Fix ordering message on wrong received time.

- Centralize received time into ChatMessageModel.
- Remove receivedTime temporary data because it is not stored into database.
- Try to set received time on new messages/events chat room listener.
- Ensure to not override receivedTime.
This commit is contained in:
Julien Wadel 2023-05-05 11:22:06 +02:00
parent 51ef0ae25b
commit ef0a59b26c
12 changed files with 89 additions and 67 deletions

View file

@ -31,19 +31,12 @@ ChatCallModel::ChatCallModel ( std::shared_ptr<linphone::CallLog> callLog, const
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mCallLog = callLog;
mIsStart = isStart;
bool hasReceived = mCallLog->dataExists("receivedTime");
if(isStart){
mTimestamp = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
if(hasReceived)
mReceivedTimestamp = QDateTime::fromMSecsSinceEpoch(mCallLog->getData<time_t>("receivedTime"));
else
mReceivedTimestamp = mTimestamp;
mReceivedTimestamp = mTimestamp;
}else{
mTimestamp = QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000);
if(hasReceived)
mReceivedTimestamp = QDateTime::fromMSecsSinceEpoch(mCallLog->getData<time_t>("receivedTime") + (callLog->getDuration() * 1000));
else
mReceivedTimestamp = mTimestamp;
mReceivedTimestamp = mTimestamp;
}
mIsOutgoing = (mCallLog->getDir() == linphone::Call::Dir::Outgoing);
mStatus = (LinphoneEnums::fromLinphone(mCallLog->getStatus()));

View file

@ -20,12 +20,36 @@
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "ChatEvent.hpp"
#include "app/App.hpp"
#include "utils/Utils.hpp"
// =============================================================================
ChatEvent::AppDataManager::AppDataManager(const QString& appdata){
if(!appdata.isEmpty()){
for(QString pair : appdata.split(';')){
QStringList fields = pair.split(':');
if(fields.size() > 1)
mData[fields[1]] = fields[0];
else
qWarning() << "Bad or too old appdata. It need a compatibility parsing : " << appdata;
}
}
}
QString ChatEvent::AppDataManager::toString(){
QStringList pairs;
for(QMap<QString,QString>::iterator it = mData.begin() ; it != mData.end() ; ++it){
pairs << it.value() + ":" + it.key();
}
return pairs.join(';');
}
ChatEvent::ChatEvent (ChatRoomModel::EntryType type, QObject * parent) : QObject(parent){
mType = type;
}

View file

@ -41,6 +41,14 @@ public:
virtual void deleteEvent();
class AppDataManager{// Used to manage appdata to store persistant data
public:
AppDataManager(const QString&);
QMap<QString, QString> mData;// Path / ID
QString toString();
};
protected:
QDateTime mTimestamp;
QDateTime mReceivedTimestamp;

View file

