diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 11a7e3dedb..222644dc33 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2913,24 +2913,26 @@ void ApiWrap::resolveJumpToHistoryDate( } } -void ApiWrap::requestSharedMediaCount( - not_null peer, - Storage::SharedMediaType type) { - requestSharedMedia(peer, type, 0, SliceType::Before); -} - void ApiWrap::requestSharedMedia( not_null peer, + MsgId topicRootId, SharedMediaType type, MsgId messageId, SliceType slice) { - const auto key = std::make_tuple(peer, type, messageId, slice); + const auto key = SharedMediaRequest{ + peer, + topicRootId, + type, + messageId, + slice, + }; if (_sharedMediaRequests.contains(key)) { return; } const auto prepared = Api::PrepareSearchRequest( peer, + topicRootId, type, QString(), messageId, @@ -2946,7 +2948,6 @@ void ApiWrap::requestSharedMedia( return request( std::move(*prepared) ).done([=](const Api::SearchRequestResult &result) { - const auto key = std::make_tuple(peer, type, messageId, slice); _sharedMediaRequests.remove(key); auto parsed = Api::ParseSearchResult( peer, @@ -2954,7 +2955,7 @@ void ApiWrap::requestSharedMedia( messageId, slice, result); - sharedMediaDone(peer, type, std::move(parsed)); + sharedMediaDone(peer, topicRootId, type, std::move(parsed)); finish(); }).fail([=] { _sharedMediaRequests.remove(key); @@ -2966,10 +2967,12 @@ void ApiWrap::requestSharedMedia( void ApiWrap::sharedMediaDone( not_null peer, + MsgId topicRootId, SharedMediaType type, Api::SearchResult &&parsed) { _session->storage().add(Storage::SharedMediaAddSlice( peer->id, + topicRootId, type, std::move(parsed.messageIds), parsed.noSkipRange, diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index d54a83d189..481f36d5e4 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -265,12 +265,10 @@ public: using SliceType = Data::LoadDirection; void requestSharedMedia( not_null peer, + MsgId topicRootId, Storage::SharedMediaType type, MsgId messageId, SliceType slice); - void requestSharedMediaCount( - not_null peer, - Storage::SharedMediaType type); void readFeaturedSetDelayed(uint64 setId); @@ -465,6 +463,7 @@ private: void sharedMediaDone( not_null peer, + MsgId topicRootId, SharedMediaType type, Api::SearchResult &&parsed); @@ -579,11 +578,18 @@ private: mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0; - base::flat_set, - SharedMediaType, - MsgId, - SliceType>> _sharedMediaRequests; + struct SharedMediaRequest { + not_null peer; + MsgId topicRootId = 0; + SharedMediaType mediaType = {}; + MsgId aroundId = 0; + SliceType sliceType = {}; + + friend inline constexpr auto operator<=>( + const SharedMediaRequest&, + const SharedMediaRequest&) = default; + }; + base::flat_set _sharedMediaRequests; std::unique_ptr _dialogsLoadState; TimeId _dialogsLoadTill = 0; diff --git a/Telegram/SourceFiles/boxes/pin_messages_box.cpp b/Telegram/SourceFiles/boxes/pin_messages_box.cpp index a2fdf4cbd0..3471ef226d 100644 --- a/Telegram/SourceFiles/boxes/pin_messages_box.cpp +++ b/Telegram/SourceFiles/boxes/pin_messages_box.cpp @@ -19,10 +19,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { -[[nodiscard]] bool IsOldForPin(MsgId id, not_null peer) { +[[nodiscard]] bool IsOldForPin( + MsgId id, + not_null peer, + MsgId topicRootId) { const auto normal = peer->migrateToOrMe(); const auto migrated = normal->migrateFrom(); - const auto top = Data::ResolveTopPinnedId(normal, migrated); + const auto top = Data::ResolveTopPinnedId(normal, topicRootId, migrated); if (!top) { return false; } else if (peer == migrated) { @@ -46,7 +49,7 @@ void PinMessageBox( mtpRequestId requestId = 0; }; - const auto pinningOld = IsOldForPin(msgId, peer); + const auto pinningOld = IsOldForPin(msgId, peer, MsgId(0)); const auto state = box->lifetime().make_state(); const auto api = box->lifetime().make_state( &peer->session().mtp()); diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 1109cfad83..14a6dc55c0 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -538,6 +538,7 @@ bool OpenMediaTimestamp( controller, document, session->data().message(itemId), + MsgId(0), // #TODO forum shared media false, timeMs)); } else if (document->isSong() || document->isVoiceMessage()) { diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 8234c8fbbf..c07ec37220 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -942,7 +942,7 @@ void ApplyChannelUpdate( } } if (const auto pinned = update.vpinned_msg_id()) { - SetTopPinnedMessageId(channel, pinned->v); + SetTopPinnedMessageId(channel, MsgId(0), pinned->v); } if (channel->isMegagroup()) { auto commands = ranges::views::all( diff --git a/Telegram/SourceFiles/data/data_chat.cpp b/Telegram/SourceFiles/data/data_chat.cpp index 57512feb82..bd23f8ce45 100644 --- a/Telegram/SourceFiles/data/data_chat.cpp +++ b/Telegram/SourceFiles/data/data_chat.cpp @@ -474,7 +474,7 @@ void ApplyChatUpdate(not_null chat, const MTPDchatFull &update) { chat->session().api().inviteLinks().clearMyPermanent(chat); } if (const auto pinned = update.vpinned_msg_id()) { - SetTopPinnedMessageId(chat, pinned->v); + SetTopPinnedMessageId(chat, MsgId(0), pinned->v); } chat->checkFolder(update.vfolder_id().value_or_empty()); chat->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty())); diff --git a/Telegram/SourceFiles/data/data_document_resolver.cpp b/Telegram/SourceFiles/data/data_document_resolver.cpp index a4469e44c1..70871d5b90 100644 --- a/Telegram/SourceFiles/data/data_document_resolver.cpp +++ b/Telegram/SourceFiles/data/data_document_resolver.cpp @@ -234,7 +234,8 @@ base::binary_guard ReadBackgroundImageAsync( void ResolveDocument( Window::SessionController *controller, not_null document, - HistoryItem *item) { + HistoryItem *item, + MsgId topicRootId) { if (document->isNull()) { return; } @@ -246,7 +247,7 @@ void ResolveDocument( && !document->filepath().isEmpty()) { File::Launch(document->location(false).fname); } else if (controller) { - controller->openDocument(document, msgId, true); + controller->openDocument(document, msgId, topicRootId, true); } }; diff --git a/Telegram/SourceFiles/data/data_document_resolver.h b/Telegram/SourceFiles/data/data_document_resolver.h index 5dd29c0baf..65a76bf192 100644 --- a/Telegram/SourceFiles/data/data_document_resolver.h +++ b/Telegram/SourceFiles/data/data_document_resolver.h @@ -32,6 +32,7 @@ base::binary_guard ReadBackgroundImageAsync( void ResolveDocument( Window::SessionController *controller, not_null document, - HistoryItem *item); + HistoryItem *item, + MsgId topicRootId); } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 549f6beafb..b1674700b1 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -1203,7 +1203,10 @@ std::optional RestrictionError( return std::nullopt; } -void SetTopPinnedMessageId(not_null peer, MsgId messageId) { +void SetTopPinnedMessageId( + not_null peer, + MsgId topicRootId, + MsgId messageId) { if (const auto channel = peer->asChannel()) { if (messageId <= channel->availableMinId()) { return; @@ -1217,6 +1220,7 @@ void SetTopPinnedMessageId(not_null peer, MsgId messageId) { } session.storage().add(Storage::SharedMediaAddExisting( peer->id, + topicRootId, Storage::SharedMediaType::Pinned, messageId, { messageId, ServerMaxMsgId })); @@ -1225,20 +1229,23 @@ void SetTopPinnedMessageId(not_null peer, MsgId messageId) { FullMsgId ResolveTopPinnedId( not_null peer, + MsgId topicRootId, PeerData *migrated) { const auto slice = peer->session().storage().snapshot( Storage::SharedMediaQuery( Storage::SharedMediaKey( peer->id, + topicRootId, Storage::SharedMediaType::Pinned, ServerMaxMsgId - 1), 1, 1)); - const auto old = migrated + const auto old = (!topicRootId && migrated) ? migrated->session().storage().snapshot( Storage::SharedMediaQuery( Storage::SharedMediaKey( migrated->id, + MsgId(0), // topicRootId Storage::SharedMediaType::Pinned, ServerMaxMsgId - 1), 1, @@ -1259,20 +1266,23 @@ FullMsgId ResolveTopPinnedId( FullMsgId ResolveMinPinnedId( not_null peer, + MsgId topicRootId, PeerData *migrated) { const auto slice = peer->session().storage().snapshot( Storage::SharedMediaQuery( Storage::SharedMediaKey( peer->id, + topicRootId, Storage::SharedMediaType::Pinned, 1), 1, 1)); - const auto old = migrated + const auto old = (!topicRootId && migrated) ? migrated->session().storage().snapshot( Storage::SharedMediaQuery( Storage::SharedMediaKey( migrated->id, + MsgId(0), // topicRootId Storage::SharedMediaType::Pinned, 1), 1, @@ -1291,34 +1301,4 @@ FullMsgId ResolveMinPinnedId( } } -std::optional ResolvePinnedCount( - not_null peer, - PeerData *migrated) { - const auto slice = peer->session().storage().snapshot( - Storage::SharedMediaQuery( - Storage::SharedMediaKey( - peer->id, - Storage::SharedMediaType::Pinned, - 0), - 0, - 0)); - const auto old = migrated - ? migrated->session().storage().snapshot( - Storage::SharedMediaQuery( - Storage::SharedMediaKey( - migrated->id, - Storage::SharedMediaType::Pinned, - 0), - 0, - 0)) - : Storage::SharedMediaResult{ - .count = 0, - .skippedBefore = 0, - .skippedAfter = 0, - }; - return (slice.count.has_value() && old.count.has_value()) - ? std::make_optional(*slice.count + *old.count) - : std::nullopt; -} - } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index e6a8cdeaaa..f480095fea 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -495,15 +495,17 @@ std::optional RestrictionError( not_null peer, UserRestriction restriction); -void SetTopPinnedMessageId(not_null peer, MsgId messageId); +void SetTopPinnedMessageId( + not_null peer, + MsgId topicRootId, + MsgId messageId); [[nodiscard]] FullMsgId ResolveTopPinnedId( not_null peer, + MsgId topicRootId, PeerData *migrated); [[nodiscard]] FullMsgId ResolveMinPinnedId( not_null peer, - PeerData *migrated); -[[nodiscard]] std::optional ResolvePinnedCount( - not_null peer, + MsgId topicRootId, PeerData *migrated); } // namespace Data diff --git a/Telegram/SourceFiles/data/data_scheduled_messages.cpp b/Telegram/SourceFiles/data/data_scheduled_messages.cpp index 48cfa926ca..c6231a6951 100644 --- a/Telegram/SourceFiles/data/data_scheduled_messages.cpp +++ b/Telegram/SourceFiles/data/data_scheduled_messages.cpp @@ -30,8 +30,7 @@ constexpr auto kRequestTimeLimit = 60 * crl::time(1000); } [[nodiscard]] MsgId LocalToRemoteMsgId(MsgId id) { - Expects(id > ServerMaxMsgId); - Expects(id < ServerMaxMsgId + ScheduledMsgIdsRange); + Expects(IsScheduledMsgId(id)); return (id - ServerMaxMsgId - 1); } diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 6dc598e497..893188b9c9 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -27,6 +27,7 @@ constexpr auto kDefaultSearchTimeoutMs = crl::time(200); std::optional PrepareSearchRequest( not_null peer, + MsgId topicRootId, Storage::SharedMediaType type, const QString &query, MsgId messageId, @@ -90,12 +91,13 @@ std::optional PrepareSearchRequest( offsetId.bare, int64(0), int64(0x3FFFFFFF))); + using Flag = MTPmessages_Search::Flag; return MTPmessages_Search( - MTP_flags(0), + MTP_flags(topicRootId ? Flag::f_top_msg_id : Flag(0)), peer->input, MTP_string(query), MTP_inputPeerEmpty(), - MTPint(), // top_msg_id + MTP_int(topicRootId), filter, MTP_int(0), // min_date MTP_int(0), // max_date @@ -234,11 +236,13 @@ rpl::producer SearchController::idsSlice( auto query = (const Query&)_current->first; auto createSimpleViewer = [=]( PeerId peerId, + MsgId topicRootId, SparseIdsSlice::Key simpleKey, int limitBefore, int limitAfter) { return simpleIdsSlice( peerId, + topicRootId, simpleKey, query, limitBefore, @@ -247,6 +251,7 @@ rpl::producer SearchController::idsSlice( return SparseIdsMergedSlice::CreateViewer( SparseIdsMergedSlice::Key( query.peerId, + query.topicRootId, query.migratedPeerId, aroundId), limitBefore, @@ -256,6 +261,7 @@ rpl::producer SearchController::idsSlice( rpl::producer SearchController::simpleIdsSlice( PeerId peerId, + MsgId topicRootId, MsgId aroundId, const Query &query, int limitBefore, @@ -264,8 +270,8 @@ rpl::producer SearchController::simpleIdsSlice( Expects(IsServerMsgId(aroundId) || (aroundId == 0)); Expects((aroundId != 0) || (limitBefore == 0 && limitAfter == 0)); - Expects((query.peerId == peerId) - || (query.migratedPeerId == peerId)); + Expects((query.peerId == peerId && query.topicRootId == topicRootId) + || (query.migratedPeerId == peerId && MsgId(0) == topicRootId)); auto it = _cache.find(query); if (it == _cache.end()) { @@ -298,7 +304,8 @@ rpl::producer SearchController::simpleIdsSlice( _session->data().itemRemoved( ) | rpl::filter([=](not_null item) { - return (item->history()->peer->id == peerId); + return (item->history()->peer->id == peerId) + && (!topicRootId || item->topicRootId() == topicRootId); }) | rpl::filter([=](not_null item) { return builder->removeOne(item->id); }) | rpl::start_with_next(pushNextSnapshot, lifetime); @@ -370,6 +377,7 @@ void SearchController::requestMore( } auto prepared = PrepareSearchRequest( listData->peer, + query.topicRootId, query.type, query.query, key.aroundId, diff --git a/Telegram/SourceFiles/data/data_search_controller.h b/Telegram/SourceFiles/data/data_search_controller.h index cd937cf317..a938df6ef6 100644 --- a/Telegram/SourceFiles/data/data_search_controller.h +++ b/Telegram/SourceFiles/data/data_search_controller.h @@ -34,6 +34,7 @@ using SearchRequestResult = MTPmessages_Messages; std::optional PrepareSearchRequest( not_null peer, + MsgId topicRootId, Storage::SharedMediaType type, const QString &query, MsgId messageId, @@ -53,6 +54,7 @@ public: using MediaType = Storage::SharedMediaType; PeerId peerId = 0; + MsgId topicRootId = 0; PeerId migratedPeerId = 0; MediaType type = MediaType::kCount; QString query; @@ -75,6 +77,7 @@ public: Query query() const { Expects(_current != _cache.cend()); + return _current->first; } @@ -106,18 +109,11 @@ private: std::optional migratedData; }; - struct CacheLess { - inline bool operator()(const Query &a, const Query &b) const { - return (a < b); - } - }; - using Cache = base::flat_map< - Query, - std::unique_ptr, - CacheLess>; + using Cache = base::flat_map>; rpl::producer simpleIdsSlice( PeerId peerId, + MsgId topicRootId, MsgId aroundId, const Query &query, int limitBefore, diff --git a/Telegram/SourceFiles/data/data_shared_media.cpp b/Telegram/SourceFiles/data/data_shared_media.cpp index e715250df8..4d32427e89 100644 --- a/Telegram/SourceFiles/data/data_shared_media.cpp +++ b/Telegram/SourceFiles/data/data_shared_media.cpp @@ -109,10 +109,12 @@ rpl::producer SharedMediaViewer( limitAfter); auto requestMediaAround = [ peer = session->data().peer(key.peerId), + topicRootId = key.topicRootId, type = key.type ](const SparseIdsSliceBuilder::AroundData &data) { peer->session().api().requestSharedMedia( peer, + topicRootId, type, data.aroundId, data.direction); @@ -128,6 +130,7 @@ rpl::producer SharedMediaViewer( session->storage().sharedMediaSliceUpdated( ) | rpl::filter([=](const SliceUpdate &update) { return (update.peerId == key.peerId) + && (update.topicRootId == key.topicRootId) && (update.type == key.type); }) | rpl::filter([=](const SliceUpdate &update) { return builder->applyUpdate(update.data); @@ -146,7 +149,7 @@ rpl::producer SharedMediaViewer( session->storage().sharedMediaAllRemoved( ) | rpl::filter([=](const AllRemoved &update) { return (update.peerId == key.peerId) - && (update.types.test(key.type)); + && update.types.test(key.type); }) | rpl::filter([=] { return builder->removeAll(); }) | rpl::start_with_next(pushNextSnapshot, lifetime); @@ -229,6 +232,7 @@ rpl::producer SharedMediaMergedViewer( int limitAfter) { auto createSimpleViewer = [=]( PeerId peerId, + MsgId topicRootId, SparseIdsSlice::Key simpleKey, int limitBefore, int limitAfter) { @@ -236,6 +240,7 @@ rpl::producer SharedMediaMergedViewer( session, Storage::SharedMediaKey( peerId, + topicRootId, key.type, simpleKey), limitBefore, @@ -462,7 +467,7 @@ rpl::producer SharedMediaWithLastViewer( }); } - if (key.scheduled) { + if (key.topicRootId == SharedMediaWithLastSlice::kScheduledTopicId) { return SharedScheduledMediaViewer( session, std::move(viewerKey), diff --git a/Telegram/SourceFiles/data/data_shared_media.h b/Telegram/SourceFiles/data/data_shared_media.h index f24c35693d..2cedd8d3d7 100644 --- a/Telegram/SourceFiles/data/data_shared_media.h +++ b/Telegram/SourceFiles/data/data_shared_media.h @@ -67,36 +67,32 @@ public: MessageId, not_null>; + static constexpr auto kScheduledTopicId + = SparseIdsMergedSlice::kScheduledTopicId; struct Key { Key( PeerId peerId, + MsgId topicRootId, PeerId migratedPeerId, Type type, - UniversalMsgId universalId, - bool scheduled = false) + UniversalMsgId universalId) : peerId(peerId) + , topicRootId(topicRootId) , migratedPeerId(migratedPeerId) , type(type) - , universalId(universalId) - , scheduled(scheduled) { + , universalId(universalId) { Expects(v::is(universalId) || type == Type::ChatPhoto); } - bool operator==(const Key &other) const { - return (peerId == other.peerId) - && (migratedPeerId == other.migratedPeerId) - && (type == other.type) - && (universalId == other.universalId); - } - bool operator!=(const Key &other) const { - return !(*this == other); - } + friend inline constexpr auto operator<=>( + const Key&, + const Key&) = default; PeerId peerId = 0; + MsgId topicRootId = 0; PeerId migratedPeerId = 0; Type type = Type::kCount; UniversalMsgId universalId; - bool scheduled = false; }; @@ -122,6 +118,7 @@ public: static SparseIdsMergedSlice::Key ViewerKey(const Key &key) { return { key.peerId, + key.topicRootId, key.migratedPeerId, v::is(key.universalId) ? v::get(key.universalId) @@ -131,6 +128,7 @@ public: static SparseIdsMergedSlice::Key EndingKey(const Key &key) { return { key.peerId, + key.topicRootId, key.migratedPeerId, ServerMaxMsgId - 1 }; diff --git a/Telegram/SourceFiles/data/data_sparse_ids.cpp b/Telegram/SourceFiles/data/data_sparse_ids.cpp index 0605db8c1b..b48881ca3a 100644 --- a/Telegram/SourceFiles/data/data_sparse_ids.cpp +++ b/Telegram/SourceFiles/data/data_sparse_ids.cpp @@ -377,6 +377,7 @@ rpl::producer SparseIdsMergedSlice::CreateViewer( int limitBefore, int limitAfter, Fn simpleViewer) { + Expects(!key.topicRootId || !key.migratedPeerId); Expects(IsServerMsgId(key.universalId) || (key.universalId == 0) || (IsServerMsgId(ServerMaxMsgId + key.universalId) && key.migratedPeerId != 0)); @@ -386,6 +387,7 @@ rpl::producer SparseIdsMergedSlice::CreateViewer( return [=](auto consumer) { auto partViewer = simpleViewer( key.peerId, + key.topicRootId, SparseIdsMergedSlice::PartKey(key), limitBefore, limitAfter @@ -402,6 +404,7 @@ rpl::producer SparseIdsMergedSlice::CreateViewer( } auto migratedViewer = simpleViewer( key.migratedPeerId, + MsgId(0), // topicRootId SparseIdsMergedSlice::MigratedKey(key), limitBefore, limitAfter); diff --git a/Telegram/SourceFiles/data/data_sparse_ids.h b/Telegram/SourceFiles/data/data_sparse_ids.h index a3f03e98da..8d5489d70f 100644 --- a/Telegram/SourceFiles/data/data_sparse_ids.h +++ b/Telegram/SourceFiles/data/data_sparse_ids.h @@ -27,32 +27,29 @@ using SparseUnsortedIdsSlice = AbstractSparseIds>; class SparseIdsMergedSlice { public: using UniversalMsgId = MsgId; + static constexpr MsgId kScheduledTopicId + = ServerMaxMsgId + ScheduledMsgIdsRange; + struct Key { Key( PeerId peerId, + MsgId topicRootId, PeerId migratedPeerId, - UniversalMsgId universalId, - bool scheduled = false) + UniversalMsgId universalId) : peerId(peerId) - , scheduled(scheduled) - , migratedPeerId(scheduled ? 0 : migratedPeerId) + , topicRootId(topicRootId) + , migratedPeerId(topicRootId ? 0 : migratedPeerId) , universalId(universalId) { } - bool operator==(const Key &other) const { - return (peerId == other.peerId) - && (migratedPeerId == other.migratedPeerId) - && (universalId == other.universalId); - } - bool operator!=(const Key &other) const { - return !(*this == other); - } + friend inline constexpr bool operator==( + const Key &, + const Key &) = default; PeerId peerId = 0; - bool scheduled = false; + MsgId topicRootId = 0; PeerId migratedPeerId = 0; UniversalMsgId universalId = 0; - }; SparseIdsMergedSlice(Key key); @@ -75,6 +72,7 @@ public: using SimpleViewerFunction = rpl::producer( PeerId peerId, + MsgId topicRootId, SparseIdsSlice::Key simpleKey, int limitBefore, int limitAfter); diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 0a32223ca4..eb6d62e6ea 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -331,7 +331,7 @@ void ApplyUserUpdate(not_null user, const MTPDuserFull &update) { user->setBotInfoVersion(-1); } if (const auto pinned = update.vpinned_msg_id()) { - SetTopPinnedMessageId(user, pinned->v); + SetTopPinnedMessageId(user, MsgId(0), pinned->v); } const auto canReceiveGifts = (update.vflags().v & MTPDuserFull::Flag::f_premium_gifts) diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index 4fe72b8df2..48e0158442 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -624,14 +624,14 @@ void InnerWidget::elementShowPollResults( void InnerWidget::elementOpenPhoto( not_null photo, FullMsgId context) { - _controller->openPhoto(photo, context); + _controller->openPhoto(photo, context, MsgId(0)); } void InnerWidget::elementOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - _controller->openDocument(document, context, showInMediaView); + _controller->openDocument(document, context, MsgId(0), showInMediaView); } void InnerWidget::elementCancelUpload(const FullMsgId &context) { @@ -1378,7 +1378,7 @@ void InnerWidget::openContextGif(FullMsgId itemId) { if (const auto item = session().data().message(itemId)) { if (const auto media = item->media()) { if (const auto document = media->document()) { - _controller->openDocument(document, itemId, true); + _controller->openDocument(document, itemId, MsgId(), true); } } } diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index bde7d36cdc..b0ece2b777 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -778,6 +778,7 @@ not_null History::addNewToBack( auto till = loadedAtBottom() ? ServerMaxMsgId : maxMsgId(); session().storage().add(Storage::SharedMediaAddExisting( peer->id, + MsgId(0), sharedMediaTypes, item->id, { from, till })); @@ -1047,6 +1048,7 @@ void History::applyServiceChanges( if (item) { session().storage().add(Storage::SharedMediaAddSlice( peer->id, + MsgId(0), // topicRootId Storage::SharedMediaType::Pinned, { id }, { id, ServerMaxMsgId })); @@ -1268,6 +1270,7 @@ void History::addEdgesToSharedMedia() { const auto type = static_cast(i); session().storage().add(Storage::SharedMediaAddSlice( peer->id, + MsgId(0), // topicRootId type, {}, { from, till })); @@ -1460,6 +1463,7 @@ void History::addToSharedMedia( const auto type = static_cast(i); session().storage().add(Storage::SharedMediaAddSlice( peer->id, + MsgId(0), // topicRootId type, std::move(medias[i]), { from, till })); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index eb530da0d5..a0d3aeb08c 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2596,7 +2596,7 @@ void HistoryInner::openContextGif(FullMsgId itemId) { if (const auto item = session().data().message(itemId)) { if (const auto media = item->media()) { if (const auto document = media->document()) { - _controller->openDocument(document, itemId, true); + _controller->openDocument(document, itemId, MsgId(), true); } } } @@ -3248,14 +3248,14 @@ void HistoryInner::elementShowPollResults( void HistoryInner::elementOpenPhoto( not_null photo, FullMsgId context) { - _controller->openPhoto(photo, context); + _controller->openPhoto(photo, context, MsgId(0)); } void HistoryInner::elementOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - _controller->openDocument(document, context, showInMediaView); + _controller->openDocument(document, context, MsgId(0), showInMediaView); } void HistoryInner::elementCancelUpload(const FullMsgId &context) { diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 89afaf60fc..965619ad82 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -482,6 +482,7 @@ void HistoryItem::setIsPinned(bool pinned) { _flags |= MessageFlag::Pinned; history()->session().storage().add(Storage::SharedMediaAddExisting( history()->peer->id, + MsgId(0), // topicRootId Storage::SharedMediaType::Pinned, id, { id, id })); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b1ff16ec20..5f47c6f89c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1464,9 +1464,9 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) { if (result.open) { const auto request = result.result->openRequest(); if (const auto photo = request.photo()) { - controller()->openPhoto(photo, FullMsgId()); + controller()->openPhoto(photo, {}, {}); } else if (const auto document = request.document()) { - controller()->openDocument(document, FullMsgId()); + controller()->openDocument(document, {}, {}); } } else { sendInlineResult(result); @@ -6138,6 +6138,7 @@ void HistoryWidget::updatePinnedViewer() { if (_pinnedClickedId && !_minPinnedId) { _minPinnedId = Data::ResolveMinPinnedId( _peer, + MsgId(0), // topicRootId _migrated ? _migrated->peer.get() : nullptr); } if (_pinnedClickedId && _minPinnedId && _minPinnedId >= _pinnedClickedId) { @@ -6183,6 +6184,7 @@ void HistoryWidget::checkPinnedBarState() { : session().settings().hiddenPinnedMessageId(_peer->id); const auto currentPinnedId = Data::ResolveTopPinnedId( _peer, + MsgId(0), // topicRootId _migrated ? _migrated->peer.get() : nullptr); const auto universalPinnedId = !currentPinnedId ? int32(0) @@ -6217,6 +6219,7 @@ void HistoryWidget::checkPinnedBarState() { }); auto pinnedRefreshed = Info::Profile::SharedMediaCountValue( _peer, + MsgId(0), // topicRootId nullptr, Storage::SharedMediaType::Pinned ) | rpl::distinct_until_changed( diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 246e03fc20..670fd2b25c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -2662,9 +2662,9 @@ void ComposeControls::applyInlineBotQuery( if (result.open) { const auto request = result.result->openRequest(); if (const auto photo = request.photo()) { - _window->openPhoto(photo, FullMsgId()); + _window->openPhoto(photo, {}, {}); } else if (const auto document = request.document()) { - _window->openDocument(document, FullMsgId()); + _window->openDocument(document, {}, {}); } } else { _inlineResultChosen.fire_copy(result); diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index c42c25f3d0..0a2c1af3c1 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -189,13 +189,12 @@ void SaveGif( } } -void OpenGif( - not_null controller, - FullMsgId itemId) { +void OpenGif(not_null list, FullMsgId itemId) { + const auto controller = list->controller(); if (const auto item = controller->session().data().message(itemId)) { if (const auto media = item->media()) { if (const auto document = media->document()) { - controller->openDocument(document, itemId, true); + list->elementOpenDocument(document, itemId, true); } } } @@ -261,8 +260,11 @@ void AddDocumentActions( item->history()->peer, document); if (notAutoplayedGif) { + const auto weak = Ui::MakeWeak(list.get()); menu->addAction(tr::lng_context_open_gif(tr::now), [=] { - OpenGif(list->controller(), contextId); + if (const auto strong = weak.data()) { + OpenGif(strong, contextId); + } }, &st::menuIconShowInChat); } if (!list->hasCopyRestriction(item)) { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index a46987b58a..cd984f3591 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -1549,14 +1549,14 @@ void ListWidget::elementShowPollResults( void ListWidget::elementOpenPhoto( not_null photo, FullMsgId context) { - _controller->openPhoto(photo, context); + _delegate->listOpenPhoto(photo, context); } void ListWidget::elementOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - _controller->openDocument(document, context, showInMediaView); + _delegate->listOpenDocument(document, context, showInMediaView); } void ListWidget::elementCancelUpload(const FullMsgId &context) { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 7935598b64..b07f586da9 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -125,6 +125,13 @@ public: virtual auto listAllowedReactionsValue() -> rpl::producer = 0; virtual void listShowPremiumToast(not_null document) = 0; + virtual void listOpenPhoto( + not_null photo, + FullMsgId context) = 0; + virtual void listOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView) = 0; }; struct SelectionData { diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index bb2740f701..2ede8215eb 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -453,28 +453,6 @@ void PinnedWidget::listDeleteRequest() { confirmDeleteSelected(); } -rpl::producer SharedMediaCountValue( - not_null peer, - PeerData *migrated, - Storage::SharedMediaType type) { - auto aroundId = 0; - auto limit = 0; - auto updated = SharedMediaMergedViewer( - &peer->session(), - SharedMediaMergedKey( - SparseIdsMergedSlice::Key( - peer->id, - migrated ? migrated->id : 0, - aroundId), - type), - limit, - limit - ) | rpl::map([](const SparseIdsMergedSlice &slice) { - return slice.fullCount(); - }) | rpl::filter_optional(); - return rpl::single(0) | rpl::then(std::move(updated)); -} - rpl::producer PinnedWidget::listSource( Data::MessagePosition aroundId, int limitBefore, @@ -488,6 +466,7 @@ rpl::producer PinnedWidget::listSource( SharedMediaMergedKey( SparseIdsMergedSlice::Key( _history->peer->id, + MsgId(0), // topicRootId _migratedPeer ? _migratedPeer->id : 0, messageId), Storage::SharedMediaType::Pinned), @@ -611,6 +590,19 @@ auto PinnedWidget::listAllowedReactionsValue() void PinnedWidget::listShowPremiumToast(not_null document) { } +void PinnedWidget::listOpenPhoto( + not_null photo, + FullMsgId context) { + controller()->openPhoto(photo, context, MsgId()); +} + +void PinnedWidget::listOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView) { + controller()->openDocument(document, context, MsgId(), showInMediaView); +} + void PinnedWidget::confirmDeleteSelected() { ConfirmDeleteSelectedItems(_inner); } diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index d17267f33e..be70e510a1 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -112,6 +112,13 @@ public: auto listAllowedReactionsValue() -> rpl::producer override; void listShowPremiumToast(not_null document) override; + void listOpenPhoto( + not_null photo, + FullMsgId context) override; + void listOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView) override; // CornerButtonsDelegate delegate. void cornerButtonsShowAtPosition( diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp index 1f9cbe7240..8f62964af2 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp @@ -82,6 +82,7 @@ void PinnedTracker::refreshViewer() { SharedMediaMergedKey( SparseIdsMergedSlice::Key( _history->peer->id, + MsgId(0), // topicRootId _migratedPeer ? _migratedPeer->id : 0, _viewerAroundId), Storage::SharedMediaType::Pinned), diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index b163f5dd43..33ca0eb3e7 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -233,7 +233,6 @@ RepliesWidget::RepliesWidget( setupRoot(); setupRootView(); - setupTopicViewer(); session().api().requestFullPeer(_history->peer); @@ -339,14 +338,17 @@ RepliesWidget::RepliesWidget( } }, lifetime()); - _history->session().changes().historyUpdates( - _history, - Data::HistoryUpdate::Flag::OutboxRead - ) | rpl::start_with_next([=] { - _inner->update(); - }, lifetime()); + if (!_topic) { + _history->session().changes().historyUpdates( + _history, + Data::HistoryUpdate::Flag::OutboxRead + ) | rpl::start_with_next([=] { + _inner->update(); + }, lifetime()); + } setupComposeControls(); + setupTopicViewer(); orderWidgets(); } @@ -890,6 +892,7 @@ void RepliesWidget::sendingFilesConfirmed( _composeControls->cancelReplyMessage(); refreshTopBarActiveChat(); } + finishSending(); } bool RepliesWidget::confirmSendingFiles( @@ -2059,6 +2062,19 @@ void RepliesWidget::listShowPremiumToast(not_null document) { _stickerToast->showFor(document); } +void RepliesWidget::listOpenPhoto( + not_null photo, + FullMsgId context) { + controller()->openPhoto(photo, context, _rootId); +} + +void RepliesWidget::listOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView) { + controller()->openDocument(document, context, _rootId, showInMediaView); +} + void RepliesWidget::confirmDeleteSelected() { ConfirmDeleteSelectedItems(_inner); } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index d7f18260ab..b6a20bff3b 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -150,6 +150,13 @@ public: auto listAllowedReactionsValue() ->rpl::producer override; void listShowPremiumToast(not_null document) override; + void listOpenPhoto( + not_null photo, + FullMsgId context) override; + void listOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView) override; // CornerButtonsDelegate delegate. void cornerButtonsShowAtPosition( diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 47f2985d4f..18c081c0d7 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -1267,6 +1267,19 @@ void ScheduledWidget::listShowPremiumToast( _stickerToast->showFor(document); } +void ScheduledWidget::listOpenPhoto( + not_null photo, + FullMsgId context) { + controller()->openPhoto(photo, context, MsgId()); +} + +void ScheduledWidget::listOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView) { + controller()->openDocument(document, context, MsgId(), showInMediaView); +} + void ScheduledWidget::confirmSendNowSelected() { ConfirmSendNowSelectedItems(_inner); } diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index 5c5ee6c715..c2767d6384 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -135,6 +135,13 @@ public: auto listAllowedReactionsValue() -> rpl::producer override; void listShowPremiumToast(not_null document) override; + void listOpenPhoto( + not_null photo, + FullMsgId context) override; + void listOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView) override; // CornerButtonsDelegate delegate. void cornerButtonsShowAtPosition( diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp index a72e042071..33212df256 100644 --- a/Telegram/SourceFiles/info/info_controller.cpp +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -100,15 +100,21 @@ rpl::producer AbstractController::mediaSource( return false; }(); - auto mediaViewer = isScheduled + const auto mediaViewer = isScheduled ? SharedScheduledMediaViewer : SharedMediaMergedViewer; + const auto topicId = isScheduled + ? SparseIdsMergedSlice::kScheduledTopicId + : topic() + ? topic()->rootId() + : MsgId(0); return mediaViewer( &session(), SharedMediaMergedKey( SparseIdsMergedSlice::Key( peer()->id, + topicId, migratedPeerId(), aroundId), section().mediaType()), @@ -363,6 +369,7 @@ rpl::producer Controller::mediaSource( SharedMediaMergedKey( SparseIdsMergedSlice::Key( query.peerId, + query.topicRootId, query.migratedPeerId, aroundId), query.type), diff --git a/Telegram/SourceFiles/info/info_controller.h b/Telegram/SourceFiles/info/info_controller.h index 2e62ce50e9..e1dae07940 100644 --- a/Telegram/SourceFiles/info/info_controller.h +++ b/Telegram/SourceFiles/info/info_controller.h @@ -129,6 +129,9 @@ public: PeerData *peer() const; PeerId migratedPeerId() const; + Data::ForumTopic *topic() const { + return key().topic(); + } UserData *settingsSelf() const { return key().settingsSelf(); } diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h index 4d69e0775e..cf4e7dedc3 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.h +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -83,12 +83,13 @@ inline auto AddButton( Ui::VerticalLayout *parent, not_null navigation, not_null peer, + MsgId topicRootId, PeerData *migrated, Type type, Ui::MultiSlideTracker &tracker) { auto result = AddCountedButton( parent, - Profile::SharedMediaCountValue(peer, migrated, type), + Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), MediaText(type), tracker)->entity(); result->addClickHandler([=] { diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index 63fcec862c..8c9e045c54 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/media/info_media_empty_widget.h" #include "info/profile/info_profile_icon.h" #include "info/info_controller.h" +#include "data/data_forum_topic.h" #include "ui/widgets/discrete_sliders.h" #include "ui/widgets/shadow.h" #include "ui/widgets/buttons.h" @@ -87,7 +88,11 @@ void InnerWidget::createTypeButtons() { st::infoProfileSkip)); auto tracker = Ui::MultiSlideTracker(); - auto addMediaButton = [&]( + const auto peer = _controller->key().peer(); + const auto topic = _controller->key().topic(); + const auto topicRootId = topic ? topic->rootId() : MsgId(); + const auto migrated = _controller->migrated(); + const auto addMediaButton = [&]( Type buttonType, const style::icon &icon) { if (buttonType == type()) { @@ -96,8 +101,9 @@ void InnerWidget::createTypeButtons() { auto result = AddButton( content, _controller, - _controller->key().peer(), - _controller->migrated(), + peer, + topicRootId, + migrated, buttonType, tracker); object_ptr( diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 67a8769ead..4053c11a3b 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_file_click_handler.h" #include "data/data_file_origin.h" #include "data/data_download_manager.h" +#include "data/data_forum_topic.h" #include "history/history_item.h" #include "history/history.h" #include "history/view/history_view_cursor_state.h" @@ -467,7 +468,7 @@ bool ListWidget::tooltipWindowActive() const { } void ListWidget::openPhoto(not_null photo, FullMsgId id) { - _controller->parentController()->openPhoto(photo, id); + _controller->parentController()->openPhoto(photo, id, topicRootId()); } void ListWidget::openDocument( @@ -477,6 +478,7 @@ void ListWidget::openDocument( _controller->parentController()->openDocument( document, id, + topicRootId(), showInMediaView); } @@ -739,6 +741,11 @@ void ListWidget::restoreScrollState() { _scrollTopState = ListScrollTopState(); } +MsgId ListWidget::topicRootId() const { + const auto topic = _controller->key().topic(); + return topic ? topic->rootId() : MsgId(0); +} + QMargins ListWidget::padding() const { return st::infoMediaMargin; } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index fec9cd0557..e95d5842ba 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -157,6 +157,8 @@ private: void setupSelectRestriction(); + [[nodiscard]] MsgId topicRootId() const; + QMargins padding() const; bool isItemLayout( not_null item, diff --git a/Telegram/SourceFiles/info/media/info_media_provider.cpp b/Telegram/SourceFiles/info/media/info_media_provider.cpp index 4cf51b462f..6bec9e04bb 100644 --- a/Telegram/SourceFiles/info/media/info_media_provider.cpp +++ b/Telegram/SourceFiles/info/media/info_media_provider.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_chat.h" #include "data/data_channel.h" +#include "data/data_forum_topic.h" #include "data/data_user.h" #include "data/data_peer_values.h" #include "data/data_document.h" @@ -61,6 +62,9 @@ constexpr auto kPreloadedScreensCountFull Provider::Provider(not_null controller) : _controller(controller) , _peer(_controller->key().peer()) +, _topicRootId(_controller->key().topic() + ? _controller->key().topic()->rootId() + : 0) , _migrated(_controller->migrated()) , _type(_controller->section().mediaType()) , _slice(sliceKey(_universalAroundId)) { @@ -348,14 +352,14 @@ void Provider::setSearchQuery(QString query) { SparseIdsMergedSlice::Key Provider::sliceKey( UniversalMsgId universalId) const { using Key = SparseIdsMergedSlice::Key; - if (_migrated) { - return Key(_peer->id, _migrated->id, universalId); + if (!_topicRootId && _migrated) { + return Key(_peer->id, _topicRootId, _migrated->id, universalId); } if (universalId < 0) { // Convert back to plain id for non-migrated histories. universalId = universalId + ServerMaxMsgId; } - return Key(_peer->id, 0, universalId); + return Key(_peer->id, _topicRootId, 0, universalId); } void Provider::itemRemoved(not_null item) { diff --git a/Telegram/SourceFiles/info/media/info_media_provider.h b/Telegram/SourceFiles/info/media/info_media_provider.h index 69b272f8b9..b544e2b8d7 100644 --- a/Telegram/SourceFiles/info/media/info_media_provider.h +++ b/Telegram/SourceFiles/info/media/info_media_provider.h @@ -104,6 +104,7 @@ private: const not_null _controller; const not_null _peer; + const MsgId _topicRootId = 0; PeerData * const _migrated = nullptr; const Type _type = Type::Photo; diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index fb92a296f1..eb13f977f0 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/media/info_media_buttons.h" #include "boxes/abstract_box.h" #include "boxes/add_contact_box.h" +#include "data/data_forum_topic.h" #include "ui/boxes/confirm_box.h" #include "mainwidget.h" #include "main/main_session.h" @@ -77,8 +78,7 @@ object_ptr InnerWidget::setupContent( }, _cover->lifetime()); _cover->setOnlineCount(rpl::single(0)); if (_topic) { - // #TODO forum shared media - //result->add(setupSharedMedia(result.data())); + result->add(setupSharedMedia(result.data())); return result; } @@ -127,6 +127,7 @@ object_ptr InnerWidget::setupSharedMedia( content, _controller, _peer, + _topic ? _topic->rootId() : 0, _migrated, type, tracker); diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index b6a69aa4dc..b31065ab80 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -400,6 +400,7 @@ rpl::producer KickedCountValue(not_null channel) { rpl::producer SharedMediaCountValue( not_null peer, + MsgId topicRootId, PeerData *migrated, Storage::SharedMediaType type) { auto aroundId = 0; @@ -409,6 +410,7 @@ rpl::producer SharedMediaCountValue( SharedMediaMergedKey( SparseIdsMergedSlice::Key( peer->id, + topicRootId, migrated ? migrated->id : 0, aroundId), type), diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index 1f70f086af..9f73c40531 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -85,6 +85,7 @@ rpl::producer> MigratedOrMeValue( not_null channel); [[nodiscard]] rpl::producer SharedMediaCountValue( not_null peer, + MsgId topicRootId, PeerData *migrated, Storage::SharedMediaType type); [[nodiscard]] rpl::producer CommonGroupsCountValue( diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index 5a4cd3ef16..fa527a7096 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -336,10 +336,11 @@ bool Result::onChoose(Layout::ItemBase *layout) { } Media::View::OpenRequest Result::openRequest() { + using namespace Media::View; if (_document) { - return Media::View::OpenRequest(nullptr, _document, nullptr); + return OpenRequest(nullptr, _document, nullptr, MsgId()); } else if (_photo) { - return Media::View::OpenRequest(nullptr, _photo, nullptr); + return OpenRequest(nullptr, _photo, nullptr, MsgId()); } return {}; } diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index 4cec5f0735..9cc24e5a9b 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -86,6 +86,7 @@ struct Instance::ShuffleData { std::vector nonPlayedIds; std::vector playedIds; History *history = nullptr; + MsgId topicRootId = 0; History *migrated = nullptr; bool scheduled = false; int indexInPlayedIds = 0; @@ -243,6 +244,7 @@ void Instance::setHistory( Main::Session *sessionFallback) { if (history) { data->history = history->migrateToOrMe(); + data->topicRootId = 0; data->migrated = data->history->migrateFrom(); setSession(data, &history->session()); } else { @@ -349,8 +351,8 @@ bool Instance::validPlaylist(not_null data) const { using Key = SliceKey; const auto inSameDomain = [](const Key &a, const Key &b) { return (a.peerId == b.peerId) - && (a.migratedPeerId == b.migratedPeerId) - && (a.scheduled == b.scheduled); + && (a.topicRootId == b.topicRootId) + && (a.migratedPeerId == b.migratedPeerId); }; const auto countDistanceInData = [&](const Key &a, const Key &b) { return [&](const SparseIdsMergedSlice &data) { @@ -382,7 +384,8 @@ void Instance::validatePlaylist(not_null data) { if (const auto key = playlistKey(data)) { data->playlistRequestedKey = key; - const auto sharedMediaViewer = key->scheduled + const auto sharedMediaViewer = (key->topicRootId + == SparseIdsMergedSlice::kScheduledTopicId) ? SharedScheduledMediaViewer : SharedMediaMergedViewer; sharedMediaViewer( @@ -419,9 +422,11 @@ auto Instance::playlistKey(not_null data) const : (contextId.msg - ServerMaxMsgId); return SliceKey( data->history->peer->id, + (item->isScheduled() + ? SparseIdsMergedSlice::kScheduledTopicId + : data->topicRootId), data->migrated ? data->migrated->peer->id : 0, - universalId, - item->isScheduled()); + universalId); } bool Instance::validOtherPlaylist(not_null data) const { @@ -476,13 +481,13 @@ auto Instance::playlistOtherKey(not_null data) const return SliceKey( data->history->peer->id, + data->topicRootId, data->migrated ? data->migrated->peer->id : 0, (data->playlistSlice->skippedBefore() == 0 ? ServerMaxMsgId - 1 : data->migrated ? (1 - ServerMaxMsgId) - : 1), - false); + : 1)); } HistoryItem *Instance::itemByIndex(not_null data, int index) { @@ -892,8 +897,10 @@ void Instance::validateShuffleData(not_null data) { } const auto raw = data->shuffleData.get(); const auto key = playlistKey(data); - const auto scheduled = key && key->scheduled; + const auto scheduled = key + && (key->topicRootId == SparseIdsMergedSlice::kScheduledTopicId); if (raw->history != data->history + || raw->topicRootId != data->topicRootId || raw->migrated != data->migrated || raw->scheduled != scheduled) { raw->history = data->history; @@ -950,9 +957,9 @@ void Instance::validateShuffleData(not_null data) { SharedMediaMergedKey( SliceKey( raw->history->peer->id, + raw->topicRootId, raw->migrated ? raw->migrated->peer->id : 0, - last, - false), + last), data->overview), kIdsLimit, kIdsLimit diff --git a/Telegram/SourceFiles/media/player/media_player_instance.h b/Telegram/SourceFiles/media/player/media_player_instance.h index 9255c9526b..31f5a68f9d 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.h +++ b/Telegram/SourceFiles/media/player/media_player_instance.h @@ -195,6 +195,7 @@ private: rpl::lifetime sessionLifetime; rpl::event_stream<> playlistChanges; History *history = nullptr; + MsgId topicRootId = 0; History *migrated = nullptr; Main::Session *session = nullptr; bool isPlaying = false; diff --git a/Telegram/SourceFiles/media/view/media_view_open_common.h b/Telegram/SourceFiles/media/view/media_view_open_common.h index b79566ba10..ad91019762 100644 --- a/Telegram/SourceFiles/media/view/media_view_open_common.h +++ b/Telegram/SourceFiles/media/view/media_view_open_common.h @@ -28,10 +28,12 @@ public: OpenRequest( Window::SessionController *controller, not_null photo, - HistoryItem *item) + HistoryItem *item, + MsgId topicRootId) : _controller(controller) , _photo(photo) - , _item(item) { + , _item(item) + , _topicRootId(topicRootId) { } OpenRequest( Window::SessionController *controller, @@ -46,11 +48,13 @@ public: Window::SessionController *controller, not_null document, HistoryItem *item, + MsgId topicRootId, bool continueStreaming = false, crl::time startTime = 0) : _controller(controller) , _document(document) , _item(item) + , _topicRootId(topicRootId) , _continueStreaming(continueStreaming) , _startTime(startTime) { } @@ -63,35 +67,39 @@ public: , _cloudTheme(cloudTheme) { } - PeerData *peer() const { + [[nodiscard]] PeerData *peer() const { return _peer; } - PhotoData *photo() const { + [[nodiscard]] PhotoData *photo() const { return _photo; } - HistoryItem *item() const { + [[nodiscard]] HistoryItem *item() const { return _item; } - DocumentData *document() const { + [[nodiscard]] MsgId topicRootId() const { + return _topicRootId; + } + + [[nodiscard]] DocumentData *document() const { return _document; } - std::optional cloudTheme() const { + [[nodiscard]] std::optional cloudTheme() const { return _cloudTheme; } - Window::SessionController *controller() const { + [[nodiscard]] Window::SessionController *controller() const { return _controller; } - bool continueStreaming() const { + [[nodiscard]] bool continueStreaming() const { return _continueStreaming; } - crl::time startTime() const { + [[nodiscard]] crl::time startTime() const { return _startTime; } @@ -101,6 +109,7 @@ private: PhotoData *_photo = nullptr; PeerData *_peer = nullptr; HistoryItem *_item = nullptr; + MsgId _topicRootId = 0; std::optional _cloudTheme = std::nullopt; bool _continueStreaming = false; crl::time _startTime = 0; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index f1f460983b..868236797c 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -244,7 +244,6 @@ struct OverlayWidget::PipWrap { PipWrap( QWidget *parent, not_null document, - FullMsgId contextId, std::shared_ptr shared, FnMut closeAndContinue, FnMut destroy); @@ -279,7 +278,6 @@ OverlayWidget::Streamed::Streamed( OverlayWidget::PipWrap::PipWrap( QWidget *parent, not_null document, - FullMsgId contextId, std::shared_ptr shared, FnMut closeAndContinue, FnMut destroy) @@ -287,7 +285,6 @@ OverlayWidget::PipWrap::PipWrap( , wrapped( &delegate, document, - contextId, std::move(shared), std::move(closeAndContinue), std::move(destroy)) { @@ -1708,7 +1705,11 @@ void OverlayWidget::handleDocumentClick() { if (_document->loading()) { saveCancel(); } else { - Data::ResolveDocument(findWindow(), _document, _message); + Data::ResolveDocument( + findWindow(), + _document, + _message, + _topicRootId); if (_document->loading() && !_radial.animating()) { _radial.start(_documentMedia->progress()); } @@ -1975,8 +1976,9 @@ auto OverlayWidget::sharedMediaKey() const -> std::optional { && !_user && _photo && _peer->userpicPhotoId() == _photo->id) { - return SharedMediaKey { + return SharedMediaKey{ _history->peer->id, + MsgId(0), // topicRootId _migrated ? _migrated->peer->id : 0, SharedMediaType::ChatPhoto, _photo @@ -1989,12 +1991,14 @@ auto OverlayWidget::sharedMediaKey() const -> std::optional { const auto keyForType = [&](SharedMediaType type) -> SharedMediaKey { return { _history->peer->id, + (isScheduled + ? SparseIdsMergedSlice::kScheduledTopicId + : _topicRootId), _migrated ? _migrated->peer->id : 0, type, (_message->history() == _history ? _message->id - : (_message->id - ServerMaxMsgId)), - isScheduled + : (_message->id - ServerMaxMsgId)) }; }; if (!_message->isRegular() && !isScheduled) { @@ -2038,8 +2042,8 @@ bool OverlayWidget::validSharedMedia() const { auto inSameDomain = [](const Key &a, const Key &b) { return (a.type == b.type) && (a.peerId == b.peerId) - && (a.migratedPeerId == b.migratedPeerId) - && (a.scheduled == b.scheduled); + && (a.topicRootId == b.topicRootId) + && (a.migratedPeerId == b.migratedPeerId); }; auto countDistanceInData = [&](const Key &a, const Key &b) { return [&](const SharedMediaWithLastSlice &data) { @@ -2432,6 +2436,7 @@ void OverlayWidget::show(OpenRequest request) { const auto photo = request.photo(); const auto contextItem = request.item(); const auto contextPeer = request.peer(); + const auto contextTopicRootId = request.topicRootId(); if (photo) { if (contextItem && contextPeer) { return; @@ -2441,7 +2446,7 @@ void OverlayWidget::show(OpenRequest request) { if (contextPeer) { setContext(contextPeer); } else if (contextItem) { - setContext(contextItem); + setContext(ItemContext{ contextItem, contextTopicRootId }); } else { setContext(v::null); } @@ -2457,7 +2462,7 @@ void OverlayWidget::show(OpenRequest request) { setSession(&document->session()); if (contextItem) { - setContext(contextItem); + setContext(ItemContext{ contextItem, contextTopicRootId }); } else { setContext(v::null); } @@ -3299,19 +3304,20 @@ void OverlayWidget::switchToPip() { const auto document = _document; const auto message = _message; + const auto topicRootId = _topicRootId; const auto closeAndContinue = [=] { _showAsPip = false; show(OpenRequest( findWindow(false), document, message, + topicRootId, true)); }; _showAsPip = true; _pip = std::make_unique( _widget, document, - message ? message->fullId() : FullMsgId(), _streamed->instance.shared(), closeAndContinue, [=] { _pip = nullptr; }); @@ -4091,9 +4097,9 @@ OverlayWidget::Entity OverlayWidget::entityForCollage(int index) const { return { v::null, nullptr }; } if (const auto document = std::get_if(&items[index])) { - return { *document, _message }; + return { *document, _message, _topicRootId }; } else if (const auto photo = std::get_if(&items[index])) { - return { *photo, _message }; + return { *photo, _message, _topicRootId }; } return { v::null, nullptr }; } @@ -4104,12 +4110,12 @@ OverlayWidget::Entity OverlayWidget::entityForItemId(const FullMsgId &itemId) co if (const auto item = _session->data().message(itemId)) { if (const auto media = item->media()) { if (const auto photo = media->photo()) { - return { photo, item }; + return { photo, item, _topicRootId }; } else if (const auto document = media->document()) { - return { document, item }; + return { document, item, _topicRootId }; } } - return { v::null, item }; + return { v::null, item, _topicRootId }; } return { v::null, nullptr }; } @@ -4128,25 +4134,29 @@ OverlayWidget::Entity OverlayWidget::entityByIndex(int index) const { void OverlayWidget::setContext( std::variant< v::null_t, - not_null, + ItemContext, not_null> context) { - if (const auto item = std::get_if>(&context)) { - _message = (*item); + if (const auto item = std::get_if(&context)) { + _message = item->item; + _topicRootId = item->topicRootId; _history = _message->history(); _peer = _history->peer; } else if (const auto peer = std::get_if>(&context)) { _peer = *peer; _history = _peer->owner().history(_peer); _message = nullptr; + _topicRootId = MsgId(); } else { _message = nullptr; + _topicRootId = MsgId(); _history = nullptr; _peer = nullptr; } _migrated = nullptr; if (_history) { if (_history->peer->migrateFrom()) { - _migrated = _history->owner().history(_history->peer->migrateFrom()); + _migrated = _history->owner().history( + _history->peer->migrateFrom()); } else if (_history->peer->migrateTo()) { _migrated = _history; _history = _history->owner().history(_history->peer->migrateTo()); @@ -4211,7 +4221,7 @@ bool OverlayWidget::moveToEntity(const Entity &entity, int preloadDelta) { return false; } if (const auto item = entity.item) { - setContext(item); + setContext(ItemContext{ item, entity.topicRootId }); } else if (_peer) { setContext(_peer); } else { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index d1eb15b51d..9d133a8a6b 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -131,7 +131,8 @@ private: v::null_t, not_null, not_null> data; - HistoryItem *item; + HistoryItem *item = nullptr; + MsgId topicRootId = 0; }; enum class SavePhotoVideo { None, @@ -241,9 +242,14 @@ private: Entity entityByIndex(int index) const; Entity entityForItemId(const FullMsgId &itemId) const; bool moveToEntity(const Entity &entity, int preloadDelta = 0); + + struct ItemContext { + not_null item; + MsgId topicRootId = 0; + }; void setContext(std::variant< v::null_t, - not_null, + ItemContext, not_null> context); void refreshLang(); @@ -519,6 +525,7 @@ private: History *_migrated = nullptr; History *_history = nullptr; // if conversation photos or files overview + MsgId _topicRootId = 0; PeerData *_peer = nullptr; UserData *_user = nullptr; // if user profile photos overview diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index 91d58ae309..e27dfa4a8f 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -906,13 +906,11 @@ void PipPanel::updateDecorations() { Pip::Pip( not_null delegate, not_null data, - FullMsgId contextId, std::shared_ptr shared, FnMut closeAndContinue, FnMut destroy) : _delegate(delegate) , _data(data) -, _contextId(contextId) , _instance(std::move(shared), [=] { waitingAnimationCallback(); }) , _panel( _delegate->pipParentWidget(), diff --git a/Telegram/SourceFiles/media/view/media_view_pip.h b/Telegram/SourceFiles/media/view/media_view_pip.h index 6cf6c66901..dcc251ec3d 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.h +++ b/Telegram/SourceFiles/media/view/media_view_pip.h @@ -135,7 +135,6 @@ public: Pip( not_null delegate, not_null data, - FullMsgId contextId, std::shared_ptr shared, FnMut closeAndContinue, FnMut destroy); @@ -254,7 +253,6 @@ private: const not_null _delegate; const not_null _data; - FullMsgId _contextId; Streaming::Instance _instance; bool _opengl = false; PipPanel _panel; diff --git a/Telegram/SourceFiles/storage/storage_shared_media.cpp b/Telegram/SourceFiles/storage/storage_shared_media.cpp index 225af5e391..e6ced75914 100644 --- a/Telegram/SourceFiles/storage/storage_shared_media.cpp +++ b/Telegram/SourceFiles/storage/storage_shared_media.cpp @@ -11,13 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Storage { -std::map::iterator - SharedMedia::enforceLists(PeerId peer) { - auto result = _lists.find(peer); +auto SharedMedia::enforceLists(Key key) +-> std::map::iterator { + auto result = _lists.find(key); if (result != _lists.end()) { return result; } - result = _lists.emplace(peer, Lists {}).first; + result = _lists.emplace(key, Lists {}).first; for (auto index = 0; index != kSharedMediaTypeCount; ++index) { auto &list = result->second[index]; auto type = static_cast(index); @@ -25,7 +25,8 @@ std::map::iterator list.sliceUpdated( ) | rpl::map([=](const SparseIdsSliceUpdate &update) { return SharedMediaSliceUpdate( - peer, + key.peerId, + key.topicRootId, type, update); }) | rpl::start_to_stream(_sliceUpdated, _lifetime); @@ -34,22 +35,26 @@ std::map::iterator } void SharedMedia::add(SharedMediaAddNew &&query) { - auto peer = query.peerId; - auto peerIt = enforceLists(peer); - for (auto index = 0; index != kSharedMediaTypeCount; ++index) { - auto type = static_cast(index); - if (query.types.test(type)) { - peerIt->second[index].addNew(query.messageId); + auto peerIt = enforceLists({ query.peerId, MsgId(0) }); + while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) { + for (auto index = 0; index != kSharedMediaTypeCount; ++index) { + auto type = static_cast(index); + if (query.types.test(type)) { + peerIt->second[index].addNew(query.messageId); + } } + ++peerIt; } } void SharedMedia::add(SharedMediaAddExisting &&query) { - auto peerIt = enforceLists(query.peerId); + auto peerIt = enforceLists({ query.peerId, query.topicRootId }); for (auto index = 0; index != kSharedMediaTypeCount; ++index) { auto type = static_cast(index); if (query.types.test(type)) { - peerIt->second[index].addExisting(query.messageId, query.noSkipRange); + peerIt->second[index].addExisting( + query.messageId, + query.noSkipRange); } } } @@ -57,7 +62,7 @@ void SharedMedia::add(SharedMediaAddExisting &&query) { void SharedMedia::add(SharedMediaAddSlice &&query) { Expects(IsValidSharedMediaType(query.type)); - auto peerIt = enforceLists(query.peerId); + auto peerIt = enforceLists({ query.peerId, query.topicRootId }); auto index = static_cast(query.type); peerIt->second[index].addSlice( std::move(query.messageIds), @@ -66,45 +71,48 @@ void SharedMedia::add(SharedMediaAddSlice &&query) { } void SharedMedia::remove(SharedMediaRemoveOne &&query) { - auto peerIt = _lists.find(query.peerId); - if (peerIt != _lists.end()) { + auto peerIt = _lists.find({ query.peerId, MsgId(0) }); + while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) { auto type = static_cast(index); if (query.types.test(type)) { peerIt->second[index].removeOne(query.messageId); } } - _oneRemoved.fire(std::move(query)); + ++peerIt; } + _oneRemoved.fire(std::move(query)); } void SharedMedia::remove(SharedMediaRemoveAll &&query) { - auto peerIt = _lists.find(query.peerId); - if (peerIt != _lists.end()) { + auto peerIt = _lists.find({ query.peerId, MsgId(0) }); + while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) { auto type = static_cast(index); if (query.types.test(type)) { peerIt->second[index].removeAll(); } } - _allRemoved.fire(std::move(query)); + ++peerIt; } + _allRemoved.fire(std::move(query)); } void SharedMedia::invalidate(SharedMediaInvalidateBottom &&query) { - auto peerIt = _lists.find(query.peerId); - if (peerIt != _lists.end()) { + auto peerIt = _lists.find({ query.peerId, MsgId(0) }); + while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) { peerIt->second[index].invalidateBottom(); } - _bottomInvalidated.fire(std::move(query)); + ++peerIt; } + _bottomInvalidated.fire(std::move(query)); } rpl::producer SharedMedia::query(SharedMediaQuery &&query) const { Expects(IsValidSharedMediaType(query.key.type)); - auto peerIt = _lists.find(query.key.peerId); + auto peerIt = _lists.find({ query.key.peerId, query.key.topicRootId }); if (peerIt != _lists.end()) { auto index = static_cast(query.key.type); return peerIt->second[index].query(SparseIdsListQuery( @@ -121,7 +129,7 @@ rpl::producer SharedMedia::query(SharedMediaQuery &&query) co SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const { Expects(IsValidSharedMediaType(query.key.type)); - auto peerIt = _lists.find(query.key.peerId); + auto peerIt = _lists.find({ query.key.peerId, query.key.topicRootId }); if (peerIt != _lists.end()) { auto index = static_cast(query.key.type); return peerIt->second[index].snapshot(SparseIdsListQuery( @@ -135,7 +143,7 @@ SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const { bool SharedMedia::empty(const SharedMediaKey &key) const { Expects(IsValidSharedMediaType(key.type)); - auto peerIt = _lists.find(key.peerId); + auto peerIt = _lists.find({ key.peerId, key.topicRootId }); if (peerIt != _lists.end()) { auto index = static_cast(key.type); return peerIt->second[index].empty(); diff --git a/Telegram/SourceFiles/storage/storage_shared_media.h b/Telegram/SourceFiles/storage/storage_shared_media.h index b2cd80929a..c2d5aafdc4 100644 --- a/Telegram/SourceFiles/storage/storage_shared_media.h +++ b/Telegram/SourceFiles/storage/storage_shared_media.h @@ -39,8 +39,13 @@ constexpr bool IsValidSharedMediaType(SharedMediaType type) { using SharedMediaTypesMask = base::enum_mask; struct SharedMediaAddNew { - SharedMediaAddNew(PeerId peerId, SharedMediaTypesMask types, MsgId messageId) - : peerId(peerId), messageId(messageId), types(types) { + SharedMediaAddNew( + PeerId peerId, + SharedMediaTypesMask types, + MsgId messageId) + : peerId(peerId) + , messageId(messageId) + , types(types) { } PeerId peerId = 0; @@ -52,16 +57,19 @@ struct SharedMediaAddNew { struct SharedMediaAddExisting { SharedMediaAddExisting( PeerId peerId, + MsgId topicRootId, SharedMediaTypesMask types, MsgId messageId, MsgRange noSkipRange) - : peerId(peerId) - , messageId(messageId) - , noSkipRange(noSkipRange) - , types(types) { + : peerId(peerId) + , topicRootId(topicRootId) + , messageId(messageId) + , noSkipRange(noSkipRange) + , types(types) { } PeerId peerId = 0; + MsgId topicRootId = 0; MsgId messageId = 0; MsgRange noSkipRange; SharedMediaTypesMask types; @@ -71,18 +79,21 @@ struct SharedMediaAddExisting { struct SharedMediaAddSlice { SharedMediaAddSlice( PeerId peerId, + MsgId topicRootId, SharedMediaType type, std::vector &&messageIds, MsgRange noSkipRange, std::optional count = std::nullopt) - : peerId(peerId) - , messageIds(std::move(messageIds)) - , noSkipRange(noSkipRange) - , type(type) - , count(count) { + : peerId(peerId) + , topicRootId(topicRootId) + , messageIds(std::move(messageIds)) + , noSkipRange(noSkipRange) + , type(type) + , count(count) { } PeerId peerId = 0; + MsgId topicRootId = 0; std::vector messageIds; MsgRange noSkipRange; SharedMediaType type = SharedMediaType::kCount; @@ -130,23 +141,21 @@ struct SharedMediaInvalidateBottom { struct SharedMediaKey { SharedMediaKey( PeerId peerId, + MsgId topicRootId, SharedMediaType type, MsgId messageId) : peerId(peerId) + , topicRootId(topicRootId) , type(type) , messageId(messageId) { } - bool operator==(const SharedMediaKey &other) const { - return (peerId == other.peerId) - && (type == other.type) - && (messageId == other.messageId); - } - bool operator!=(const SharedMediaKey &other) const { - return !(*this == other); - } + friend inline constexpr auto operator<=>( + const SharedMediaKey &, + const SharedMediaKey &) = default; PeerId peerId = 0; + MsgId topicRootId = 0; SharedMediaType type = SharedMediaType::kCount; MsgId messageId = 0; @@ -173,14 +182,17 @@ using SharedMediaResult = SparseIdsListResult; struct SharedMediaSliceUpdate { SharedMediaSliceUpdate( PeerId peerId, + MsgId topicRootId, SharedMediaType type, const SparseIdsSliceUpdate &data) : peerId(peerId) + , topicRootId(topicRootId) , type(type) , data(data) { } PeerId peerId = 0; + MsgId topicRootId = 0; SharedMediaType type = SharedMediaType::kCount; SparseIdsSliceUpdate data; }; @@ -205,11 +217,17 @@ public: rpl::producer bottomInvalidated() const; private: + struct Key { + PeerId peerId = 0; + MsgId topicRootId = 0; + + friend inline constexpr auto operator<=>(Key, Key) = default; + }; using Lists = std::array; - std::map::iterator enforceLists(PeerId peer); + std::map::iterator enforceLists(Key key); - std::map _lists; + std::map _lists; rpl::event_stream _sliceUpdated; rpl::event_stream _oneRemoved; diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index a27096ade8..0ab888f341 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -1443,7 +1443,7 @@ void HidePinnedBar( close(); auto &session = peer->session(); const auto migrated = peer->migrateFrom(); - const auto top = Data::ResolveTopPinnedId(peer, migrated); + const auto top = Data::ResolveTopPinnedId(peer, MsgId(0), migrated); const auto universal = !top ? MsgId(0) : (migrated && !peerIsChannel(top.peer)) diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index da669e052d..57e65ab78a 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1707,11 +1707,13 @@ void SessionController::hideLayer(anim::type animated) { void SessionController::openPhoto( not_null photo, - FullMsgId contextId) { + FullMsgId contextId, + MsgId topicRootId) { _window->openInMediaView(Media::View::OpenRequest( this, photo, - session().data().message(contextId))); + session().data().message(contextId), + topicRootId)); } void SessionController::openPhoto( @@ -1723,18 +1725,21 @@ void SessionController::openPhoto( void SessionController::openDocument( not_null document, FullMsgId contextId, + MsgId topicRootId, bool showInMediaView) { if (showInMediaView) { _window->openInMediaView(Media::View::OpenRequest( this, document, - session().data().message(contextId))); + session().data().message(contextId), + topicRootId)); return; } Data::ResolveDocument( this, document, - session().data().message(contextId)); + session().data().message(contextId), + topicRootId); } auto SessionController::cachedChatThemeValue( diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 96eaab33e3..efec0dc0cb 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -441,11 +441,15 @@ public: void showPassportForm(const Passport::FormRequest &request); void clearPassportForm(); - void openPhoto(not_null photo, FullMsgId contextId); + void openPhoto( + not_null photo, + FullMsgId contextId, + MsgId topicRootId); void openPhoto(not_null photo, not_null peer); void openDocument( not_null document, FullMsgId contextId, + MsgId topicRootId, bool showInMediaView = false); void showChooseReportMessages(