From f2ed77649e91a816b5c29263b2026c4f5bd5439d Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 9 Feb 2023 09:56:47 +0400 Subject: [PATCH] Preload complex last message on demand. --- Telegram/SourceFiles/boxes/share_box.cpp | 4 +- Telegram/SourceFiles/data/data_folder.cpp | 2 +- Telegram/SourceFiles/data/data_folder.h | 2 +- .../SourceFiles/data/data_forum_topic.cpp | 40 +++++++--- Telegram/SourceFiles/data/data_forum_topic.h | 5 +- Telegram/SourceFiles/dialogs/dialogs_entry.h | 2 +- .../dialogs/dialogs_inner_widget.cpp | 14 ++-- .../dialogs/dialogs_inner_widget.h | 2 +- .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 1 + Telegram/SourceFiles/history/history.cpp | 78 ++++++++++++------- Telegram/SourceFiles/history/history.h | 6 +- 11 files changed, 101 insertions(+), 55 deletions(-) diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index b3245188f..548edf1fd 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -854,7 +854,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) { if (((*i)->index() * _rowHeight) >= yTo) { break; } - (*i)->entry()->loadUserpic(); + (*i)->entry()->chatListPreloadData(); } } } else if (!_filtered.empty()) { @@ -865,7 +865,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) { if (to > _filtered.size()) to = _filtered.size(); for (; from < to; ++from) { - _filtered[from]->entry()->loadUserpic(); + _filtered[from]->entry()->chatListPreloadData(); } } } diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp index bd027837b..f3cc2c638 100644 --- a/Telegram/SourceFiles/data/data_folder.cpp +++ b/Telegram/SourceFiles/data/data_folder.cpp @@ -211,7 +211,7 @@ not_null Folder::chatsList() { return &_chatsList; } -void Folder::loadUserpic() { +void Folder::chatListPreloadData() { } void Folder::paintUserpic( diff --git a/Telegram/SourceFiles/data/data_folder.h b/Telegram/SourceFiles/data/data_folder.h index 779c1ba1b..665443755 100644 --- a/Telegram/SourceFiles/data/data_folder.h +++ b/Telegram/SourceFiles/data/data_folder.h @@ -54,7 +54,7 @@ public: const base::flat_set &chatListNameWords() const override; const base::flat_set &chatListFirstLetters() const override; - void loadUserpic() override; + void chatListPreloadData() override; void paintUserpic( Painter &p, Ui::PeerUserpicView &view, diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index bf7ee2ec0..5925f303d 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -471,17 +471,7 @@ void ForumTopic::applyTopicTopMessage(MsgId topMessageId) { const auto itemId = FullMsgId(channel()->id, topMessageId); if (const auto item = owner().message(itemId)) { setLastServerMessage(item); - - // If we set a single album part, request the full album. - if (item->groupId() != MessageGroupId()) { - if (owner().groups().isGroupOfOne(item) - && !item->toPreview({ - .hideSender = true, - .hideCaption = true }).images.empty() - && _requestedGroups.emplace(item->fullId()).second) { - owner().histories().requestGroupAround(item); - } - } + resolveChatListMessageGroup(); } else { setLastServerMessage(nullptr); } @@ -490,6 +480,23 @@ void ForumTopic::applyTopicTopMessage(MsgId topMessageId) { } } +void ForumTopic::resolveChatListMessageGroup() { + if (!(_flags & Flag::ResolveChatListMessage)) { + return; + } + // If we set a single album part, request the full album. + const auto item = _lastServerMessage.value_or(nullptr); + if (item && item->groupId() != MessageGroupId()) { + if (owner().groups().isGroupOfOne(item) + && !item->toPreview({ + .hideSender = true, + .hideCaption = true }).images.empty() + && _requestedGroups.emplace(item->fullId()).second) { + owner().histories().requestGroupAround(item); + } + } +} + void ForumTopic::growLastKnownServerMessageId(MsgId id) { _lastKnownServerMessageId = std::max(_lastKnownServerMessageId, id); } @@ -548,10 +555,11 @@ void ForumTopic::setChatListMessage(HistoryItem *item) { _forum->listMessageChanged(was, item); } -void ForumTopic::loadUserpic() { +void ForumTopic::chatListPreloadData() { if (_icon) { [[maybe_unused]] const auto preload = _icon->ready(); } + allowChatListMessageResolve(); } void ForumTopic::paintUserpic( @@ -840,6 +848,14 @@ Dialogs::UnreadState ForumTopic::unreadStateFor( return result; } +void ForumTopic::allowChatListMessageResolve() { + if (_flags & Flag::ResolveChatListMessage) { + return; + } + _flags |= Flag::ResolveChatListMessage; + resolveChatListMessageGroup(); +} + HistoryItem *ForumTopic::chatListMessage() const { return _lastMessage.value_or(nullptr); } diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 295685e76..66430a0a3 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -146,7 +146,7 @@ public: return _notify; } - void loadUserpic() override; + void chatListPreloadData() override; void paintUserpic( Painter &p, Ui::PeerUserpicView &view, @@ -169,6 +169,7 @@ private: HasPinnedMessages = (1 << 3), GeneralIconActive = (1 << 4), GeneralIconSelected = (1 << 5), + ResolveChatListMessage = (1 << 6), }; friend inline constexpr bool is_flag_type(Flag) { return true; } using Flags = base::flags; @@ -183,6 +184,8 @@ private: void setLastMessage(HistoryItem *item); void setLastServerMessage(HistoryItem *item); void setChatListMessage(HistoryItem *item); + void allowChatListMessageResolve(); + void resolveChatListMessageGroup(); int chatListNameVersion() const override; diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h index bfb38d6dc..3ad4281f3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.h +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h @@ -230,7 +230,7 @@ public: return nullptr; } - virtual void loadUserpic() = 0; + virtual void chatListPreloadData() = 0; virtual void paintUserpic( Painter &p, Ui::PeerUserpicView &view, diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 08b9ad537..352fcfe0f 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -2506,7 +2506,7 @@ void InnerWidget::visibleTopBottomUpdated( int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; - loadPeerPhotos(); + preloadRowsData(); const auto loadTill = _visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop); if (_state == WidgetState::Filtered && loadTill >= peerSearchOffset()) { @@ -2726,7 +2726,7 @@ void InnerWidget::refresh(bool toTop) { if (toTop) { stopReorderPinned(); _mustScrollTo.fire({ 0, 0 }); - loadPeerPhotos(); + preloadRowsData(); } _controller->setDialogsListDisplayForced( _searchInChat || !_filter.isEmpty()); @@ -3115,8 +3115,10 @@ void InnerWidget::scrollToDefaultSelected() { } } -void InnerWidget::loadPeerPhotos() { - if (!parentWidget()) return; +void InnerWidget::preloadRowsData() { + if (!parentWidget()) { + return; + } auto yFrom = _visibleTop; auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1); @@ -3129,7 +3131,7 @@ void InnerWidget::loadPeerPhotos() { if (((*i)->index() * _st->height) >= yTo) { break; } - (*i)->entry()->loadUserpic(); + (*i)->entry()->chatListPreloadData(); } yFrom = 0; } else { @@ -3144,7 +3146,7 @@ void InnerWidget::loadPeerPhotos() { if (to > _filterResults.size()) to = _filterResults.size(); for (; from < to; ++from) { - _filterResults[from].key().entry()->loadUserpic(); + _filterResults[from].key().entry()->chatListPreloadData(); } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 00d06ba99..6b01e940f 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -243,7 +243,7 @@ private: Qt::KeyboardModifiers modifiers); void clearIrrelevantState(); void selectByMouse(QPoint globalPosition); - void loadPeerPhotos(); + void preloadRowsData(); void scrollToItem(int top, int height); void scrollToDefaultSelected(); void setCollapsedPressed(int pressed); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 81939e8f3..a104294ff 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -743,6 +743,7 @@ void RowPainter::Paint( const auto thread = row->thread(); const auto peer = history ? history->peer.get() : nullptr; const auto badgesState = entry->chatListBadgesState(); + entry->chatListPreloadData(); // Allow chat list message resolve. const auto item = entry->chatListMessage(); const auto cloudDraft = [&]() -> const Data::Draft*{ if (!thread) { diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 77251f700..5b965667b 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -607,16 +607,6 @@ not_null History::addNewItem( } else { addNewToBack(item, unread); checkForLoadedAtTop(item); - if (!unread) { - // When we add just one last item, like we do while loading dialogs, - // we want to remove a single added grouped media, otherwise it will - // jump once we open the message history (first we show only that - // media, then we load the rest of the group and show the group). - // - // That way when we open the message history we show nothing until a - // whole history part is loaded, it certainly will contain the group. - removeOrphanMediaGroupPart(); - } } return item; } @@ -2241,6 +2231,44 @@ Dialogs::UnreadState History::computeUnreadState() const { return result; } +void History::allowChatListMessageResolve() { + if (_flags & Flag::ResolveChatListMessage) { + return; + } + _flags |= Flag::ResolveChatListMessage; + if (!chatListMessageKnown()) { + requestChatListMessage(); + } else { + resolveChatListMessageGroup(); + } +} + +void History::resolveChatListMessageGroup() { + const auto item = _chatListMessage.value_or(nullptr); + if (!(_flags & Flag::ResolveChatListMessage) + || !item + || !hasOrphanMediaGroupPart()) { + return; + } + // If we set a single album part, request the full album. + const auto withImages = !item->toPreview({ + .hideSender = true, + .hideCaption = true }).images.empty(); + if (withImages) { + owner().histories().requestGroupAround(item); + } + if (unreadCountKnown() && !unreadCount()) { + // When we add just one last item, like we do while loading dialogs, + // we want to remove a single added grouped media, otherwise it will + // jump once we open the message history (first we show only that + // media, then we load the rest of the group and show the group). + // + // That way when we open the message history we show nothing until a + // whole history part is loaded, it certainly will contain the group. + clear(ClearType::Unload); + } +} + HistoryItem *History::chatListMessage() const { return _chatListMessage.value_or(nullptr); } @@ -2269,8 +2297,9 @@ const base::flat_set &History::chatListFirstLetters() const { return peer->nameFirstLetters(); } -void History::loadUserpic() { +void History::chatListPreloadData() { peer->loadUserpic(); + allowChatListMessageResolve(); } void History::paintUserpic( @@ -2452,14 +2481,7 @@ void History::setChatListMessage(HistoryItem *item) { } _chatListMessage = item; setChatListTimeId(item->date()); - - // If we have a single message from a group, request the full album. - if (hasOrphanMediaGroupPart() - && !item->toPreview({ - .hideSender = true, - .hideCaption = true }).images.empty()) { - owner().histories().requestGroupAround(item); - } + resolveChatListMessageGroup(); } else if (!_chatListMessage || *_chatListMessage) { _chatListMessage = nullptr; updateChatListEntry(); @@ -2560,13 +2582,21 @@ void History::requestChatListMessage() { } void History::setFakeChatListMessage() { - if (const auto chat = peer->asChat()) { + if (!(_flags & Flag::ResolveChatListMessage)) { + if (!chatListTimeId()) { + if (const auto last = lastMessage()) { + setChatListTimeId(last->date()); + } + } + return; + } else if (const auto chat = peer->asChat()) { // In chats we try to take the item before the 'last', which // is the empty-displayed migration message. owner().histories().requestFakeChatListMessage(this); } else if (const auto from = migrateFrom()) { // In megagroups we just try to use // the message from the original group. + from->allowChatListMessageResolve(); from->requestChatListMessage(); } } @@ -3309,14 +3339,6 @@ bool History::hasOrphanMediaGroupPart() const { return last->groupId() != MessageGroupId(); } -bool History::removeOrphanMediaGroupPart() { - if (hasOrphanMediaGroupPart()) { - clear(ClearType::Unload); - return true; - } - return false; -} - std::vector History::collectMessagesFromParticipantToDelete( not_null participant) const { auto result = std::vector(); diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 1d91860d6..d2b80be10 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -111,7 +111,6 @@ public: Element *findLastNonEmpty() const; Element *findLastDisplayed() const; bool hasOrphanMediaGroupPart() const; - bool removeOrphanMediaGroupPart(); [[nodiscard]] std::vector collectMessagesFromParticipantToDelete( not_null participant) const; @@ -387,7 +386,7 @@ public: const QString &chatListNameSortKey() const override; const base::flat_set &chatListNameWords() const override; const base::flat_set &chatListFirstLetters() const override; - void loadUserpic() override; + void chatListPreloadData() override; void paintUserpic( Painter &p, Ui::PeerUserpicView &view, @@ -467,6 +466,7 @@ private: IsForum = (1 << 3), FakeUnreadWhileOpened = (1 << 4), HasPinnedMessages = (1 << 5), + ResolveChatListMessage = (1 << 6), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { @@ -553,6 +553,8 @@ private: void setChatListMessageFromLast(); void setChatListMessageUnknown(); void setFakeChatListMessage(); + void allowChatListMessageResolve(); + void resolveChatListMessageGroup(); // Add all items to the unread mentions if we were not loaded at bottom and now are. void checkAddAllToUnreadMentions();