From 99910a3f3a9a672949aaa76e939f6323762b1e31 Mon Sep 17 00:00:00 2001 From: Sebastian Wolf Date: Mon, 6 Jun 2022 15:55:21 +0200 Subject: [PATCH] Bring unread mention/reactions to chat list --- qml/components/ChatListViewItem.qml | 6 ++- qml/components/PhotoTextsListItem.qml | 46 ++++++++++++++++++++ qml/pages/ChatPage.qml | 1 + src/chatlistmodel.cpp | 60 +++++++++++++++++++++++++++ src/chatlistmodel.h | 4 ++ src/tdlibreceiver.cpp | 20 +++++++++ src/tdlibreceiver.h | 4 ++ src/tdlibwrapper.cpp | 2 + src/tdlibwrapper.h | 2 + 9 files changed, 143 insertions(+), 2 deletions(-) diff --git a/qml/components/ChatListViewItem.qml b/qml/components/ChatListViewItem.qml index b24fdc0..8df67f8 100644 --- a/qml/components/ChatListViewItem.qml +++ b/qml/components/ChatListViewItem.qml @@ -24,6 +24,8 @@ PhotoTextsListItem { // message date tertiaryText.text: showDraft ? Functions.getDateTimeElapsed(draft_message_date) : ( last_message_date ? ( last_message_date.length === 0 ? "" : Functions.getDateTimeElapsed(last_message_date) + Emoji.emojify(last_message_status, tertiaryText.font.pixelSize) ) : "" ) unreadCount: unread_count + unreadReactionCount: unread_reaction_count + unreadMentionCount: unread_mention_count isSecret: ( chat_type === TelegramAPI.ChatTypeSecret ) isMarkedAsUnread: is_marked_as_unread isPinned: is_pinned @@ -48,7 +50,7 @@ PhotoTextsListItem { sourceComponent: Component { ContextMenu { MenuItem { - visible: unread_count > 0 + visible: unread_count > 0 || unread_reaction_count > 0 || unread_mention_count > 0 onClicked: { tdLibWrapper.viewMessage(chat_id, display.last_message.id, true); tdLibWrapper.readAllChatMentions(chat_id); @@ -59,7 +61,7 @@ PhotoTextsListItem { } MenuItem { - visible: unread_count === 0 + visible: unread_count === 0 && unread_reaction_count === 0 && unread_mention_count === 0 onClicked: { tdLibWrapper.toggleChatIsMarkedAsUnread(chat_id, !is_marked_as_unread); } diff --git a/qml/components/PhotoTextsListItem.qml b/qml/components/PhotoTextsListItem.qml index f2270bb..40cf989 100644 --- a/qml/components/PhotoTextsListItem.qml +++ b/qml/components/PhotoTextsListItem.qml @@ -11,6 +11,8 @@ ListItem { property alias tertiaryText: tertiaryText //usually last message date property int unreadCount: 0 + property int unreadMentionCount: 0 + property int unreadReactionCount: 0 property bool isSecret: false property bool isVerified: false property bool isMarkedAsUnread: false @@ -103,6 +105,50 @@ ListItem { opacity: isMuted ? Theme.opacityHigh : 1.0 text: chatListViewItem.unreadCount > 99 ? "99+" : chatListViewItem.unreadCount } + + Rectangle { + id: chatUnreadReactionCountBackground + color: isMuted ? ((Theme.colorScheme === Theme.DarkOnLight) ? "lightgray" : "dimgray") : Theme.highlightBackgroundColor + width: Theme.fontSizeLarge + height: Theme.fontSizeLarge + anchors.right: parent.right + anchors.top: parent.top + radius: parent.width / 2 + visible: chatListViewItem.unreadReactionCount > 0 + } + + Text { + id: chatUnreadReactionCount + font.pixelSize: Theme.fontSizeSmall + font.bold: true + color: Theme.primaryColor + anchors.centerIn: chatUnreadReactionCountBackground + visible: chatListViewItem.unreadReactionCount > 0 + opacity: isMuted ? Theme.opacityHigh : 1.0 + text: "❤️" + } + + Rectangle { + id: chatUnreadMentionCountBackground + color: isMuted ? ((Theme.colorScheme === Theme.DarkOnLight) ? "lightgray" : "dimgray") : Theme.highlightBackgroundColor + width: Theme.fontSizeLarge + height: Theme.fontSizeLarge + anchors.right: parent.right + anchors.top: parent.top + radius: parent.width / 2 + visible: chatListViewItem.unreadMentionCount > 0 + } + + Text { + id: chatUnreadMentionCount + font.pixelSize: Theme.fontSizeSmall + font.bold: true + color: Theme.primaryColor + anchors.centerIn: chatUnreadMentionCountBackground + visible: chatListViewItem.unreadMentionCount > 0 + opacity: isMuted ? Theme.opacityHigh : 1.0 + text: "@" + } } } Column { diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index 51d071f..acfec79 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -1191,6 +1191,7 @@ Page { } } else { tdLibWrapper.readAllChatMentions(chatInformation.id); + tdLibWrapper.readAllChatReactions(chatInformation.id); } manuallyScrolledToBottom = chatView.atYEnd } diff --git a/src/chatlistmodel.cpp b/src/chatlistmodel.cpp index f5fa42b..ebb5799 100644 --- a/src/chatlistmodel.cpp +++ b/src/chatlistmodel.cpp @@ -42,6 +42,8 @@ namespace { const QString BASIC_GROUP_ID("basic_group_id"); const QString SUPERGROUP_ID("supergroup_id"); const QString UNREAD_COUNT("unread_count"); + const QString UNREAD_MENTION_COUNT("unread_mention_count"); + const QString UNREAD_REACTION_COUNT("unread_reaction_count"); const QString NOTIFICATION_SETTINGS("notification_settings"); const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id"); const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id"); @@ -66,6 +68,8 @@ public: const QVariant lastMessage(const QString &key) const; QString title() const; int unreadCount() const; + int unreadMentionCount() const; + int unreadReactionCount() const; QVariant photoSmall() const; qlonglong lastReadInboxMessageId() const; qlonglong senderUserId() const; @@ -159,6 +163,16 @@ int ChatListModel::ChatData::unreadCount() const return chatData.value(UNREAD_COUNT).toInt(); } +int ChatListModel::ChatData::unreadMentionCount() const +{ + return chatData.value(UNREAD_MENTION_COUNT).toInt(); +} + +int ChatListModel::ChatData::unreadReactionCount() const +{ + return chatData.value(UNREAD_REACTION_COUNT).toInt(); +} + QVariant ChatListModel::ChatData::photoSmall() const { return chatData.value(PHOTO).toMap().value(SMALL); @@ -384,6 +398,8 @@ ChatListModel::ChatListModel(TDLibWrapper *tdLibWrapper, AppSettings *appSetting connect(tdLibWrapper, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)), this, SLOT(handleChatIsMarkedAsUnreadUpdated(qlonglong, bool))); connect(tdLibWrapper, SIGNAL(chatPinnedUpdated(qlonglong, bool)), this, SLOT(handleChatPinnedUpdated(qlonglong, bool))); connect(tdLibWrapper, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)), this, SLOT(handleChatDraftMessageUpdated(qlonglong, QVariantMap, QString))); + connect(tdLibWrapper, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)), this, SLOT(handleChatUnreadMentionCountUpdated(qlonglong, int))); + connect(tdLibWrapper, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)), this, SLOT(handleChatUnreadReactionCountUpdated(qlonglong, int))); // Don't start the timer until we have at least one chat relativeTimeRefreshTimer = new QTimer(this); @@ -418,6 +434,8 @@ QHash ChatListModel::roleNames() const roles.insert(ChatListModel::RoleTitle, "title"); roles.insert(ChatListModel::RolePhotoSmall, "photo_small"); roles.insert(ChatListModel::RoleUnreadCount, "unread_count"); + roles.insert(ChatListModel::RoleUnreadMentionCount, "unread_mention_count"); + roles.insert(ChatListModel::RoleUnreadReactionCount, "unread_reaction_count"); roles.insert(ChatListModel::RoleLastReadInboxMessageId, "last_read_inbox_message_id"); roles.insert(ChatListModel::RoleLastMessageSenderId, "last_message_sender_id"); roles.insert(ChatListModel::RoleLastMessageDate, "last_message_date"); @@ -453,6 +471,8 @@ QVariant ChatListModel::data(const QModelIndex &index, int role) const case ChatListModel::RoleTitle: return data->title(); case ChatListModel::RolePhotoSmall: return data->photoSmall(); case ChatListModel::RoleUnreadCount: return data->unreadCount(); + case ChatListModel::RoleUnreadMentionCount: return data->unreadMentionCount(); + case ChatListModel::RoleUnreadReactionCount: return data->unreadReactionCount(); case ChatListModel::RoleLastReadInboxMessageId: return data->lastReadInboxMessageId(); case ChatListModel::RoleLastMessageSenderId: return data->senderUserId(); case ChatListModel::RoleLastMessageText: return data->senderMessageText(); @@ -969,6 +989,46 @@ void ChatListModel::handleChatDraftMessageUpdated(qlonglong chatId, const QVaria } } +void ChatListModel::handleChatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount) +{ + if (chatIndexMap.contains(chatId)) { + LOG("Updating mention count for" << chatId << unreadMentionCount); + const int chatIndex = chatIndexMap.value(chatId); + ChatData *chat = chatList.at(chatIndex); + chat->chatData.insert(UNREAD_MENTION_COUNT, unreadMentionCount); + QVector changedRoles; + changedRoles.append(ChatListModel::RoleUnreadMentionCount); + const QModelIndex modelIndex(index(chatIndex)); + emit dataChanged(modelIndex, modelIndex, changedRoles); + } else { + ChatData *chat = hiddenChats.value(chatId); + if (chat) { + LOG("Updating mention count for hidden chat" << chatId << unreadMentionCount); + chat->chatData.insert(UNREAD_MENTION_COUNT, unreadMentionCount); + } + } +} + +void ChatListModel::handleChatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount) +{ + if (chatIndexMap.contains(chatId)) { + LOG("Updating reaction count for" << chatId << unreadReactionCount); + const int chatIndex = chatIndexMap.value(chatId); + ChatData *chat = chatList.at(chatIndex); + chat->chatData.insert(UNREAD_REACTION_COUNT, unreadReactionCount); + QVector changedRoles; + changedRoles.append(ChatListModel::RoleUnreadReactionCount); + const QModelIndex modelIndex(index(chatIndex)); + emit dataChanged(modelIndex, modelIndex, changedRoles); + } else { + ChatData *chat = hiddenChats.value(chatId); + if (chat) { + LOG("Updating reaction count for hidden chat" << chatId << unreadReactionCount); + chat->chatData.insert(UNREAD_REACTION_COUNT, unreadReactionCount); + } + } +} + void ChatListModel::handleRelativeTimeRefreshTimer() { LOG("Refreshing timestamps"); diff --git a/src/chatlistmodel.h b/src/chatlistmodel.h index 0d8cdaf..77b67e5 100644 --- a/src/chatlistmodel.h +++ b/src/chatlistmodel.h @@ -40,6 +40,8 @@ public: RoleTitle, RolePhotoSmall, RoleUnreadCount, + RoleUnreadMentionCount, + RoleUnreadReactionCount, RoleLastReadInboxMessageId, RoleLastMessageSenderId, RoleLastMessageDate, @@ -89,6 +91,8 @@ private slots: void handleChatPinnedUpdated(qlonglong chatId, bool chatIsPinned); void handleChatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread); void handleChatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order); + void handleChatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount); + void handleChatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount); void handleRelativeTimeRefreshTimer(); signals: diff --git a/src/tdlibreceiver.cpp b/src/tdlibreceiver.cpp index 98a6c22..985e7b7 100644 --- a/src/tdlibreceiver.cpp +++ b/src/tdlibreceiver.cpp @@ -44,6 +44,8 @@ namespace { const QString LAST_MESSAGE("last_message"); const QString TOTAL_COUNT("total_count"); const QString UNREAD_COUNT("unread_count"); + const QString UNREAD_MENTION_COUNT("unread_mention_count"); + const QString UNREAD_REACTION_COUNT("unread_reaction_count"); const QString TEXT("text"); const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id"); const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id"); @@ -163,6 +165,8 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren handlers.insert("updateMessageInteractionInfo", &TDLibReceiver::processUpdateMessageInteractionInfo); handlers.insert("sessions", &TDLibReceiver::processSessions); handlers.insert("availableReactions", &TDLibReceiver::processAvailableReactions); + handlers.insert("updateChatUnreadMentionCount", &TDLibReceiver::processUpdateChatUnreadMentionCount); + handlers.insert("updateChatUnreadReactionCount", &TDLibReceiver::processUpdateChatUnreadReactionCount); } void TDLibReceiver::setActive(bool active) @@ -698,6 +702,22 @@ void TDLibReceiver::processAvailableReactions(const QVariantMap &receivedInforma } } +void TDLibReceiver::processUpdateChatUnreadMentionCount(const QVariantMap &receivedInformation) +{ + const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong(); + const int unreadMentionCount = receivedInformation.value(UNREAD_MENTION_COUNT).toInt(); + LOG("Chat unread mention count updated" << chatId << unreadMentionCount); + emit chatUnreadMentionCountUpdated(chatId, unreadMentionCount); +} + +void TDLibReceiver::processUpdateChatUnreadReactionCount(const QVariantMap &receivedInformation) +{ + const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong(); + const int unreadReactionCount = receivedInformation.value(UNREAD_REACTION_COUNT).toInt(); + LOG("Chat unread reaction count updated" << chatId << unreadReactionCount); + emit chatUnreadReactionCountUpdated(chatId, unreadReactionCount); +} + // Recursively removes (some) unused entries from QVariantMaps to reduce // memory usage. QStrings allocated by QVariantMaps are the top consumers // of memory. The biggest saving is achieved by removing "outline" from diff --git a/src/tdlibreceiver.h b/src/tdlibreceiver.h index 0fade9e..b033d9d 100644 --- a/src/tdlibreceiver.h +++ b/src/tdlibreceiver.h @@ -103,6 +103,8 @@ signals: void okReceived(const QString &request); void sessionsReceived(const QVariantList &sessions); void availableReactionsReceived(qlonglong messageId, const QStringList &reactions); + void chatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount); + void chatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount); private: typedef void (TDLibReceiver::*Handler)(const QVariantMap &); @@ -182,6 +184,8 @@ private: void processUpdateMessageInteractionInfo(const QVariantMap &receivedInformation); void processSessions(const QVariantMap &receivedInformation); void processAvailableReactions(const QVariantMap &receivedInformation); + void processUpdateChatUnreadMentionCount(const QVariantMap &receivedInformation); + void processUpdateChatUnreadReactionCount(const QVariantMap &receivedInformation); }; #endif // TDLIBRECEIVER_H diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index 2f4c96b..6beeff6 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -166,6 +166,8 @@ void TDLibWrapper::initializeTDLibReceiver() { connect(this->tdLibReceiver, SIGNAL(okReceived(QString)), this, SIGNAL(okReceived(QString))); connect(this->tdLibReceiver, SIGNAL(sessionsReceived(QVariantList)), this, SIGNAL(sessionsReceived(QVariantList))); connect(this->tdLibReceiver, SIGNAL(availableReactionsReceived(qlonglong, QStringList)), this, SIGNAL(availableReactionsReceived(qlonglong, QStringList))); + connect(this->tdLibReceiver, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadMentionCountUpdated(qlonglong, int))); + connect(this->tdLibReceiver, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int)), this, SIGNAL(chatUnreadReactionCountUpdated(qlonglong, int))); this->tdLibReceiver->start(); } diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index c31962a..33560de 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -322,6 +322,8 @@ signals: void sessionsReceived(const QVariantList &sessions); void openFileExternally(const QString &filePath); void availableReactionsReceived(qlonglong messageId, const QStringList &reactions); + void chatUnreadMentionCountUpdated(qlonglong chatId, int unreadMentionCount); + void chatUnreadReactionCountUpdated(qlonglong chatId, int unreadReactionCount); void tgUrlFound(const QString &tgUrl); public slots: