diff --git a/Linphone/core/chat/ChatCore.cpp b/Linphone/core/chat/ChatCore.cpp index d7cbd6910..d54cf3742 100644 --- a/Linphone/core/chat/ChatCore.cpp +++ b/Linphone/core/chat/ChatCore.cpp @@ -81,11 +81,13 @@ ChatCore::ChatCore(const std::shared_ptr &chatRoom) : QObjec for (auto &eventLog : history) { if (eventLog->getChatMessage()) lHistory.push_back(eventLog->getChatMessage()); } + QList> messageList; for (auto &message : lHistory) { if (!message) continue; auto chatMessage = ChatMessageCore::create(message); - mChatMessageList.append(chatMessage); + messageList.append(chatMessage); } + resetChatMessageList(messageList); mIdentifier = Utils::coreStringToAppString(chatRoom->getIdentifier()); connect(this, &ChatCore::messageListChanged, this, &ChatCore::lUpdateLastMessage); connect(this, &ChatCore::messagesInserted, this, &ChatCore::lUpdateLastMessage); @@ -108,8 +110,8 @@ void ChatCore::setSelf(QSharedPointer me) { clearMessagesList(); //: Deleted Utils::showInformationPopup(tr("info_toast_deleted_title"), - //: Message history has been deleted - tr("info_toast_deleted_message_history"), true); + //: Message history has been deleted + tr("info_toast_deleted_message_history"), true); }); }); mChatModelConnection->makeConnectToCore(&ChatCore::lUpdateUnreadCount, [this]() { diff --git a/Linphone/core/chat/message/ChatMessageCore.cpp b/Linphone/core/chat/message/ChatMessageCore.cpp index ce6deb797..93462c7c6 100644 --- a/Linphone/core/chat/message/ChatMessageCore.cpp +++ b/Linphone/core/chat/message/ChatMessageCore.cpp @@ -55,6 +55,7 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr &c !chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne); mIsRead = chatmessage->isRead(); mMessageState = LinphoneEnums::fromLinphone(chatmessage->getState()); + mMessageId = Utils::coreStringToAppString(chatmessage->getMessageId()); } ChatMessageCore::~ChatMessageCore() { @@ -68,8 +69,8 @@ void ChatMessageCore::setSelf(QSharedPointer me) { mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageDeleted, [this]() { //: Deleted Utils::showInformationPopup(tr("info_toast_deleted_title"), - //: The message has been deleted - tr("info_toast_deleted_message"), true); + //: The message has been deleted + tr("info_toast_deleted_message"), true); emit deleted(); }); mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lMarkAsRead, [this] { @@ -128,6 +129,9 @@ QString ChatMessageCore::getToAddress() const { return mToAddress; } +QString ChatMessageCore::getMessageId() const { + return mMessageId; +} bool ChatMessageCore::isRemoteMessage() const { return mIsRemoteMessage; } diff --git a/Linphone/core/chat/message/ChatMessageCore.hpp b/Linphone/core/chat/message/ChatMessageCore.hpp index 70989d6c5..467eb636a 100644 --- a/Linphone/core/chat/message/ChatMessageCore.hpp +++ b/Linphone/core/chat/message/ChatMessageCore.hpp @@ -63,6 +63,7 @@ public: QString getFromAddress() const; QString getFromName() const; QString getToAddress() const; + QString getMessageId() const; bool isRemoteMessage() const; bool isFromChatGroup() const; @@ -94,6 +95,7 @@ private: QString mToAddress; QString mFromName; QString mPeerName; + QString mMessageId; QDateTime mTimestamp; bool mIsRemoteMessage = false; bool mIsFromChatGroup = false; diff --git a/Linphone/core/chat/message/ChatMessageList.cpp b/Linphone/core/chat/message/ChatMessageList.cpp index c71064987..b2422a011 100644 --- a/Linphone/core/chat/message/ChatMessageList.cpp +++ b/Linphone/core/chat/message/ChatMessageList.cpp @@ -48,7 +48,6 @@ ChatMessageList::createChatMessageCore(const std::shared_ptrmEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); - connect(this, &ChatMessageList::chatChanged, this, &ChatMessageList::lUpdate); } ChatMessageList::~ChatMessageList() { @@ -73,11 +72,22 @@ void ChatMessageList::setChatCore(QSharedPointer core) { if (mChatCore) connect(mChatCore.get(), &ChatCore::messagesInserted, this, [this](QList> list) { + auto chatList = getSharedList(); for (auto &message : list) { - add(message); + auto it = std::find_if(chatList.begin(), chatList.end(), + [message](const QSharedPointer item) { + return item->getMessageId() == message->getMessageId(); + }); + if (it == chatList.end()) { + add(message); + int index; + get(message.get(), &index); + emit messageInserted(index, new ChatMessageGui(message)); + } } }); emit chatChanged(); + lUpdate(); } } @@ -86,6 +96,13 @@ void ChatMessageList::setChatGui(ChatGui *chat) { setChatCore(chatCore); } +int ChatMessageList::findFirstUnreadIndex() { + auto chatList = getSharedList(); + auto it = std::find_if(chatList.begin(), chatList.end(), + [](const QSharedPointer item) { return !item->isRead(); }); + return it == chatList.end() ? -1 : std::distance(chatList.begin(), it); +} + void ChatMessageList::setSelf(QSharedPointer me) { mModelConnection = SafeConnection::create(me, CoreModel::getInstance()); diff --git a/Linphone/core/chat/message/ChatMessageList.hpp b/Linphone/core/chat/message/ChatMessageList.hpp index 9459784c5..c00663f13 100644 --- a/Linphone/core/chat/message/ChatMessageList.hpp +++ b/Linphone/core/chat/message/ChatMessageList.hpp @@ -42,9 +42,11 @@ public: ~ChatMessageList(); QSharedPointer getChatCore() const; - ChatGui* getChat() const; + ChatGui *getChat() const; void setChatCore(QSharedPointer core); - void setChatGui(ChatGui* chat); + void setChatGui(ChatGui *chat); + + int findFirstUnreadIndex(); void setSelf(QSharedPointer me); virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -52,6 +54,7 @@ signals: void lUpdate(); void filterChanged(QString filter); void chatChanged(); + void messageInserted(int index, ChatMessageGui *message); private: QString mFilter; diff --git a/Linphone/core/chat/message/ChatMessageProxy.cpp b/Linphone/core/chat/message/ChatMessageProxy.cpp index 6abc2a1de..34f9e8648 100644 --- a/Linphone/core/chat/message/ChatMessageProxy.cpp +++ b/Linphone/core/chat/message/ChatMessageProxy.cpp @@ -41,6 +41,16 @@ void ChatMessageProxy::setSourceModel(QAbstractItemModel *model) { auto newChatMessageList = dynamic_cast(model); if (newChatMessageList) { connect(newChatMessageList, &ChatMessageList::chatChanged, this, &ChatMessageProxy::chatChanged); + connect(newChatMessageList, &ChatMessageList::messageInserted, this, + [this, newChatMessageList](int index, ChatMessageGui *message) { + if (index != -1) { + index = dynamic_cast(sourceModel()) + ->mapFromSource(newChatMessageList->index(index, 0)) + .row(); + if (mMaxDisplayItems <= index) setMaxDisplayItems(index + mDisplayItemsStep); + } + emit messageInserted(index, message); + }); } setSourceModels(new SortFilterList(model)); sort(0); @@ -68,14 +78,20 @@ ChatMessageGui *ChatMessageProxy::getChatMessageAtIndex(int i) { } int ChatMessageProxy::findFirstUnreadIndex() { - int n = getCount(); - for (int i = 0; i < n; ++i) { - auto chat = getItemAt(i); - if (chat && !chat->isRead()) { - return i; + auto chatMessageList = getListModel(); + if (chatMessageList) { + auto listIndex = chatMessageList->findFirstUnreadIndex(); + if (listIndex != -1) { + listIndex = dynamic_cast(sourceModel()) + ->mapFromSource(chatMessageList->index(listIndex, 0)) + .row(); + if (mMaxDisplayItems <= listIndex) setMaxDisplayItems(listIndex + mDisplayItemsStep); + return listIndex; + } else { + return std::max(0, getCount() - 1); } } - return std::max(0, n - 1); + return std::max(0, getCount() - 1); } bool ChatMessageProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { diff --git a/Linphone/core/chat/message/ChatMessageProxy.hpp b/Linphone/core/chat/message/ChatMessageProxy.hpp index 082769d17..2fc9e27ce 100644 --- a/Linphone/core/chat/message/ChatMessageProxy.hpp +++ b/Linphone/core/chat/message/ChatMessageProxy.hpp @@ -49,6 +49,7 @@ public: signals: void chatChanged(); + void messageInserted(int index, ChatMessageGui *message); protected: QSharedPointer mList; diff --git a/Linphone/model/chat/message/ChatMessageModel.cpp b/Linphone/model/chat/message/ChatMessageModel.cpp index 62d1600a2..4f987bbdd 100644 --- a/Linphone/model/chat/message/ChatMessageModel.cpp +++ b/Linphone/model/chat/message/ChatMessageModel.cpp @@ -56,6 +56,10 @@ QString ChatMessageModel::getToAddress() const { return Utils::coreStringToAppString(mMonitor->getToAddress()->asStringUriOnly()); } +QString ChatMessageModel::getMessageId() const { + return Utils::coreStringToAppString(mMonitor->getMessageId()); +} + QDateTime ChatMessageModel::getTimestamp() const { return QDateTime::fromSecsSinceEpoch(mMonitor->getTime()); } diff --git a/Linphone/model/chat/message/ChatMessageModel.hpp b/Linphone/model/chat/message/ChatMessageModel.hpp index 384485f35..3c5cebb89 100644 --- a/Linphone/model/chat/message/ChatMessageModel.hpp +++ b/Linphone/model/chat/message/ChatMessageModel.hpp @@ -43,6 +43,7 @@ public: QString getPeerAddress() const; QString getFromAddress() const; QString getToAddress() const; + QString getMessageId() const; bool isRead() const; void markAsRead(); diff --git a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml index 459759cab..3237eba80 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml @@ -10,15 +10,9 @@ import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils ListView { id: mainItem + spacing: Math.round(4 * DefaultStyle.dp) property ChatGui chat property color backgroundColor - spacing: Math.round(4 * DefaultStyle.dp) - - onChatChanged: { - var index = chatMessageProxy.findFirstUnreadIndex() - positionViewAtIndex(index, ListView.End) - } - Component.onCompleted: { var index = chatMessageProxy.findFirstUnreadIndex() @@ -56,6 +50,12 @@ ListView { model: ChatMessageProxy { id: chatMessageProxy chatGui: mainItem.chat + // scroll when in view and message inserted + onMessageInserted: (index, gui) => { + if (!mainItem.visible) return + mainItem.positionViewAtIndex(index, ListView.End) + if (!gui.core.isRead) gui.core.lMarkAsRead() + } } header: Item { @@ -65,7 +65,6 @@ ListView { delegate: ChatMessage { chatMessage: modelData property real maxWidth: Math.round(mainItem.width * (3/4)) - // height: childrenRect.height onVisibleChanged: if (!modelData.core.isRead) modelData.core.lMarkAsRead() width: mainItem.width property var previousIndex: index - 1 diff --git a/Linphone/view/Page/Form/Chat/SelectedChatView.qml b/Linphone/view/Page/Form/Chat/SelectedChatView.qml index 261b21f2b..143ce4230 100644 --- a/Linphone/view/Page/Form/Chat/SelectedChatView.qml +++ b/Linphone/view/Page/Form/Chat/SelectedChatView.qml @@ -157,6 +157,7 @@ RowLayout { MouseArea { anchors.fill: parent onPressed: sendingTextArea.forceActiveFocus() + cursorShape: Qt.IBeamCursor } } contentItem: RowLayout {