@ -68,25 +68,6 @@ void ChatMessageModel::connectTo(ChatMessageListener * listener){
}
// =============================================================================
ChatMessageModel::AppDataManager::AppDataManager(const QString& appdata){
if(!appdata.isEmpty()){
for(QString pair : appdata.split(';')){
QStringList fields = pair.split(':');
if(fields.size() > 1)
mData[fields[1]] = fields[0];
else
qWarning() << "Bad or too old appdata. It need a compatibility parsing : " << appdata;
}
}
}
QString ChatMessageModel::AppDataManager::toString(){
QStringList pairs;
for(QMap<QString,QString>::iterator it = mData.begin() ; it != mData.end() ; ++it){
pairs << it.value() + ":" + it.key();
}
return pairs.join(';');
}
ChatMessageModel::ChatMessageModel ( std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent) : ChatEvent(ChatRoomModel::EntryType::MessageEntry, parent) {
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it
if(chatMessage){
@ -109,13 +90,7 @@ ChatMessageModel::ChatMessageModel ( std::shared_ptr<linphone::ChatMessage> chat
mContent = txt;
mTimestamp = QDateTime::fromMSecsSinceEpoch(chatMessage->getTime() * 1000);
auto appdata = ChatMessageModel::AppDataManager(QString::fromStdString(chatMessage->getAppdata()));
if(!appdata.mData.contains("receivedTime")){
mReceivedTimestamp = QDateTime::currentDateTime();
appdata.mData["receivedTime"] = QString::number(mReceivedTimestamp.toMSecsSinceEpoch());
chatMessage->setAppdata(Utils::appStringToCoreString(appdata.toString()));
}else
mReceivedTimestamp = QDateTime::fromMSecsSinceEpoch(appdata.mData["receivedTime"].toULongLong());
mReceivedTimestamp = ChatMessageModel::initReceivedTimestamp(chatMessage);
}
mWasDownloaded = false;
@ -275,6 +250,16 @@ void ChatMessageModel::updateFileTransferInformation(){
mContentListModel->updateContents(this);
}
QDateTime ChatMessageModel::initReceivedTimestamp(const std::shared_ptr<linphone::ChatMessage> &message){
auto appdata = ChatEvent::AppDataManager(QString::fromStdString(message->getAppdata()));
if(!appdata.mData.contains("receivedTime")){// Already set : Do not overwrite.
appdata.mData["receivedTime"] = QString::number(QDateTime::currentMSecsSinceEpoch());
qDebug() << "New message received at " << QDateTime::fromMSecsSinceEpoch(appdata.mData["receivedTime"].toLongLong()).toString("yyyy/MM/dd hh:mm:ss.zzz");
message->setAppdata(Utils::appStringToCoreString(appdata.toString()));
}
return QDateTime::fromMSecsSinceEpoch(appdata.mData["receivedTime"].toLongLong());
}
void ChatMessageModel::onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, const std::shared_ptr<const linphone::Buffer> & buffer){
}
void ChatMessageModel::onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size, const std::shared_ptr<linphone::Buffer> & buffer) {

View file

@ -46,15 +46,6 @@ public:
ChatMessageModel (std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent = nullptr);
virtual ~ChatMessageModel();
class AppDataManager{// Used to manage appdata to store persistant data
public:
AppDataManager(const QString&);
QMap<QString, QString> mData;// Path / ID
QString toString();
};
Q_PROPERTY(QString fromDisplayName READ getFromDisplayName CONSTANT)
Q_PROPERTY(QString fromDisplayNameReplyMessage READ getFromDisplayNameReplyMessage CONSTANT)
Q_PROPERTY(QString fromSipAddress READ getFromSipAddress CONSTANT)
@ -116,12 +107,14 @@ public:
virtual void setTimestamp(const QDateTime& timestamp = QDateTime::currentDateTime()) override;
virtual void setReceivedTimestamp(const QDateTime& timestamp = QDateTime::currentDateTime()) override;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
Q_INVOKABLE void resendMessage ();
virtual void deleteEvent() override;
void updateFileTransferInformation();
static QDateTime initReceivedTimestamp(const std::shared_ptr<linphone::ChatMessage> &message); // return received timestamp
// Linphone callbacks
void onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, const std::shared_ptr<const linphone::Buffer> & buffer) ;
void onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size, const std::shared_ptr<linphone::Buffer> & buffer) ;

View file

@ -34,10 +34,7 @@ ChatNoticeModel::ChatNoticeModel ( std::shared_ptr<linphone::EventLog> eventLog,
mEventLogType = LinphoneEnums::EventLogType::EventLogTypeNone;
setEventLogType(LinphoneEnums::fromLinphone(mEventLog->getType()));
mTimestamp = QDateTime::fromMSecsSinceEpoch(eventLog->getCreationTime() * 1000);
if(mEventLog->dataExists("receivedTime"))
mReceivedTimestamp = QDateTime::fromMSecsSinceEpoch(mEventLog->getData<time_t>("receivedTime"));
else
mReceivedTimestamp = mTimestamp;
mReceivedTimestamp = mTimestamp;
}
ChatNoticeModel::ChatNoticeModel ( NoticeType noticeType, const QDateTime& timestamp, const QDateTime& receivedTimestamp, const QString& txt, QObject * parent) : ChatEvent(ChatRoomModel::EntryType::NoticeEntry, parent) {

View file

@ -44,6 +44,9 @@ void ChatRoomListener::onMessagesReceived(const std::shared_ptr<linphone::ChatRo
void ChatRoomListener::onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
emit newEvent(chatRoom, eventLog);
}
void ChatRoomListener::onNewEvents(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs){
emit newEvents(chatRoom, eventLogs);
}
void ChatRoomListener::onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
emit chatMessageReceived(chatRoom, eventLog);
}

