From b1c43119909df28a3429f1f6129dcc0d8e9d5bb9 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Sun, 31 Jan 2021 22:08:39 +0200 Subject: [PATCH] Update message view counts in real time --- qml/components/MessageListViewItem.qml | 5 +- qml/pages/ChatPage.qml | 1 + src/chatmodel.cpp | 139 +++++++++++++++++++++---- src/chatmodel.h | 1 + src/tdlibreceiver.cpp | 10 ++ src/tdlibreceiver.h | 4 +- src/tdlibwrapper.cpp | 1 + src/tdlibwrapper.h | 1 + 8 files changed, 140 insertions(+), 22 deletions(-) diff --git a/qml/components/MessageListViewItem.qml b/qml/components/MessageListViewItem.qml index c72933a..021b9af 100644 --- a/qml/components/MessageListViewItem.qml +++ b/qml/components/MessageListViewItem.qml @@ -29,6 +29,7 @@ ListItem { property var chatId property var messageId property int messageIndex + property int messageViewCount property var myMessage property bool canReplyToMessage readonly property bool isAnonymous: myMessage.sender["@type"] === "messageSenderChat" @@ -490,10 +491,10 @@ ListItem { height: parent.height anchors.right: parent.right asynchronous: true - active: chatPage.isChannel && myMessage.interaction_info && myMessage.interaction_info.view_count + active: chatPage.isChannel && messageViewCount sourceComponent: Component { Label { - text: Functions.getShortenedCount(myMessage.interaction_info.view_count) + text: Functions.getShortenedCount(messageViewCount) leftPadding: Theme.iconSizeSmall font.pixelSize: Theme.fontSizeTiny color: Theme.secondaryColor diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index 69735f7..bc6bc34 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -1131,6 +1131,7 @@ Page { chatId: chatModel.chatId myMessage: model.display messageId: model.message_id + messageViewCount: model.view_count messageIndex: model.index hasContentComponent: !!myMessage.content && chatView.delegateMessagesContent.indexOf(model.content_type) > -1 canReplyToMessage: chatPage.canSendMessages diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp index 7dbc0a4..089783b 100644 --- a/src/chatmodel.cpp +++ b/src/chatmodel.cpp @@ -40,6 +40,15 @@ namespace { const QString PINNED_MESSAGE_ID("pinned_message_id"); const QString REPLY_MARKUP("reply_markup"); const QString _TYPE("@type"); + + // "interaction_info": { + // "@type": "messageInteractionInfo", + // "forward_count": 0, + // "view_count": 47 + // } + const QString TYPE_MESSAGE_INTERACTION_INFO("messageInteractionInfo"); + const QString INTERACTION_INFO("interaction_info"); + const QString VIEW_COUNT("view_count"); } class ChatModel::MessageData @@ -48,16 +57,35 @@ public: enum Role { RoleDisplay = Qt::DisplayRole, RoleMessageId, - RoleMessageContentType + RoleMessageContentType, + RoleMessageViewCount + }; + + enum RoleFlag { + RoleFlagDisplay = 0x01, + RoleFlagMessageId = 0x02, + RoleFlagMessageContentType = 0x04, + RoleFlagMessageViewCount = 0x08 }; MessageData(const QVariantMap &data, qlonglong msgid); static bool lessThan(const MessageData *message1, const MessageData *message2); + static QVector flagsToRoles(uint flags); + + uint updateMessageData(const QVariantMap &data); + uint updateContent(const QVariantMap &content); + uint updateContentType(const QVariantMap &content); + uint updateReplyMarkup(const QVariantMap &replyMarkup); + uint updateViewCount(const QVariantMap &interactionInfo); + uint updateInteractionInfo(const QVariantMap &interactionInfo); + QVector diff(const MessageData *message) const; QVector setMessageData(const QVariantMap &data); QVector setContent(const QVariantMap &content); QVector setReplyMarkup(const QVariantMap &replyMarkup); + QVector setInteractionInfo(const QVariantMap &interactionInfo); + int senderUserId() const; qlonglong senderChatId() const; bool senderIsChat() const; @@ -66,15 +94,35 @@ public: QVariantMap messageData; const qlonglong messageId; QString messageContentType; + int viewCount; }; ChatModel::MessageData::MessageData(const QVariantMap &data, qlonglong msgid) : messageData(data), messageId(msgid), - messageContentType(data.value(CONTENT).toMap().value(_TYPE).toString()) + messageContentType(data.value(CONTENT).toMap().value(_TYPE).toString()), + viewCount(data.value(INTERACTION_INFO).toMap().value(VIEW_COUNT).toInt()) { } +QVector ChatModel::MessageData::flagsToRoles(uint flags) +{ + QVector roles; + if (flags & RoleFlagDisplay) { + roles.append(RoleDisplay); + } + if (flags & RoleFlagMessageId) { + roles.append(RoleMessageId); + } + if (flags & RoleFlagMessageContentType) { + roles.append(RoleMessageContentType); + } + if (flags & RoleFlagMessageViewCount) { + roles.append(RoleMessageViewCount); + } + return roles; +} + int ChatModel::MessageData::senderUserId() const { return messageData.value(SENDER).toMap().value(USER_ID).toInt(); @@ -101,37 +149,74 @@ QVector ChatModel::MessageData::diff(const MessageData *message) const if (message->messageContentType != messageContentType) { roles.append(RoleMessageContentType); } + if (message->viewCount != viewCount) { + roles.append(RoleMessageViewCount); + } } return roles; } -QVector ChatModel::MessageData::setMessageData(const QVariantMap &data) +uint ChatModel::MessageData::updateMessageData(const QVariantMap &data) { messageData = data; - QVector changedRoles; - changedRoles.append(RoleDisplay); - return changedRoles; + return RoleFlagDisplay | + updateContentType(data.value(CONTENT).toMap()) | + updateViewCount(data.value(INTERACTION_INFO).toMap()); +} + +QVector ChatModel::MessageData::setMessageData(const QVariantMap &data) +{ + return flagsToRoles(updateMessageData(data)); +} + +uint ChatModel::MessageData::updateContentType(const QVariantMap &content) +{ + const QString oldContentType(messageContentType); + messageContentType = content.value(_TYPE).toString(); + return (oldContentType == messageContentType) ? 0 : RoleFlagMessageContentType; +} + +uint ChatModel::MessageData::updateContent(const QVariantMap &content) +{ + messageData.insert(CONTENT, content); + return RoleFlagDisplay | updateContentType(content); } QVector ChatModel::MessageData::setContent(const QVariantMap &content) { - const QString oldContentType(messageContentType); - messageData.insert(CONTENT, content); - messageContentType = content.value(_TYPE).toString(); - QVector changedRoles; - if (oldContentType != messageContentType) { - changedRoles.append(RoleMessageContentType); - } - changedRoles.append(RoleDisplay); - return changedRoles; + return flagsToRoles(updateContent(content)); +} + +uint ChatModel::MessageData::updateReplyMarkup(const QVariantMap &replyMarkup) +{ + messageData.insert(REPLY_MARKUP, replyMarkup); + return RoleFlagDisplay; } QVector ChatModel::MessageData::setReplyMarkup(const QVariantMap &replyMarkup) { - messageData.insert(REPLY_MARKUP, replyMarkup); - QVector changedRoles; - changedRoles.append(RoleDisplay); - return changedRoles; + return flagsToRoles(updateReplyMarkup(replyMarkup)); +} + +uint ChatModel::MessageData::updateViewCount(const QVariantMap &interactionInfo) +{ + const int oldViewCount = viewCount; + viewCount = interactionInfo.value(VIEW_COUNT).toInt(); + return (viewCount == oldViewCount) ? 0 : RoleFlagMessageViewCount; +} + +uint ChatModel::MessageData::updateInteractionInfo(const QVariantMap &interactionInfo) +{ + if (interactionInfo.value(_TYPE) == TYPE_MESSAGE_INTERACTION_INFO) { + messageData.insert(INTERACTION_INFO, interactionInfo); + return RoleFlagDisplay | updateViewCount(interactionInfo); + } + return 0; +} + +QVector ChatModel::MessageData::setInteractionInfo(const QVariantMap &info) +{ + return flagsToRoles(updateInteractionInfo(info)); } bool ChatModel::MessageData::lessThan(const MessageData *message1, const MessageData *message2) @@ -157,6 +242,7 @@ ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) : connect(this->tdLibWrapper, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SLOT(handleChatPinnedMessageUpdated(qlonglong, qlonglong))); connect(this->tdLibWrapper, SIGNAL(messageContentUpdated(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageContentUpdated(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibWrapper, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageEditedUpdated(qlonglong, qlonglong, QVariantMap))); + connect(this->tdLibWrapper, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap)), this, SLOT(handleMessageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibWrapper, SIGNAL(messagesDeleted(qlonglong, QList)), this, SLOT(handleMessagesDeleted(qlonglong, QList))); } @@ -172,6 +258,7 @@ QHash ChatModel::roleNames() const roles.insert(MessageData::RoleDisplay, "display"); roles.insert(MessageData::RoleMessageId, "message_id"); roles.insert(MessageData::RoleMessageContentType, "content_type"); + roles.insert(MessageData::RoleMessageViewCount, "view_count"); return roles; } @@ -189,6 +276,7 @@ QVariant ChatModel::data(const QModelIndex &index, int role) const case MessageData::RoleDisplay: return message->messageData; case MessageData::RoleMessageId: return message->messageId; case MessageData::RoleMessageContentType: return message->messageContentType; + case MessageData::RoleMessageViewCount: return message->viewCount; } } return QVariant(); @@ -497,6 +585,19 @@ void ChatModel::handleMessageContentUpdated(qlonglong chatId, qlonglong messageI } } +void ChatModel::handleMessageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo) +{ + if (chatId == this->chatId && messageIndexMap.contains(messageId)) { + const int pos = messageIndexMap.value(messageId, -1); + if (pos >= 0) { + LOG("Message interaction info was updated at index" << pos); + const QVector changedRoles(messages.at(pos)->setInteractionInfo(updatedInfo)); + const QModelIndex messageIndex(index(pos)); + emit dataChanged(messageIndex, messageIndex, changedRoles); + } + } +} + void ChatModel::handleMessageEditedUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &replyMarkup) { LOG("Message edited updated" << chatId << messageId); diff --git a/src/chatmodel.h b/src/chatmodel.h index 87d741a..30ce20f 100644 --- a/src/chatmodel.h +++ b/src/chatmodel.h @@ -73,6 +73,7 @@ private slots: void handleChatPinnedMessageUpdated(qlonglong chatId, qlonglong pinnedMessageId); void handleMessageContentUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &newContent); void handleMessageEditedUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &replyMarkup); + void handleMessageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo); void handleMessagesDeleted(qlonglong chatId, const QList &messageIds); private: diff --git a/src/tdlibreceiver.cpp b/src/tdlibreceiver.cpp index 0637403..d75f84e 100644 --- a/src/tdlibreceiver.cpp +++ b/src/tdlibreceiver.cpp @@ -48,6 +48,7 @@ namespace { const QString LAST_READ_INBOX_MESSAGE_ID("last_read_inbox_message_id"); const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id"); const QString SECRET_CHAT("secret_chat"); + const QString INTERACTION_INFO("interaction_info"); const QString TYPE("@type"); const QString EXTRA("@extra"); @@ -141,6 +142,7 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren handlers.insert("callbackQueryAnswer", &TDLibReceiver::processCallbackQueryAnswer); handlers.insert("userPrivacySettingRules", &TDLibReceiver::processUserPrivacySettingRules); handlers.insert("updateUserPrivacySettingRules", &TDLibReceiver::processUpdateUserPrivacySettingRules); + handlers.insert("updateMessageInteractionInfo", &TDLibReceiver::processUpdateMessageInteractionInfo); } void TDLibReceiver::setActive(bool active) @@ -628,3 +630,11 @@ void TDLibReceiver::processUpdateUserPrivacySettingRules(const QVariantMap &rece LOG("User privacy setting rules updated"); emit userPrivacySettingRulesUpdated(receivedInformation); } + +void TDLibReceiver::processUpdateMessageInteractionInfo(const QVariantMap &receivedInformation) +{ + const qlonglong chatId = receivedInformation.value(CHAT_ID).toLongLong(); + const qlonglong messageId = receivedInformation.value(MESSAGE_ID).toLongLong(); + LOG("Message interaction info updated" << chatId << messageId); + emit messageInteractionInfoUpdated(chatId, messageId, receivedInformation.value(INTERACTION_INFO).toMap()); +} diff --git a/src/tdlibreceiver.h b/src/tdlibreceiver.h index 9e46f82..326499b 100644 --- a/src/tdlibreceiver.h +++ b/src/tdlibreceiver.h @@ -97,6 +97,7 @@ signals: void callbackQueryAnswer(const QString &text, bool alert, const QString &url); void userPrivacySettingRules(const QVariantMap &rules); void userPrivacySettingRulesUpdated(const QVariantMap &updatedRules); + void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo); void okReceived(const QString &request); private: @@ -107,6 +108,7 @@ private: bool isActive; void receiverLoop(); + void nop(const QVariantMap &receivedInformation); void processReceivedDocument(const QJsonDocument &receivedJsonDocument); void processUpdateOption(const QVariantMap &receivedInformation); void processUpdateAuthorizationState(const QVariantMap &receivedInformation); @@ -158,7 +160,6 @@ private: void processUpdateMessageIsPinned(const QVariantMap &receivedInformation); void processUsers(const QVariantMap &receivedInformation); void processError(const QVariantMap &receivedInformation); - void nop(const QVariantMap &receivedInformation); void processSecretChat(const QVariantMap &receivedInformation); void processUpdateSecretChat(const QVariantMap &receivedInformation); void processUpdateMessageEdited(const QVariantMap &receivedInformation); @@ -169,6 +170,7 @@ private: void processCallbackQueryAnswer(const QVariantMap &receivedInformation); void processUserPrivacySettingRules(const QVariantMap &receivedInformation); void processUpdateUserPrivacySettingRules(const QVariantMap &receivedInformation); + void processUpdateMessageInteractionInfo(const QVariantMap &receivedInformation); }; #endif // TDLIBRECEIVER_H diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index 6b5b339..d762329 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -160,6 +160,7 @@ void TDLibWrapper::initializeTDLibReciever() { connect(this->tdLibReceiver, SIGNAL(callbackQueryAnswer(QString, bool, QString)), this, SIGNAL(callbackQueryAnswer(QString, bool, QString))); connect(this->tdLibReceiver, SIGNAL(userPrivacySettingRules(QVariantMap)), this, SLOT(handleUserPrivacySettingRules(QVariantMap))); connect(this->tdLibReceiver, SIGNAL(userPrivacySettingRulesUpdated(QVariantMap)), this, SLOT(handleUpdatedUserPrivacySettingRules(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageInteractionInfoUpdated(qlonglong, qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(okReceived(QString)), this, SIGNAL(okReceived(QString))); this->tdLibReceiver->start(); diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index f715b96..3536c8b 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -297,6 +297,7 @@ signals: void inlineQueryResults(const QString &inlineQueryId, const QString &nextOffset, const QVariantList &results, const QString &switchPmText, const QString &switchPmParameter, const QString &extra); void callbackQueryAnswer(const QString &text, bool alert, const QString &url); void userPrivacySettingUpdated(UserPrivacySetting setting, UserPrivacySettingRule rule); + void messageInteractionInfoUpdated(qlonglong chatId, qlonglong messageId, const QVariantMap &updatedInfo); void okReceived(const QString &request); public slots: