From cd5cad72bd7cb8bcf2c335816abdb78c7ae99f87 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 21 Oct 2020 14:07:49 +0300 Subject: [PATCH] Use only shared media code for pinned tracking. --- Telegram/CMakeLists.txt | 2 - Telegram/SourceFiles/apiwrap.cpp | 3 + Telegram/SourceFiles/boxes/confirm_box.cpp | 2 +- Telegram/SourceFiles/data/data_changes.h | 2 +- Telegram/SourceFiles/data/data_channel.cpp | 4 +- Telegram/SourceFiles/data/data_chat.cpp | 4 +- Telegram/SourceFiles/data/data_peer.cpp | 84 +++++------- Telegram/SourceFiles/data/data_peer.h | 20 +-- .../SourceFiles/data/data_pinned_messages.cpp | 88 ------------ .../SourceFiles/data/data_pinned_messages.h | 43 ------ Telegram/SourceFiles/data/data_user.cpp | 4 +- Telegram/SourceFiles/history/history.cpp | 7 + Telegram/SourceFiles/history/history_item.cpp | 9 +- .../SourceFiles/history/history_widget.cpp | 18 +-- .../view/history_view_pinned_section.cpp | 1 - .../view/history_view_pinned_tracker.cpp | 129 +++++++++++------- .../view/history_view_pinned_tracker.h | 15 +- 17 files changed, 162 insertions(+), 273 deletions(-) delete mode 100644 Telegram/SourceFiles/data/data_pinned_messages.cpp delete mode 100644 Telegram/SourceFiles/data/data_pinned_messages.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index a04fd853a3..85f68e3781 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -400,8 +400,6 @@ PRIVATE data/data_photo.h data/data_photo_media.cpp data/data_photo_media.h - data/data_pinned_messages.cpp - data/data_pinned_messages.h data/data_poll.cpp data/data_poll.h data/data_pts_waiter.cpp diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 0d5a88a9b6..a51049a54c 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3570,6 +3570,9 @@ void ApiWrap::sharedMediaDone( parsed.noSkipRange, parsed.fullCount )); + if (type == SharedMediaType::Pinned && !parsed.messageIds.empty()) { + peer->setHasPinnedMessages(true); + } } void ApiWrap::requestUserPhotos( diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index b098ef1002..7c5afd5103 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -444,7 +444,7 @@ PinMessageBox::PinMessageBox( : _peer(peer) , _api(&peer->session().mtp()) , _msgId(msgId) -, _pinningOld(msgId < peer->topPinnedMessageId()) +, _pinningOld(msgId < Data::ResolveTopPinnedId(peer)) , _text( this, (_pinningOld diff --git a/Telegram/SourceFiles/data/data_changes.h b/Telegram/SourceFiles/data/data_changes.h index 3a363ee6ee..5bd4436886 100644 --- a/Telegram/SourceFiles/data/data_changes.h +++ b/Telegram/SourceFiles/data/data_changes.h @@ -57,7 +57,7 @@ struct PeerUpdate { Notifications = (1 << 4), Migration = (1 << 5), UnavailableReason = (1 << 6), - PinnedMessage = (1 << 7), + PinnedMessages = (1 << 7), IsBlocked = (1 << 8), // For users diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index e2b6b8c9bd..102eb637e4 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -769,9 +769,7 @@ void ApplyChannelUpdate( } } if (const auto pinned = update.vpinned_msg_id()) { - channel->setTopPinnedMessageId(pinned->v); - } else { - channel->clearPinnedMessages(); + SetTopPinnedMessageId(channel, pinned->v); } if (channel->isMegagroup()) { const auto stickerSet = update.vstickerset(); diff --git a/Telegram/SourceFiles/data/data_chat.cpp b/Telegram/SourceFiles/data/data_chat.cpp index 37930f1030..47c1679517 100644 --- a/Telegram/SourceFiles/data/data_chat.cpp +++ b/Telegram/SourceFiles/data/data_chat.cpp @@ -333,9 +333,7 @@ void ApplyChatUpdate(not_null chat, const MTPDchatFull &update) { return QString(); })); if (const auto pinned = update.vpinned_msg_id()) { - chat->setTopPinnedMessageId(pinned->v); - } else { - chat->clearPinnedMessages(); + SetTopPinnedMessageId(chat, pinned->v); } chat->checkFolder(update.vfolder_id().value_or_empty()); chat->fullUpdated(); diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 25227cc24a..b9341eb760 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_file_origin.h" #include "data/data_histories.h" -#include "data/data_pinned_messages.h" #include "base/unixtime.h" #include "base/crc32hash.h" #include "lang/lang_keys.h" @@ -464,54 +463,13 @@ bool PeerData::canEditMessagesIndefinitely() const { Unexpected("Peer type in PeerData::canEditMessagesIndefinitely."); } -MsgId PeerData::topPinnedMessageId() const { - return _pinnedMessages ? _pinnedMessages->topId() : 0; +bool PeerData::hasPinnedMessages() const { + return _hasPinnedMessages; } -void PeerData::ensurePinnedMessagesCreated() { - if (!_pinnedMessages) { - _pinnedMessages = std::make_unique(this); - session().changes().peerUpdated(this, UpdateFlag::PinnedMessage); - } -} - -void PeerData::removeEmptyPinnedMessages() { - if (_pinnedMessages && _pinnedMessages->empty()) { - _pinnedMessages = nullptr; - session().changes().peerUpdated(this, UpdateFlag::PinnedMessage); - } -} - -bool PeerData::messageIdTooSmall(MsgId messageId) const { - if (const auto channel = asChannel()) { - return (messageId <= channel->availableMinId()); - } - return false; -} - -void PeerData::setTopPinnedMessageId(MsgId messageId) { - if (messageIdTooSmall(messageId)) { - clearPinnedMessages(); - return; - } - const auto hiddenId = session().settings().hiddenPinnedMessageId(id); - if (hiddenId != 0 && hiddenId != messageId) { - session().settings().setHiddenPinnedMessageId(id, 0); - session().saveSettingsDelayed(); - } - ensurePinnedMessagesCreated(); - _pinnedMessages->setTopId(messageId); -} - -void PeerData::clearPinnedMessages() { - if (session().settings().hiddenPinnedMessageId(id) != 0) { - session().settings().setHiddenPinnedMessageId(id, 0); - session().saveSettingsDelayed(); - } - session().storage().remove(Storage::SharedMediaRemoveAll( - id, - Storage::SharedMediaType::Pinned)); - removeEmptyPinnedMessages(); +void PeerData::setHasPinnedMessages(bool has) { + _hasPinnedMessages = has; + session().changes().peerUpdated(this, UpdateFlag::PinnedMessages); } bool PeerData::canExportChatHistory() const { @@ -1038,4 +996,36 @@ std::optional RestrictionError( return std::nullopt; } +void SetTopPinnedMessageId(not_null peer, MsgId messageId) { + if (const auto channel = peer->asChannel()) { + if (messageId <= channel->availableMinId()) { + return; + } + } + auto &session = peer->session(); + const auto hiddenId = session.settings().hiddenPinnedMessageId(peer->id); + if (hiddenId != 0 && hiddenId != messageId) { + session.settings().setHiddenPinnedMessageId(peer->id, 0); + session.saveSettingsDelayed(); + } + session.storage().add(Storage::SharedMediaAddExisting( + peer->id, + Storage::SharedMediaType::Pinned, + messageId, + { messageId, ServerMaxMsgId })); + peer->setHasPinnedMessages(true); +} + +MsgId ResolveTopPinnedId(not_null peer) { + const auto slice = peer->session().storage().snapshot( + Storage::SharedMediaQuery( + Storage::SharedMediaKey( + peer->id, + Storage::SharedMediaType::Pinned, + ServerMaxMsgId - 1), + 1, + 1)); + return slice.messageIds.empty() ? 0 : slice.messageIds.back(); +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index dbdf8d0941..4fa630510a 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -29,8 +29,6 @@ class Session; namespace Data { class Session; -class PinnedMessages; -struct PinnedAroundId; int PeerColorIndex(PeerId peerId); int PeerColorIndex(int32 bareId); @@ -328,12 +326,9 @@ public: [[nodiscard]] bool canPinMessages() const; [[nodiscard]] bool canEditMessagesIndefinitely() const; - [[nodiscard]] MsgId topPinnedMessageId() const; - void setTopPinnedMessageId(MsgId messageId); - void clearPinnedMessages(); - Data::PinnedMessages *currentPinnedMessages() const { - return _pinnedMessages.get(); - } + + [[nodiscard]] bool hasPinnedMessages() const; + void setHasPinnedMessages(bool has); [[nodiscard]] bool canExportChatHistory() const; @@ -412,10 +407,6 @@ private: -> const std::vector &; void setUserpicChecked(PhotoId photoId, const ImageLocation &location); - void ensurePinnedMessagesCreated(); - void removeEmptyPinnedMessages(); - - [[nodiscard]] bool messageIdTooSmall(MsgId messageId) const; static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL); @@ -433,7 +424,7 @@ private: base::flat_set _nameFirstLetters; crl::time _lastFullUpdate = 0; - std::unique_ptr _pinnedMessages; + bool _hasPinnedMessages = false; Settings _settings = { kSettingsUnknown }; BlockStatus _blockStatus = BlockStatus::Unknown; @@ -451,4 +442,7 @@ std::optional RestrictionError( not_null peer, ChatRestriction restriction); +void SetTopPinnedMessageId(not_null peer, MsgId messageId); +[[nodiscard]] MsgId ResolveTopPinnedId(not_null peer); + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_pinned_messages.cpp b/Telegram/SourceFiles/data/data_pinned_messages.cpp deleted file mode 100644 index 518be33ff8..0000000000 --- a/Telegram/SourceFiles/data/data_pinned_messages.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "data/data_pinned_messages.h" - -#include "data/data_peer.h" -#include "main/main_session.h" -#include "storage/storage_facade.h" -#include "storage/storage_shared_media.h" -#include "data/data_shared_media.h" -#include "data/data_sparse_ids.h" - -namespace Data { -namespace { - -constexpr auto PinnedType = Storage::SharedMediaType::Pinned; - -using Storage::SharedMediaQuery; -using Storage::SharedMediaKey; -using Storage::SharedMediaResult; - -} // namespace - -PinnedMessages::PinnedMessages(not_null peer) -: _peer(peer) -, _storage(_peer->session().storage()) { -} - -bool PinnedMessages::empty() const { - return _storage.empty(SharedMediaKey(_peer->id, PinnedType, 0)); -} - -MsgId PinnedMessages::topId() const { - const auto slice = _storage.snapshot( - SharedMediaQuery( - SharedMediaKey(_peer->id, PinnedType, ServerMaxMsgId), - 1, - 1)); - return slice.messageIds.empty() ? 0 : slice.messageIds.back(); -} - -rpl::producer PinnedMessages::viewer( - MsgId aroundId, - int limit) const { - return SharedMediaViewer( - &_peer->session(), - SharedMediaKey(_peer->id, PinnedType, aroundId), - limit, - limit - ) | rpl::map([](const SparseIdsSlice &result) { - auto data = PinnedAroundId(); - data.fullCount = result.fullCount(); - data.skippedBefore = result.skippedBefore(); - data.skippedAfter = result.skippedAfter(); - const auto count = result.size(); - data.ids.reserve(count); - for (auto i = 0; i != count; ++i) { - data.ids.push_back(result[i]); - } - return data; - }); -} - -void PinnedMessages::setTopId(MsgId messageId) { - while (true) { - auto top = topId(); - if (top > messageId) { - _storage.remove(Storage::SharedMediaRemoveOne( - _peer->id, - PinnedType, - top)); - } else if (top == messageId) { - return; - } else { - break; - } - } - _storage.add(Storage::SharedMediaAddNew( - _peer->id, - PinnedType, - messageId)); -} - -} // namespace Data diff --git a/Telegram/SourceFiles/data/data_pinned_messages.h b/Telegram/SourceFiles/data/data_pinned_messages.h deleted file mode 100644 index 5edcd29ec9..0000000000 --- a/Telegram/SourceFiles/data/data_pinned_messages.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -#include "data/data_messages.h" -#include "base/weak_ptr.h" - -namespace Storage { -class Facade; -} // namespace Storage - -namespace Data { - -struct PinnedAroundId { - std::vector ids; - std::optional skippedBefore; - std::optional skippedAfter; - std::optional fullCount; -}; - -class PinnedMessages final : public base::has_weak_ptr { -public: - explicit PinnedMessages(not_null peer); - - [[nodiscard]] bool empty() const; - [[nodiscard]] MsgId topId() const; - [[nodiscard]] rpl::producer viewer( - MsgId aroundId, - int limit) const; - void setTopId(MsgId messageId); - -private: - const not_null _peer; - Storage::Facade &_storage; - -}; - -} // namespace Data diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 099da8df16..5a865fde1b 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -262,9 +262,7 @@ void ApplyUserUpdate(not_null user, const MTPDuserFull &update) { user->setBotInfoVersion(-1); } if (const auto pinned = update.vpinned_msg_id()) { - user->setTopPinnedMessageId(pinned->v); - } else { - user->clearPinnedMessages(); + SetTopPinnedMessageId(user, pinned->v); } user->setFullFlags(update.vflags().v); user->setIsBlocked(update.is_blocked()); diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 1459ce95f6..e2828b48f5 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -705,6 +705,9 @@ not_null History::addNewToBack( sharedMediaTypes, item->id, { from, till })); + if (sharedMediaTypes.test(Storage::SharedMediaType::Pinned)) { + peer->setHasPinnedMessages(true); + } } } if (item->from()->id) { @@ -1008,6 +1011,7 @@ void History::applyServiceChanges( Storage::SharedMediaType::Pinned, { id }, { id, ServerMaxMsgId })); + peer->setHasPinnedMessages(true); } }); } @@ -1348,6 +1352,9 @@ void History::addToSharedMedia( type, std::move(medias[i]), { from, till })); + if (type == Storage::SharedMediaType::Pinned) { + peer->setHasPinnedMessages(true); + } } } } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 71d4acb53f..7bb00c86e3 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -355,6 +355,7 @@ void HistoryItem::setIsPinned(bool pinned) { Storage::SharedMediaType::Pinned, id, { id, id })); + history()->peer->setHasPinnedMessages(true); } else { _flags &= ~MTPDmessage::Flag::f_pinned; history()->session().storage().remove(Storage::SharedMediaRemoveOne( @@ -489,12 +490,12 @@ void HistoryItem::indexAsNewItem() { addToUnreadMentions(UnreadMentionType::New); if (const auto types = sharedMediaTypes()) { _history->session().storage().add(Storage::SharedMediaAddNew( - history()->peer->id, + _history->peer->id, types, id)); - } - if (isPinned()) { - _history->peer->setTopPinnedMessageId(id); + if (types.test(Storage::SharedMediaType::Pinned)) { + _history->peer->setHasPinnedMessages(true); + } } //if (const auto channel = history()->peer->asChannel()) { // #feed // if (const auto feed = channel->feed()) { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index c066a84c9c..2a3bbe9182 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -567,7 +567,7 @@ HistoryWidget::HistoryWidget( | UpdateFlag::ChannelLinkedChat | UpdateFlag::Slowmode | UpdateFlag::BotStartToken - | UpdateFlag::PinnedMessage + | UpdateFlag::PinnedMessages ) | rpl::filter([=](const Data::PeerUpdate &update) { return (update.peer.get() == _peer); }) | rpl::map([](const Data::PeerUpdate &update) { @@ -608,7 +608,7 @@ HistoryWidget::HistoryWidget( | UpdateFlag::ChannelLinkedChat)) { handlePeerUpdate(); } - if (_pinnedTracker && (flags & UpdateFlag::PinnedMessage)) { + if (_pinnedTracker && (flags & UpdateFlag::PinnedMessages)) { checkPinnedBarState(); } }, lifetime()); @@ -5184,7 +5184,7 @@ void HistoryWidget::updatePinnedViewer() { }(); const auto lessThanId = item ? (item->data()->id + (offset > 0 ? 1 : 0)) - : (_history->peer->topPinnedMessageId() + 1); + : (ServerMaxMsgId - 1); _pinnedTracker->trackAround(lessThanId); } @@ -5193,13 +5193,7 @@ void HistoryWidget::setupPinnedTracker() { _pinnedTracker = std::make_unique(_history); _pinnedBar = nullptr; - Info::Profile::SharedMediaCountValue( - _history->peer, - _migrated ? _migrated->peer.get() : nullptr, - Storage::SharedMediaType::Pinned - ) | rpl::start_with_next([=] { - checkPinnedBarState(); - }, _pinnedTracker->lifetime()); + checkPinnedBarState(); } void HistoryWidget::checkPinnedBarState() { @@ -5208,7 +5202,7 @@ void HistoryWidget::checkPinnedBarState() { const auto hiddenId = _peer->canPinMessages() ? MsgId(0) : session().settings().hiddenPinnedMessageId(_peer->id); - const auto currentPinnedId = _peer->topPinnedMessageId(); + const auto currentPinnedId = Data::ResolveTopPinnedId(_peer); if (currentPinnedId == hiddenId) { if (_pinnedBar) { _pinnedTracker->reset(); @@ -5601,7 +5595,7 @@ void HistoryWidget::hidePinnedMessage() { if (_peer->canPinMessages()) { unpinMessage({ peerToChannel(_peer->id), id.message }); } else { - const auto top = _peer->topPinnedMessageId(); + const auto top = Data::ResolveTopPinnedId(_peer); if (top) { session().settings().setHiddenPinnedMessageId(_peer->id, top); session().saveSettingsDelayed(); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 92f63e34cb..b049bc262e 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_user.h" #include "data/data_channel.h" -#include "data/data_pinned_messages.h" #include "data/data_changes.h" #include "data/data_sparse_ids.h" #include "data/data_shared_media.h" diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp index f2aee74192..f8c9c6d31b 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp @@ -8,9 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_pinned_tracker.h" #include "data/data_changes.h" -#include "data/data_pinned_messages.h" #include "data/data_peer.h" #include "data/data_channel.h" +#include "data/data_shared_media.h" #include "data/data_session.h" #include "main/main_session.h" #include "storage/storage_facade.h" @@ -21,16 +21,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace{ -constexpr auto kLoadedLimit = 4; +constexpr auto kLoadedLimit = 5; +constexpr auto kChangeViewerLimit = 2; } // namespace PinnedTracker::PinnedTracker(not_null history) : _history(history) { _history->session().changes().peerFlagsValue( _history->peer, - Data::PeerUpdate::Flag::PinnedMessage - ) | rpl::start_with_next([=] { - refreshData(); + Data::PeerUpdate::Flag::PinnedMessages + ) | rpl::map([=] { + return _history->peer->hasPinnedMessages(); + }) | rpl::distinct_until_changed( + ) | rpl::start_with_next([=](bool has) { + if (has) { + refreshViewer(); + } else { + clear(); + } }, _lifetime); } @@ -48,60 +56,85 @@ PinnedId PinnedTracker::currentMessageId() const { return _current.current(); } -void PinnedTracker::refreshData() { - const auto now = _history->peer->currentPinnedMessages(); - if (!now) { - _dataLifetime.destroy(); - _current = PinnedId(); - } else if (_data.get() != now) { - _dataLifetime.destroy(); - _data = now; - if (_aroundId) { - setupViewer(now); +void PinnedTracker::refreshViewer() { + if (_viewerAroundId == _aroundId) { + return; + } + _dataLifetime.destroy(); + _viewerAroundId = _aroundId; + SharedMediaViewer( + &_history->peer->session(), + Storage::SharedMediaKey( + _history->peer->id, + Storage::SharedMediaType::Pinned, + _viewerAroundId), + kLoadedLimit, + kLoadedLimit + ) | rpl::start_with_next([=](const SparseIdsSlice &result) { + _slice.fullCount = result.fullCount(); + _slice.skippedBefore = result.skippedBefore(); + _slice.skippedAfter = result.skippedAfter(); + _slice.ids.clear(); + const auto count = result.size(); + _slice.ids.reserve(count); + for (auto i = 0; i != count; ++i) { + _slice.ids.push_back(result[i]); + } + refreshCurrentFromSlice(); + if (_slice.fullCount == 0) { + _history->peer->setHasPinnedMessages(false); + } + }, _dataLifetime); +} + +void PinnedTracker::refreshCurrentFromSlice() { + const auto i = ranges::lower_bound(_slice.ids, _aroundId); + const auto empty = _slice.ids.empty(); + const auto before = int(i - begin(_slice.ids)); + const auto after = int(end(_slice.ids) - i); + const auto haveValidData = (before > 0 || _slice.skippedBefore == 0) + && (after > 0 || _slice.skippedAfter == 0); + const auto nearEnd = !haveValidData + || (before <= kChangeViewerLimit && _slice.skippedBefore != 0) + || (after <= kChangeViewerLimit && _slice.skippedAfter != 0); + if (haveValidData) { + const auto count = std::max( + _slice.fullCount.value_or(1), + int(_slice.ids.size())); + const auto index = _slice.skippedBefore.has_value() + ? (*_slice.skippedBefore + before) + : _slice.skippedAfter.has_value() + ? (count - *_slice.skippedAfter - after) + : 1; + if (i != begin(_slice.ids)) { + _current = PinnedId{ *(i - 1), index - 1, count }; + } else if (!_slice.ids.empty()) { + _current = PinnedId{ _slice.ids.front(), 0, count }; + } else { + _current = PinnedId(); } } + if (nearEnd) { + refreshViewer(); + } +} + +void PinnedTracker::clear() { + _dataLifetime.destroy(); + _viewerAroundId = 0; + _current = PinnedId(); } void PinnedTracker::trackAround(MsgId messageId) { if (_aroundId == messageId) { return; } - _dataLifetime.destroy(); _aroundId = messageId; if (!_aroundId) { - _current = PinnedId(); - } else if (const auto now = _data.get()) { - setupViewer(now); + clear(); + } else { + refreshCurrentFromSlice(); } } -void PinnedTracker::setupViewer(not_null data) { - data->viewer( - _aroundId, - kLoadedLimit + 2 - ) | rpl::start_with_next([=](const Data::PinnedAroundId &snapshot) { - const auto i = ranges::lower_bound(snapshot.ids, _aroundId); - const auto empty = snapshot.ids.empty(); - const auto before = int(i - begin(snapshot.ids)); - const auto after = int(end(snapshot.ids) - i); - if (snapshot.ids.empty()) { - _current = PinnedId(); - return; - } - const auto count = std::max( - snapshot.fullCount.value_or(1), - int(snapshot.ids.size())); - const auto index = snapshot.skippedBefore.has_value() - ? (*snapshot.skippedBefore + before) - : snapshot.skippedAfter.has_value() - ? (count - *snapshot.skippedAfter - after) - : 1; - if (i != begin(snapshot.ids)) { - _current = PinnedId{ *(i - 1), index - 1, count }; - } else if (snapshot.skippedBefore == 0) { - _current = PinnedId{ snapshot.ids.front(), 0, count }; - } - }, _dataLifetime); -} - } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h index 21f18bb4e0..9335c48519 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h @@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class History; namespace Data { -class PinnedMessages; enum class LoadDirection : char; } // namespace Data @@ -46,16 +45,24 @@ public: } private: - void refreshData(); - void setupViewer(not_null data); + struct Slice { + std::vector ids; + std::optional fullCount; + std::optional skippedBefore; + std::optional skippedAfter; + }; + void clear(); + void refreshViewer(); + void refreshCurrentFromSlice(); const not_null _history; - base::weak_ptr _data; rpl::variable _current; rpl::lifetime _dataLifetime; MsgId _aroundId = 0; + MsgId _viewerAroundId = 0; + Slice _slice; rpl::lifetime _lifetime;