From 1f971123068b683b09d6307883d85ac168e0596b Mon Sep 17 00:00:00 2001 From: Gaelle Braud Date: Mon, 13 Oct 2025 17:03:46 +0200 Subject: [PATCH] fix chat message research #LINQT-2047 try to fix persistent spinner on chat message state icon remove medias section from contact page #LINQT-2060 #LINQT-2066 --- .../core/chat/message/ChatMessageCore.cpp | 1 - Linphone/core/chat/message/EventLogList.cpp | 98 +++++++++++++------ Linphone/core/chat/message/EventLogList.hpp | 7 ++ Linphone/core/chat/message/EventLogProxy.cpp | 37 ++++--- Linphone/model/chat/ChatModel.cpp | 12 +++ Linphone/model/chat/ChatModel.hpp | 6 ++ .../view/Control/Display/Chat/ChatMessage.qml | 1 + .../view/Control/Display/Chat/FileView.qml | 2 +- .../view/Page/Main/Contact/ContactPage.qml | 2 +- 9 files changed, 119 insertions(+), 47 deletions(-) diff --git a/Linphone/core/chat/message/ChatMessageCore.cpp b/Linphone/core/chat/message/ChatMessageCore.cpp index de475dd52..c793c94c7 100644 --- a/Linphone/core/chat/message/ChatMessageCore.cpp +++ b/Linphone/core/chat/message/ChatMessageCore.cpp @@ -267,7 +267,6 @@ void ChatMessageCore::setSelf(QSharedPointer me) { mChatMessageModelConnection->makeConnectToModel( &ChatMessageModel::msgStateChanged, [this](const std::shared_ptr &message, linphone::ChatMessage::State state) { - if (mChatMessageModel->getMonitor() != message) return; auto imdnStatusList = computeDeliveryStatus(message); auto msgState = LinphoneEnums::fromLinphone(state); mChatMessageModelConnection->invokeToCore([this, msgState, imdnStatusList] { diff --git a/Linphone/core/chat/message/EventLogList.cpp b/Linphone/core/chat/message/EventLogList.cpp index 835505e41..9323622c6 100644 --- a/Linphone/core/chat/message/EventLogList.cpp +++ b/Linphone/core/chat/message/EventLogList.cpp @@ -161,7 +161,7 @@ void EventLogList::displayMore() { auto model = EventLogCore::create(it); events->push_back(model); } - mCoreModelConnection->invokeToCore([this, events, newCount] { + mCoreModelConnection->invokeToCore([this, events] { int currentCount = mList.count(); for (auto it = events->end() - 1; it >= events->begin(); --it) { connectItem(*it); @@ -171,6 +171,35 @@ void EventLogList::displayMore() { }); } +void EventLogList::loadMessagesUpTo(std::shared_ptr event) { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + auto oldestEventLoaded = getAt(0); + auto linOldest = std::const_pointer_cast(oldestEventLoaded->getModel()->getEventLog()); + auto chatModel = mChatCore->getModel(); + assert(chatModel); + if (!chatModel) return; + int filters = static_cast(linphone::ChatRoom::HistoryFilter::ChatMessage) | + static_cast(linphone::ChatRoom::HistoryFilter::InfoNoDevice); + auto beforeEvents = chatModel->getHistoryRangeNear(mItemsToLoadBeforeSearchResult, 0, event, filters); + auto linphoneLogs = chatModel->getHistoryRangeBetween(event, linOldest, filters); + QList> *events = new QList>(); + for (auto it : beforeEvents) { + auto model = EventLogCore::create(it); + events->push_back(model); + } + for (auto it : linphoneLogs) { + auto model = EventLogCore::create(it); + events->push_back(model); + } + mCoreModelConnection->invokeToCore([this, events, event] { + for (auto &e : *events) { + connectItem(e); + add(e); + } + emit messagesLoadedUpTo(event); + }); +} + int EventLogList::findFirstUnreadIndex() { auto eventList = getSharedList(); auto it = std::find_if(eventList.begin(), eventList.end(), [](const QSharedPointer item) { @@ -184,31 +213,47 @@ void EventLogList::findChatMessageWithFilter(QString filter, bool forward, bool isFirstResearch) { if (mChatCore) { - auto modelConnection = mChatCore->getChatModelConnection(); + if (isFirstResearch) mLastFoundResult.reset(); auto chatModel = mChatCore->getModel(); auto startEventModel = startEvent ? startEvent->getModel() : nullptr; - modelConnection->invokeToModel( - [this, chatModel, startEventModel, filter, forward, modelConnection, isFirstResearch] { - auto linStartEvent = startEventModel ? startEventModel->getEventLog() : nullptr; - auto eventLog = chatModel->searchMessageByText(filter, linStartEvent, forward); - // If it is the first research and event was not found from the start event, search in the - // entire history - if (!eventLog && isFirstResearch) { - auto firstEvent = getAt(0); - auto linFirst = firstEvent ? firstEvent->getModel()->getEventLog() : nullptr; - eventLog = chatModel->searchMessageByText(filter, nullptr, forward); - } - int index = -1; - if (eventLog) { - auto eventList = getSharedList(); - auto it = std::find_if(eventList.begin(), eventList.end(), - [eventLog](const QSharedPointer item) { - return item->getModel()->getEventLog() == eventLog; - }); - index = it == eventList.end() ? -1 : std::distance(eventList.begin(), it); - } - modelConnection->invokeToCore([this, index] { emit messageWithFilterFound(index); }); - }); + mCoreModelConnection->invokeToModel([this, chatModel, startEventModel, filter, forward, isFirstResearch] { + auto linStartEvent = startEventModel ? startEventModel->getEventLog() : nullptr; + auto eventLog = chatModel->searchMessageByText(filter, linStartEvent, forward); + if (!eventLog) + // event not found, search in the entire history + auto eventLog = chatModel->searchMessageByText(filter, nullptr, forward); + int index = -1; + if (eventLog) { + auto eventList = getSharedList(); + auto it = std::find_if(eventList.begin(), eventList.end(), + [eventLog](const QSharedPointer item) { + return item->getModel()->getEventLog() == eventLog; + }); + if (it != eventList.end()) { + int index = std::distance(eventList.begin(), it); + if (mLastFoundResult && mLastFoundResult == *it) index = -1; + mLastFoundResult = *it; + mCoreModelConnection->invokeToCore([this, index] { emit messageWithFilterFound(index); }); + } else { + connect(this, &EventLogList::messagesLoadedUpTo, this, + [this](std::shared_ptr event) { + auto eventList = getSharedList(); + auto it = std::find_if(eventList.begin(), eventList.end(), + [event](const QSharedPointer item) { + return item->getModel()->getEventLog() == event; + }); + int index = it != eventList.end() ? std::distance(eventList.begin(), it) : -1; + if (mLastFoundResult && mLastFoundResult == *it) index = -1; + mLastFoundResult = *it; + mCoreModelConnection->invokeToCore( + [this, index] { emit messageWithFilterFound(index); }); + }); + loadMessagesUpTo(eventLog); + } + } else { + mCoreModelConnection->invokeToCore([this, index] { emit messageWithFilterFound(index); }); + } + }); } } @@ -217,7 +262,6 @@ void EventLogList::setSelf(QSharedPointer me) { mCoreModelConnection->makeConnectToCore(&EventLogList::lUpdate, [this]() { mustBeInMainThread(log().arg(Q_FUNC_INFO)); - if (mChatCore) qDebug() << "reset messages model for chat core" << mChatCore << mChatCore->getTitle(); setIsUpdating(true); beginResetModel(); mList.clear(); @@ -234,7 +278,6 @@ void EventLogList::setSelf(QSharedPointer me) { } mCoreModelConnection->invokeToModel([this, chatModel]() { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); - qDebug() << "update history till" << mDisplayItemsStep; auto linphoneLogs = chatModel->getHistoryRange(0, mDisplayItemsStep); QList> *events = new QList>(); for (auto it : linphoneLogs) { @@ -251,9 +294,8 @@ void EventLogList::setSelf(QSharedPointer me) { } for (auto &event : *events) { connectItem(event); + mList.append(event); } - for (auto i : *events) - mList << i.template objectCast(); endResetModel(); setIsUpdating(false); }); diff --git a/Linphone/core/chat/message/EventLogList.hpp b/Linphone/core/chat/message/EventLogList.hpp index 84e343512..713469308 100644 --- a/Linphone/core/chat/message/EventLogList.hpp +++ b/Linphone/core/chat/message/EventLogList.hpp @@ -50,6 +50,10 @@ public: void setIsUpdating(bool updating); + void loadMessagesUpTo(std::shared_ptr event); + + void setLastFoundResult(const QSharedPointer &eventLog); + int findFirstUnreadIndex(); void displayMore(); @@ -73,6 +77,7 @@ signals: void chatGuiChanged(); void isUpdatingChanged(); void displayItemsStepChanged(); + void messagesLoadedUpTo(std::shared_ptr event); private: QString mFilter; @@ -81,6 +86,8 @@ private: QSharedPointer> mCoreModelConnection; bool mIsUpdating = false; int mDisplayItemsStep = 0; + int mItemsToLoadBeforeSearchResult = 3; + QSharedPointer mLastFoundResult; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/core/chat/message/EventLogProxy.cpp b/Linphone/core/chat/message/EventLogProxy.cpp index 323f9e13d..2069ba1e3 100644 --- a/Linphone/core/chat/message/EventLogProxy.cpp +++ b/Linphone/core/chat/message/EventLogProxy.cpp @@ -48,29 +48,31 @@ void EventLogProxy::setSourceModel(QAbstractItemModel *model) { connect(newEventLogList, &EventLogList::eventInserted, this, [this, newEventLogList](int index, EventLogGui *event) { invalidate(); + int proxyIndex = -1; if (index != -1) { - index = dynamic_cast(sourceModel()) - ->mapFromSource(newEventLogList->index(index, 0)) - .row(); - if (mMaxDisplayItems <= index) setMaxDisplayItems(index + mDisplayItemsStep); + proxyIndex = dynamic_cast(sourceModel()) + ->mapFromSource(newEventLogList->index(index, 0)) + .row(); } - loadUntil(index); - emit eventInserted(index, event); + loadUntil(proxyIndex); + emit eventInserted(proxyIndex, event); }); - connect(newEventLogList, &EventLogList::messageWithFilterFound, this, [this, newEventLogList](int index) { - if (index != -1) { + connect(newEventLogList, &EventLogList::messageWithFilterFound, this, [this, newEventLogList](int i) { + connect(this, &EventLogProxy::layoutChanged, newEventLogList, [this, i, newEventLogList] { + disconnect(this, &EventLogProxy::layoutChanged, newEventLogList, nullptr); auto model = getListModel(); - mLastSearchStart = model->getAt(index); - index = dynamic_cast(sourceModel()) - ->mapFromSource(newEventLogList->index(index, 0)) - .row(); - loadUntil(index); - } - emit indexWithFilterFound(index); + int proxyIndex = + dynamic_cast(sourceModel())->mapFromSource(newEventLogList->index(i, 0)).row(); + if (i != -1) { + loadUntil(proxyIndex); + } + emit indexWithFilterFound(proxyIndex); + }); + invalidate(); }); } setSourceModels(new SortFilterList(model, Qt::DescendingOrder)); - sort(0); + sort(0, Qt::DescendingOrder); } ChatGui *EventLogProxy::getChatGui() { @@ -144,5 +146,8 @@ bool EventLogProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModel } bool EventLogProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const { + auto l = getItemAtSource(sourceLeft.row()); + auto r = getItemAtSource(sourceRight.row()); + if (l && r) return l->getTimestamp() <= r->getTimestamp(); return true; } diff --git a/Linphone/model/chat/ChatModel.cpp b/Linphone/model/chat/ChatModel.cpp index 3b84137b2..e1bba568e 100644 --- a/Linphone/model/chat/ChatModel.cpp +++ b/Linphone/model/chat/ChatModel.cpp @@ -68,6 +68,18 @@ std::list> ChatModel::getHistoryRange(int be return mMonitor->getHistoryRangeEvents(begin, end); } +std::list> +ChatModel::getHistoryRangeBetween(const std::shared_ptr firstEvent, + const std::shared_ptr lastEvent, + int filters) { + return mMonitor->getHistoryRangeBetween(firstEvent, lastEvent, filters); +} + +std::list> +ChatModel::getHistoryRangeNear(int before, int after, const std::shared_ptr event, int filters) { + return mMonitor->getHistoryRangeNear(before, after, event, filters); +} + std::list> ChatModel::getChatMessageHistory() const { auto history = mMonitor->getHistory(0, (int)linphone::ChatRoom::HistoryFilter::ChatMessage); std::list> res; diff --git a/Linphone/model/chat/ChatModel.hpp b/Linphone/model/chat/ChatModel.hpp index b4a4a8be7..0e1cfbbc3 100644 --- a/Linphone/model/chat/ChatModel.hpp +++ b/Linphone/model/chat/ChatModel.hpp @@ -50,6 +50,12 @@ public: std::list> getSharedDocuments() const; std::list> getHistory() const; std::list> getHistoryRange(int begin, int end); + std::list> + getHistoryRangeBetween(const std::shared_ptr firstEvent, + const std::shared_ptr lastEvent, + int filters); + std::list> + getHistoryRangeNear(int before, int after, const std::shared_ptr firstEvent, int filters); std::list> getChatMessageHistory() const; int getHistorySizeEvents(); QString getIdentifier() const; diff --git a/Linphone/view/Control/Display/Chat/ChatMessage.qml b/Linphone/view/Control/Display/Chat/ChatMessage.qml index 8235f9b48..8f5bd1faf 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessage.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessage.qml @@ -299,6 +299,7 @@ Control.Control { } } EffectImage { + // Imdn status icon visible: !mainItem.isRemoteMessage Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0 Layout.preferredHeight: visible ? 14 * DefaultStyle.dp : 0 diff --git a/Linphone/view/Control/Display/Chat/FileView.qml b/Linphone/view/Control/Display/Chat/FileView.qml index 6c4500532..1db5ed529 100644 --- a/Linphone/view/Control/Display/Chat/FileView.qml +++ b/Linphone/view/Control/Display/Chat/FileView.qml @@ -72,7 +72,7 @@ Item { color: DefaultStyle.main1_200 opacity: 0.5 Image { - anchors.fill: image + anchors.fill: parent z: parent.z + 1 visible: image.status == Image.Error || image.status == Image.Null || !UtilsCpp.fileExists(mainItem.filePath) source: AppIcons.fileImage diff --git a/Linphone/view/Page/Main/Contact/ContactPage.qml b/Linphone/view/Page/Main/Contact/ContactPage.qml index e9635175f..b418a9f76 100644 --- a/Linphone/view/Page/Main/Contact/ContactPage.qml +++ b/Linphone/view/Page/Main/Contact/ContactPage.qml @@ -606,7 +606,7 @@ FriendGui{ } } ContactDetailLayout { - visible: !SettingsCpp.disableChatFeature + visible: false//!SettingsCpp.disableChatFeature //: "Medias" label: qsTr("contact_details_medias_title") Layout.fillWidth: true