Show comments unread status.

This commit is contained in:
John Preston 2020-09-15 11:39:39 +03:00
parent 040f29abe6
commit 59abe95754
9 changed files with 155 additions and 63 deletions

View file

@ -169,7 +169,9 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
if (viewer->around != ShowAtUnreadMsgId) { if (viewer->around != ShowAtUnreadMsgId) {
return viewer->around; return viewer->around;
} else if (const auto item = lookupRoot()) { } else if (const auto item = lookupRoot()) {
return item->repliesReadTill(); if (const auto original = item->lookupDiscussionPostOriginal()) {
return original->commentsReadTill();
}
} }
return viewer->around; return viewer->around;
}(); }();
@ -439,9 +441,9 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) {
return true; return true;
} }
const auto id = IdFromMessage(list.front()); const auto maxId = IdFromMessage(list.front());
const auto wasSize = int(_list.size()); 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 clientFlags = MTPDmessage_ClientFlags();
const auto type = NewMessageType::Existing; const auto type = NewMessageType::Existing;
auto refreshed = std::vector<MsgId>(); auto refreshed = std::vector<MsgId>();
@ -488,6 +490,17 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) {
_skippedBefore = checkedCount - *_skippedAfter - nowSize; _skippedBefore = checkedCount - *_skippedAfter - nowSize;
} }
_fullCount = checkedCount; _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; return false;
} }

View file

@ -256,6 +256,21 @@ bool HistoryItem::isDiscussionPost() const {
return (discussionPostOriginalSender() != nullptr); return (discussionPostOriginalSender() != nullptr);
} }
HistoryItem *HistoryItem::lookupDiscussionPostOriginal() const {
if (!history()->peer->isMegagroup()) {
return nullptr;
}
const auto forwarded = Get<HistoryMessageForwarded>();
if (!forwarded
|| !forwarded->savedFromPeer
|| !forwarded->savedFromMsgId) {
return nullptr;
}
return _history->owner().message(
forwarded->savedFromPeer->asChannel(),
forwarded->savedFromMsgId);
}
PeerData *HistoryItem::displayFrom() const { PeerData *HistoryItem::displayFrom() const {
if (const auto sender = discussionPostOriginalSender()) { if (const auto sender = discussionPostOriginalSender()) {
return sender; return sender;

View file

@ -206,6 +206,18 @@ public:
} }
virtual void setCommentsItemId(FullMsgId id) { 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; [[nodiscard]] virtual bool needCheck() const;
@ -267,11 +279,6 @@ public:
} }
virtual void changeRepliesCount(int delta, PeerId replier) { 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 setReplyToTop(MsgId replyToTop) {
} }
virtual void setRealId(MsgId newId); virtual void setRealId(MsgId newId);
@ -356,6 +363,7 @@ public:
[[nodiscard]] ChannelData *discussionPostOriginalSender() const; [[nodiscard]] ChannelData *discussionPostOriginalSender() const;
[[nodiscard]] bool isDiscussionPost() const; [[nodiscard]] bool isDiscussionPost() const;
[[nodiscard]] HistoryItem *lookupDiscussionPostOriginal() const;
[[nodiscard]] PeerData *displayFrom() const; [[nodiscard]] PeerData *displayFrom() const;
[[nodiscard]] virtual std::unique_ptr<HistoryView::Element> createView( [[nodiscard]] virtual std::unique_ptr<HistoryView::Element> createView(

View file

@ -46,7 +46,8 @@ struct HistoryMessageViews : public RuntimeComponent<HistoryMessageViews, Histor
Part replies; Part replies;
ChannelId commentsChannelId = 0; ChannelId commentsChannelId = 0;
MsgId commentsRootId = 0; MsgId commentsRootId = 0;
MsgId repliesReadTillId = 0; MsgId commentsReadTillId = 0;
MsgId commentsMaxId = 0;
}; };
struct HistoryMessageSigned : public RuntimeComponent<HistoryMessageSigned, HistoryItem> { struct HistoryMessageSigned : public RuntimeComponent<HistoryMessageSigned, HistoryItem> {

View file

@ -814,6 +814,58 @@ void HistoryMessage::setCommentsItemId(FullMsgId id) {
} }
} }
MsgId HistoryMessage::commentsReadTill() const {
if (const auto views = Get<HistoryMessageViews>()) {
return views->commentsReadTillId;
}
return 0;
}
void HistoryMessage::setCommentsReadTill(MsgId readTillId) {
if (const auto views = Get<HistoryMessageViews>()) {
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<HistoryMessageViews>()) {
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<HistoryMessageViews>()) {
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<HistoryMessageViews>()) {
return (views->commentsReadTillId > 1)
&& (views->commentsMaxId > views->commentsReadTillId);
}
return false;
}
bool HistoryMessage::updateDependencyItem() { bool HistoryMessage::updateDependencyItem() {
if (const auto reply = Get<HistoryMessageReply>()) { if (const auto reply = Get<HistoryMessageReply>()) {
const auto documentId = reply->replyToDocumentId; const auto documentId = reply->replyToDocumentId;
@ -1531,6 +1583,17 @@ void HistoryMessage::setReplies(const MTPMessageReplies &data) {
views->recentRepliers = repliers; views->recentRepliers = repliers;
} }
views->commentsChannelId = channelId; 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); refreshRepliesText(views, channelChanged);
}); });
} }
@ -1585,22 +1648,6 @@ void HistoryMessage::changeRepliesCount(int delta, PeerId replier) {
refreshRepliesText(views); refreshRepliesText(views);
} }
void HistoryMessage::setRepliesReadTill(MsgId readTillId) {
auto views = Get<HistoryMessageViews>();
if (!views) {
AddComponents(HistoryMessageViews::Bit());
views = Get<HistoryMessageViews>();
}
views->repliesReadTillId = std::max(readTillId, 1);
}
MsgId HistoryMessage::repliesReadTill() const {
if (const auto views = Get<HistoryMessageViews>()) {
return views->repliesReadTillId;
}
return 0;
}
void HistoryMessage::setReplyToTop(MsgId replyToTop) { void HistoryMessage::setReplyToTop(MsgId replyToTop) {
const auto reply = Get<HistoryMessageReply>(); const auto reply = Get<HistoryMessageReply>();
if (!reply if (!reply
@ -1662,15 +1709,8 @@ void HistoryMessage::changeReplyToTopCounter(
} }
} }
changeFor(top); changeFor(top);
if (const auto sender = top->discussionPostOriginalSender()) { if (const auto original = top->lookupDiscussionPostOriginal()) {
if (const auto forwarded = top->Get<HistoryMessageForwarded>()) { changeFor(original);
const auto id = FullMsgId(
sender->bareId(),
forwarded->savedFromMsgId);
if (const auto original = history()->owner().message(id)) {
changeFor(original);
}
}
} }
} }