View file

@ -40,6 +40,7 @@ public:
virtual void onMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onMessagesReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::ChatMessage>> & messages) override;
virtual void onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onNewEvents(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs) override;
virtual void onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
virtual void onChatMessagesReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs) override;
virtual void onChatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
@ -69,6 +70,7 @@ signals:
void messageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message);
void messagesReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::ChatMessage>> & messages);
void newEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
void newEvents(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs);
void chatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
void chatMessagesReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs);
void chatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);

View file

@ -76,6 +76,7 @@ void ChatRoomModel::connectTo(ChatRoomListener * listener){
connect(listener, &ChatRoomListener::messageReceived, this, &ChatRoomModel::onMessageReceived);
connect(listener, &ChatRoomListener::messagesReceived, this, &ChatRoomModel::onMessagesReceived);
connect(listener, &ChatRoomListener::newEvent, this, &ChatRoomModel::onNewEvent);
connect(listener, &ChatRoomListener::newEvents, this, &ChatRoomModel::onNewEvents);
connect(listener, &ChatRoomListener::chatMessageReceived, this, &ChatRoomModel::onChatMessageReceived);
connect(listener, &ChatRoomListener::chatMessagesReceived, this, &ChatRoomModel::onChatMessagesReceived);
connect(listener, &ChatRoomListener::chatMessageSending, this, &ChatRoomModel::onChatMessageSending);
@ -980,8 +981,11 @@ void ChatRoomModel::initEntries(){
if(entries.size() >0){
beginInsertRows(QModelIndex(),0, entries.size()-1);
for(auto e : entries) {
if( e->mType == ChatRoomModel::EntryType::MessageEntry)
if( e->mType == ChatRoomModel::EntryType::MessageEntry){
connect(e.objectCast<ChatMessageModel>().get(), &ChatMessageModel::remove, this, &ChatRoomModel::removeEntry);
auto model = e.objectCast<ChatMessageModel>().get();
qDebug() << "Adding" << model->getReceivedTimestamp().toString("yyyy/MM/dd hh:mm:ss.zzz") << model->getTimestamp().toString("yyyy/MM/dd hh:mm:ss.zzz") << model->getChatMessage()->getUtf8Text().c_str();
}
mList.push_back(e);
}
endInsertRows();
@ -1145,6 +1149,7 @@ QSharedPointer<ChatMessageModel> ChatRoomModel::insertMessageAtEnd (const std::s
if(mIsInitialized && !exists(message)){
model = ChatMessageModel::create(message);
if(model){
qDebug() << "Adding at end" << model->getReceivedTimestamp().toString("hh:mm:ss.zzz") << model->getTimestamp().toString("hh:mm:ss.zzz") << message->getUtf8Text().c_str();
connect(model.get(), &ChatMessageModel::remove, this, &ChatRoomModel::removeEntry);
setUnreadMessagesCount(mChatRoom->getUnreadMessagesCount());
add(model);
@ -1282,11 +1287,14 @@ void ChatRoomModel::onIsComposingReceived(const std::shared_ptr<linphone::ChatRo
}
void ChatRoomModel::onMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message){
if(message) ChatMessageModel::initReceivedTimestamp(message);
setUnreadMessagesCount(chatRoom->getUnreadMessagesCount());
updateLastUpdateTime();
}
void ChatRoomModel::onMessagesReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::ChatMessage>> & messages){
for(auto message : messages)
if(message) ChatMessageModel::initReceivedTimestamp(message);
setUnreadMessagesCount(chatRoom->getUnreadMessagesCount());
updateLastUpdateTime();
}
@ -1303,9 +1311,27 @@ void ChatRoomModel::onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatR
}
}
void ChatRoomModel::onNewEvents(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs){
int missCount = 0;
bool updatePeerAddress = false;
for(auto eventLog : eventLogs)
if(eventLog){
if( eventLog->getType() == linphone::EventLog::Type::ConferenceCallEnded )
++missCount;
if( eventLog->getType() == linphone::EventLog::Type::ConferenceCreated )
updatePeerAddress = true;
}
if(missCount > 0)
setMissedCallsCount(mMissedCallsCount+missCount);
if(updatePeerAddress)
emit fullPeerAddressChanged();
updateLastUpdateTime();
}
void ChatRoomModel::onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) {
auto message = eventLog->getChatMessage();
if(message){
ChatMessageModel::initReceivedTimestamp(message);
insertMessageAtEnd(message);
updateLastUpdateTime();
emit messageReceived(message);
@ -1316,6 +1342,7 @@ void ChatRoomModel::onChatMessagesReceived(const std::shared_ptr<linphone::ChatR
for(auto eventLog : eventLogs){
auto message = eventLog->getChatMessage();
if(message){
ChatMessageModel::initReceivedTimestamp(message);
insertMessageAtEnd(message);
updateLastUpdateTime();
emit messageReceived(message);
@ -1326,6 +1353,7 @@ void ChatRoomModel::onChatMessagesReceived(const std::shared_ptr<linphone::ChatR
void ChatRoomModel::onChatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
auto message = eventLog->getChatMessage();
if(message){
ChatMessageModel::initReceivedTimestamp(message);
insertMessageAtEnd(message);
updateLastUpdateTime();
emit messageReceived(message);

View file

@ -222,6 +222,7 @@ public slots:
virtual void onMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message);
virtual void onMessagesReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::ChatMessage>> & messages);
virtual void onNewEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
virtual void onNewEvents(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs);
virtual void onChatMessageReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
virtual void onChatMessagesReceived(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::list<std::shared_ptr<linphone::EventLog>> & eventLogs);
virtual void onChatMessageSending(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);

View file

@ -229,13 +229,7 @@ void CoreHandlers::onMessagesReceived (
appSettings.beginGroup("chatrooms");
for(auto message : messages){
if(message){
auto chatRoom = message->getChatRoom();
auto dbMessage = chatRoom->findMessage(message->getMessageId());
auto appdata = ChatMessageModel::AppDataManager(QString::fromStdString(dbMessage->getAppdata()));
appdata.mData["receivedTime"] = QString::number(QDateTime::currentMSecsSinceEpoch());
dbMessage->setAppdata(Utils::appStringToCoreString(appdata.toString()));
}
if(message) ChatMessageModel::initReceivedTimestamp(message);
if( !message || message->isOutgoing() )
continue;
// 1. Do not notify if chat is not activated.

View file

@ -44,10 +44,7 @@ using namespace std;
static inline void fillCallStartEntry (QVariantMap &dest, const shared_ptr<linphone::CallLog> &callLog) {
dest["type"] = HistoryModel::CallEntry;
dest["timestamp"] = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
if(callLog->dataExists("receivedTime"))
dest["receivedTimestamp"] = QDateTime::fromMSecsSinceEpoch(callLog->getData<time_t>("receivedTime"));
else
dest["receivedTimestamp"] = dest["timestamp"];
dest["receivedTimestamp"] = dest["timestamp"];
dest["isOutgoing"] = callLog->getDir() == linphone::Call::Dir::Outgoing;
dest["status"] = static_cast<HistoryModel::CallStatus>(callLog->getStatus());
dest["isStart"] = true;
@ -63,10 +60,7 @@ static inline void fillCallStartEntry (QVariantMap &dest, const shared_ptr<linph
static inline void fillCallEndEntry (QVariantMap &dest, const shared_ptr<linphone::CallLog> &callLog) {
dest["type"] = HistoryModel::CallEntry;
dest["timestamp"] = QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000);
if(callLog->dataExists("receivedTime"))
dest["receivedTimestamp"] = QDateTime::fromMSecsSinceEpoch(callLog->getData<time_t>("receivedTime") + (callLog->getDuration() * 1000));
else
dest["receivedTimestamp"] = dest["timestamp"];
dest["receivedTimestamp"] = dest["timestamp"];
dest["isOutgoing"] = callLog->getDir() == linphone::Call::Dir::Outgoing;
dest["status"] = static_cast<HistoryModel::CallStatus>(callLog->getStatus());
dest["isStart"] = false;