From 59abe95754ebd7cdc96b6ec5012b27b2fcdf2bf4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 15 Sep 2020 11:39:39 +0300 Subject: [PATCH] Show comments unread status. --- .../SourceFiles/data/data_replies_list.cpp | 19 +++- Telegram/SourceFiles/history/history_item.cpp | 15 ++++ Telegram/SourceFiles/history/history_item.h | 18 ++-- .../history/history_item_components.h | 3 +- .../SourceFiles/history/history_message.cpp | 90 +++++++++++++------ .../SourceFiles/history/history_message.h | 7 +- .../history/view/history_view_message.cpp | 17 +++- .../view/history_view_replies_section.cpp | 40 ++++----- .../window/window_session_controller.cpp | 9 +- 9 files changed, 155 insertions(+), 63 deletions(-) diff --git a/Telegram/SourceFiles/data/data_replies_list.cpp b/Telegram/SourceFiles/data/data_replies_list.cpp index 74a64a25f..ae5798e94 100644 --- a/Telegram/SourceFiles/data/data_replies_list.cpp +++ b/Telegram/SourceFiles/data/data_replies_list.cpp @@ -169,7 +169,9 @@ bool RepliesList::buildFromData(not_null viewer) { if (viewer->around != ShowAtUnreadMsgId) { return viewer->around; } else if (const auto item = lookupRoot()) { - return item->repliesReadTill(); + if (const auto original = item->lookupDiscussionPostOriginal()) { + return original->commentsReadTill(); + } } return viewer->around; }(); @@ -439,9 +441,9 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) { return true; } - const auto id = IdFromMessage(list.front()); + const auto maxId = IdFromMessage(list.front()); const auto wasSize = int(_list.size()); - const auto toFront = (wasSize > 0) && (id > _list.front()); + const auto toFront = (wasSize > 0) && (maxId > _list.front()); const auto clientFlags = MTPDmessage_ClientFlags(); const auto type = NewMessageType::Existing; auto refreshed = std::vector(); @@ -488,6 +490,17 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) { _skippedBefore = checkedCount - *_skippedAfter - nowSize; } _fullCount = checkedCount; + + if (const auto item = lookupRoot()) { + if (const auto original = item->lookupDiscussionPostOriginal()) { + if (_skippedAfter == 0) { + original->setCommentsMaxId(_list.front()); + } else { + original->setCommentsPossibleMaxId(maxId); + } + } + } + return false; } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 5c5aaa819..76ebd7e3b 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -256,6 +256,21 @@ bool HistoryItem::isDiscussionPost() const { return (discussionPostOriginalSender() != nullptr); } +HistoryItem *HistoryItem::lookupDiscussionPostOriginal() const { + if (!history()->peer->isMegagroup()) { + return nullptr; + } + const auto forwarded = Get(); + if (!forwarded + || !forwarded->savedFromPeer + || !forwarded->savedFromMsgId) { + return nullptr; + } + return _history->owner().message( + forwarded->savedFromPeer->asChannel(), + forwarded->savedFromMsgId); +} + PeerData *HistoryItem::displayFrom() const { if (const auto sender = discussionPostOriginalSender()) { return sender; diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 0871e3642..9aa217acd 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -206,6 +206,18 @@ public: } virtual void setCommentsItemId(FullMsgId id) { } + [[nodiscard]] virtual MsgId commentsReadTill() const { + return MsgId(0); + } + virtual void setCommentsReadTill(MsgId readTillId) { + } + virtual void setCommentsMaxId(MsgId maxId) { + } + virtual void setCommentsPossibleMaxId(MsgId possibleMaxId) { + } + [[nodiscard]] virtual bool areCommentsUnread() const { + return false; + } [[nodiscard]] virtual bool needCheck() const; @@ -267,11 +279,6 @@ public: } virtual void changeRepliesCount(int delta, PeerId replier) { } - virtual void setRepliesReadTill(MsgId readTillId) { - } - [[nodiscard]] virtual MsgId repliesReadTill() const { - return MsgId(0); - } virtual void setReplyToTop(MsgId replyToTop) { } virtual void setRealId(MsgId newId); @@ -356,6 +363,7 @@ public: [[nodiscard]] ChannelData *discussionPostOriginalSender() const; [[nodiscard]] bool isDiscussionPost() const; + [[nodiscard]] HistoryItem *lookupDiscussionPostOriginal() const; [[nodiscard]] PeerData *displayFrom() const; [[nodiscard]] virtual std::unique_ptr createView( diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 79a2b34cc..cd5bc368b 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -46,7 +46,8 @@ struct HistoryMessageViews : public RuntimeComponent { diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 7cb57da04..0037d7ba4 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -814,6 +814,58 @@ void HistoryMessage::setCommentsItemId(FullMsgId id) { } } +MsgId HistoryMessage::commentsReadTill() const { + if (const auto views = Get()) { + return views->commentsReadTillId; + } + return 0; +} + +void HistoryMessage::setCommentsReadTill(MsgId readTillId) { + if (const auto views = Get()) { + const auto newReadTillId = std::max(readTillId, 1); + if (newReadTillId > views->commentsReadTillId) { + const auto wasUnread = areCommentsUnread(); + views->commentsReadTillId = newReadTillId; + if (wasUnread && !areCommentsUnread()) { + history()->owner().requestItemRepaint(this); + } + } + } +} + +void HistoryMessage::setCommentsMaxId(MsgId maxId) { + if (const auto views = Get()) { + if (views->commentsMaxId != maxId) { + const auto wasUnread = areCommentsUnread(); + views->commentsMaxId = maxId; + if (wasUnread != areCommentsUnread()) { + history()->owner().requestItemRepaint(this); + } + } + } +} + +void HistoryMessage::setCommentsPossibleMaxId(MsgId possibleMaxId) { + if (const auto views = Get()) { + if (views->commentsMaxId < possibleMaxId) { + const auto wasUnread = areCommentsUnread(); + views->commentsMaxId = possibleMaxId; + if (!wasUnread && areCommentsUnread()) { + history()->owner().requestItemRepaint(this); + } + } + } +} + +bool HistoryMessage::areCommentsUnread() const { + if (const auto views = Get()) { + return (views->commentsReadTillId > 1) + && (views->commentsMaxId > views->commentsReadTillId); + } + return false; +} + bool HistoryMessage::updateDependencyItem() { if (const auto reply = Get()) { const auto documentId = reply->replyToDocumentId; @@ -1531,6 +1583,17 @@ void HistoryMessage::setReplies(const MTPMessageReplies &data) { views->recentRepliers = repliers; } views->commentsChannelId = channelId; + const auto wasUnread = areCommentsUnread(); + if (const auto till = data.vread_max_id()) { + views->commentsReadTillId = std::max( + { views->commentsReadTillId, till->v, 1 }); + } + if (const auto maxId = data.vmax_id()) { + views->commentsMaxId = maxId->v; + } + if (wasUnread != areCommentsUnread()) { + history()->owner().requestItemRepaint(this); + } refreshRepliesText(views, channelChanged); }); } @@ -1585,22 +1648,6 @@ void HistoryMessage::changeRepliesCount(int delta, PeerId replier) { refreshRepliesText(views); } -void HistoryMessage::setRepliesReadTill(MsgId readTillId) { - auto views = Get(); - if (!views) { - AddComponents(HistoryMessageViews::Bit()); - views = Get(); - } - views->repliesReadTillId = std::max(readTillId, 1); -} - -MsgId HistoryMessage::repliesReadTill() const { - if (const auto views = Get()) { - return views->repliesReadTillId; - } - return 0; -} - void HistoryMessage::setReplyToTop(MsgId replyToTop) { const auto reply = Get(); if (!reply @@ -1662,15 +1709,8 @@ void HistoryMessage::changeReplyToTopCounter( } } changeFor(top); - if (const auto sender = top->discussionPostOriginalSender()) { - if (const auto forwarded = top->Get()) { - const auto id = FullMsgId( - sender->bareId(), - forwarded->savedFromMsgId); - if (const auto original = history()->owner().message(id)) { - changeFor(original); - } - } + if (const auto original = top->lookupDiscussionPostOriginal()) { + changeFor(original); } } diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index 8112b0465..9a99811c9 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -136,8 +136,6 @@ public: void setForwardsCount(int count) override; void setReplies(const MTPMessageReplies &data) override; void changeRepliesCount(int delta, PeerId replier) override; - void setRepliesReadTill(MsgId readTillId) override; - MsgId repliesReadTill() const override; void setReplyToTop(MsgId replyToTop) override; void setRealId(MsgId newId) override; void incrementReplyToTopCounter() override; @@ -173,6 +171,11 @@ public: [[nodiscard]] bool externalReply() const override; [[nodiscard]] FullMsgId commentsItemId() const override; void setCommentsItemId(FullMsgId id) override; + [[nodiscard]] MsgId commentsReadTill() const override; + void setCommentsReadTill(MsgId readTillId) override; + void setCommentsMaxId(MsgId maxId) override; + void setCommentsPossibleMaxId(MsgId possibleMaxId) override; + [[nodiscard]] bool areCommentsUnread() const override; bool updateDependencyItem() override; [[nodiscard]] MsgId dependencyMsgId() const override { return replyToId(); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 0410ca212..b42933b37 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -373,7 +373,9 @@ QSize Message::performCountOptimalSize() { + st::historyCommentsSkipRight + st::historyCommentsSkipText + st::historyCommentsOpenOutSelected.width() - + st::historyCommentsSkipRight; + + st::historyCommentsSkipRight + + st::mediaUnreadSkip + + st::mediaUnreadSize; accumulate_max(maxWidth, added + views->replies.textWidth); } else if (item->externalReply()) { const auto added = st::historyCommentsIn.width() @@ -718,12 +720,23 @@ void Message::paintCommentsButton( p.setPen(outbg ? (selected ? st::msgFileThumbLinkOutFgSelected : st::msgFileThumbLinkOutFg) : (selected ? st::msgFileThumbLinkInFgSelected : st::msgFileThumbLinkInFg)); p.setFont(st::semiboldFont); + const auto textTop = top + (st::historyCommentsButtonHeight - st::semiboldFont->height) / 2; p.drawTextLeft( left, - top + (st::historyCommentsButtonHeight - st::semiboldFont->height) / 2, + textTop, width, views ? views->replies.text : tr::lng_replies_view_original(tr::now), views ? views->replies.textWidth : -1); + + if (views && data()->areCommentsUnread()) { + p.setPen(Qt::NoPen); + p.setBrush(outbg ? (selected ? st::msgFileOutBgSelected : st::msgFileOutBg) : (selected ? st::msgFileInBgSelected : st::msgFileInBg)); + + { + PainterHighQualityEnabler hq(p); + p.drawEllipse(style::rtlrect(left + views->replies.textWidth + st::mediaUnreadSkip, textTop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, width)); + } + } } void Message::paintFromName( diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 4223a4ab6..f6b7bd864 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -84,11 +84,13 @@ bool CanSendFiles(not_null data) { RepliesMemento::RepliesMemento(not_null commentsItem) : RepliesMemento(commentsItem->history(), commentsItem->id) { - if (commentsItem->repliesReadTill() == MsgId(1)) { - _list.setAroundPosition(Data::MinMessagePosition); - _list.setScrollTopState(ListMemento::ScrollTopState{ - Data::MinMessagePosition - }); + if (const auto original = commentsItem->lookupDiscussionPostOriginal()) { + if (original->commentsReadTill() == MsgId(1)) { + _list.setAroundPosition(Data::MinMessagePosition); + _list.setScrollTopState(ListMemento::ScrollTopState{ + Data::MinMessagePosition + }); + } } } @@ -215,7 +217,7 @@ RepliesWidget::~RepliesWidget() { } void RepliesWidget::sendReadTillRequest() { - if (!_commentsRoot || !_root) { + if (!_commentsRoot) { return; } if (_readRequestTimer.isActive()) { @@ -226,9 +228,8 @@ void RepliesWidget::sendReadTillRequest() { _readRequestId = api->request(MTPmessages_ReadDiscussion( _commentsRoot->history()->peer->input, MTP_int(_commentsRoot->id), - MTP_int(_root->repliesReadTill()) + MTP_int(_commentsRoot->commentsReadTill()) )).done([=](const MTPBool &) { - }).send(); } @@ -307,14 +308,9 @@ HistoryItem *RepliesWidget::lookupRoot() const { } HistoryItem *RepliesWidget::lookupCommentsRoot() const { - if (!computeAreComments()) { - return nullptr; - } - const auto forwarded = _root->Get(); - Assert(forwarded != nullptr); - return _history->owner().message( - forwarded->savedFromPeer->asChannel(), - forwarded->savedFromMsgId); + return _root + ? _root->lookupDiscussionPostOriginal() + : nullptr; } bool RepliesWidget::computeAreComments() const { @@ -1446,12 +1442,12 @@ void RepliesWidget::listSelectionChanged(SelectedItems &&items) { } void RepliesWidget::readTill(MsgId tillId) { - if (!_root) { + if (!_commentsRoot) { return; } - const auto now = _root->repliesReadTill(); + const auto now = _commentsRoot->commentsReadTill(); if (now < tillId) { - _root->setRepliesReadTill(tillId); + _commentsRoot->setCommentsReadTill(tillId); if (!_readRequestTimer.isActive()) { _readRequestTimer.callOnce(kReadRequestTimeout); } @@ -1470,10 +1466,10 @@ void RepliesWidget::listVisibleItemsChanged(HistoryItemsList &&items) { std::optional RepliesWidget::listUnreadBarView( const std::vector> &elements) { - if (!_root) { + if (!_commentsRoot) { return std::nullopt; } - const auto till = _root->repliesReadTill(); + const auto till = _commentsRoot->commentsReadTill(); if (till < 2) { return std::nullopt; } @@ -1481,7 +1477,7 @@ std::optional RepliesWidget::listUnreadBarView( const auto item = elements[i]->data(); if (item->id > till) { if (item->out()) { - _root->setRepliesReadTill(item->id); + _commentsRoot->setCommentsReadTill(item->id); _readRequestTimer.callOnce(kReadRequestTimeout); } else { return i; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index dc371b3a7..167ebbee0 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -147,9 +147,12 @@ void SessionNavigation::showRepliesForMessage( const auto post = _session->data().message(channelId, rootId); if (post) { post->setCommentsItemId(item->fullId()); - } - if (const auto readTill = data.vread_max_id()) { - item->setRepliesReadTill(readTill->v); + if (const auto maxId = data.vmax_id()) { + post->setCommentsMaxId(maxId->v); + } + if (const auto readTill = data.vread_max_id()) { + post->setCommentsReadTill(readTill->v); + } } showSection( HistoryView::RepliesMemento(item));