View file

@ -136,8 +136,6 @@ public:
void setForwardsCount(int count) override; void setForwardsCount(int count) override;
void setReplies(const MTPMessageReplies &data) override; void setReplies(const MTPMessageReplies &data) override;
void changeRepliesCount(int delta, PeerId replier) override; void changeRepliesCount(int delta, PeerId replier) override;
void setRepliesReadTill(MsgId readTillId) override;
MsgId repliesReadTill() const override;
void setReplyToTop(MsgId replyToTop) override; void setReplyToTop(MsgId replyToTop) override;
void setRealId(MsgId newId) override; void setRealId(MsgId newId) override;
void incrementReplyToTopCounter() override; void incrementReplyToTopCounter() override;
@ -173,6 +171,11 @@ public:
[[nodiscard]] bool externalReply() const override; [[nodiscard]] bool externalReply() const override;
[[nodiscard]] FullMsgId commentsItemId() const override; [[nodiscard]] FullMsgId commentsItemId() const override;
void setCommentsItemId(FullMsgId id) 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; bool updateDependencyItem() override;
[[nodiscard]] MsgId dependencyMsgId() const override { [[nodiscard]] MsgId dependencyMsgId() const override {
return replyToId(); return replyToId();

View file

@ -373,7 +373,9 @@ QSize Message::performCountOptimalSize() {
+ st::historyCommentsSkipRight + st::historyCommentsSkipRight
+ st::historyCommentsSkipText + st::historyCommentsSkipText
+ st::historyCommentsOpenOutSelected.width() + st::historyCommentsOpenOutSelected.width()
+ st::historyCommentsSkipRight; + st::historyCommentsSkipRight
+ st::mediaUnreadSkip
+ st::mediaUnreadSize;
accumulate_max(maxWidth, added + views->replies.textWidth); accumulate_max(maxWidth, added + views->replies.textWidth);
} else if (item->externalReply()) { } else if (item->externalReply()) {
const auto added = st::historyCommentsIn.width() 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.setPen(outbg ? (selected ? st::msgFileThumbLinkOutFgSelected : st::msgFileThumbLinkOutFg) : (selected ? st::msgFileThumbLinkInFgSelected : st::msgFileThumbLinkInFg));
p.setFont(st::semiboldFont); p.setFont(st::semiboldFont);
const auto textTop = top + (st::historyCommentsButtonHeight - st::semiboldFont->height) / 2;
p.drawTextLeft( p.drawTextLeft(
left, left,
top + (st::historyCommentsButtonHeight - st::semiboldFont->height) / 2, textTop,
width, width,
views ? views->replies.text : tr::lng_replies_view_original(tr::now), views ? views->replies.text : tr::lng_replies_view_original(tr::now),
views ? views->replies.textWidth : -1); 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( void Message::paintFromName(

View file

@ -84,11 +84,13 @@ bool CanSendFiles(not_null<const QMimeData*> data) {
RepliesMemento::RepliesMemento(not_null<HistoryItem*> commentsItem) RepliesMemento::RepliesMemento(not_null<HistoryItem*> commentsItem)
: RepliesMemento(commentsItem->history(), commentsItem->id) { : RepliesMemento(commentsItem->history(), commentsItem->id) {
if (commentsItem->repliesReadTill() == MsgId(1)) { if (const auto original = commentsItem->lookupDiscussionPostOriginal()) {
_list.setAroundPosition(Data::MinMessagePosition); if (original->commentsReadTill() == MsgId(1)) {
_list.setScrollTopState(ListMemento::ScrollTopState{ _list.setAroundPosition(Data::MinMessagePosition);
Data::MinMessagePosition _list.setScrollTopState(ListMemento::ScrollTopState{
}); Data::MinMessagePosition
});
}
} }
} }
@ -215,7 +217,7 @@ RepliesWidget::~RepliesWidget() {
} }
void RepliesWidget::sendReadTillRequest() { void RepliesWidget::sendReadTillRequest() {
if (!_commentsRoot || !_root) { if (!_commentsRoot) {
return; return;
} }
if (_readRequestTimer.isActive()) { if (_readRequestTimer.isActive()) {
@ -226,9 +228,8 @@ void RepliesWidget::sendReadTillRequest() {
_readRequestId = api->request(MTPmessages_ReadDiscussion( _readRequestId = api->request(MTPmessages_ReadDiscussion(
_commentsRoot->history()->peer->input, _commentsRoot->history()->peer->input,
MTP_int(_commentsRoot->id), MTP_int(_commentsRoot->id),
MTP_int(_root->repliesReadTill()) MTP_int(_commentsRoot->commentsReadTill())
)).done([=](const MTPBool &) { )).done([=](const MTPBool &) {
}).send(); }).send();
} }
@ -307,14 +308,9 @@ HistoryItem *RepliesWidget::lookupRoot() const {
} }
HistoryItem *RepliesWidget::lookupCommentsRoot() const { HistoryItem *RepliesWidget::lookupCommentsRoot() const {
if (!computeAreComments()) { return _root
return nullptr; ? _root->lookupDiscussionPostOriginal()
} : nullptr;
const auto forwarded = _root->Get<HistoryMessageForwarded>();
Assert(forwarded != nullptr);
return _history->owner().message(
forwarded->savedFromPeer->asChannel(),
forwarded->savedFromMsgId);
} }
bool RepliesWidget::computeAreComments() const { bool RepliesWidget::computeAreComments() const {
@ -1446,12 +1442,12 @@ void RepliesWidget::listSelectionChanged(SelectedItems &&items) {
} }
void RepliesWidget::readTill(MsgId tillId) { void RepliesWidget::readTill(MsgId tillId) {
if (!_root) { if (!_commentsRoot) {
return; return;
} }
const auto now = _root->repliesReadTill(); const auto now = _commentsRoot->commentsReadTill();
if (now < tillId) { if (now < tillId) {
_root->setRepliesReadTill(tillId); _commentsRoot->setCommentsReadTill(tillId);
if (!_readRequestTimer.isActive()) { if (!_readRequestTimer.isActive()) {
_readRequestTimer.callOnce(kReadRequestTimeout); _readRequestTimer.callOnce(kReadRequestTimeout);
} }
@ -1470,10 +1466,10 @@ void RepliesWidget::listVisibleItemsChanged(HistoryItemsList &&items) {
std::optional<int> RepliesWidget::listUnreadBarView( std::optional<int> RepliesWidget::listUnreadBarView(
const std::vector<not_null<Element*>> &elements) { const std::vector<not_null<Element*>> &elements) {
if (!_root) { if (!_commentsRoot) {
return std::nullopt; return std::nullopt;
} }
const auto till = _root->repliesReadTill(); const auto till = _commentsRoot->commentsReadTill();
if (till < 2) { if (till < 2) {
return std::nullopt; return std::nullopt;
} }
@ -1481,7 +1477,7 @@ std::optional<int> RepliesWidget::listUnreadBarView(
const auto item = elements[i]->data(); const auto item = elements[i]->data();
if (item->id > till) { if (item->id > till) {
if (item->out()) { if (item->out()) {
_root->setRepliesReadTill(item->id); _commentsRoot->setCommentsReadTill(item->id);
_readRequestTimer.callOnce(kReadRequestTimeout); _readRequestTimer.callOnce(kReadRequestTimeout);
} else { } else {
return i; return i;

View file

@ -147,9 +147,12 @@ void SessionNavigation::showRepliesForMessage(
const auto post = _session->data().message(channelId, rootId); const auto post = _session->data().message(channelId, rootId);
if (post) { if (post) {
post->setCommentsItemId(item->fullId()); post->setCommentsItemId(item->fullId());
} if (const auto maxId = data.vmax_id()) {
if (const auto readTill = data.vread_max_id()) { post->setCommentsMaxId(maxId->v);
item->setRepliesReadTill(readTill->v); }
if (const auto readTill = data.vread_max_id()) {
post->setCommentsReadTill(readTill->v);
}
} }
showSection( showSection(
HistoryView::RepliesMemento(item)); HistoryView::RepliesMemento(item));