diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index 08073b683f..4f14fabb15 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -353,15 +353,7 @@ void Stories::processExpired() { } Stories::Set *Stories::lookupArchive(not_null peer) { - const auto peerId = peer->id; - if (hasArchive(peer)) { - const auto i = _archive.find(peerId); - return (i != end(_archive)) - ? &i->second - : &_archive.emplace(peerId, Set()).first->second; - } - clearArchive(peer); - return nullptr; + return albumIdsSet(peer->id, kStoriesAlbumIdArchive); } void Stories::clearArchive(not_null peer) { @@ -379,7 +371,7 @@ void Stories::clearArchive(not_null peer) { } } } - _archiveChanged.fire_copy(peerId); + _albumIdsChanged.fire({ peerId, kStoriesAlbumIdArchive }); } void Stories::parseAndApply( @@ -523,7 +515,7 @@ Story *Stories::parseAndApply( if (archive->total >= 0 && id > archive->lastId) { ++archive->total; } - _archiveChanged.fire_copy(peer->id); + _albumIdsChanged.fire({ peer->id, kStoriesAlbumIdArchive }); } } @@ -615,7 +607,7 @@ void Stories::savedStateChanged(not_null story) { if (saved.total >= 0 && id > saved.lastId) { ++saved.total; } - _savedChanged.fire_copy(peer); + _albumIdsChanged.fire({ peer, kStoriesAlbumIdSaved }); } } else if (const auto i = _saved.find(peer); i != end(_saved)) { auto &saved = i->second; @@ -623,7 +615,7 @@ void Stories::savedStateChanged(not_null story) { if (saved.total > 0) { --saved.total; } - _savedChanged.fire_copy(peer); + _albumIdsChanged.fire({ peer, kStoriesAlbumIdSaved }); } } } @@ -678,6 +670,8 @@ void Stories::preloadListsMore() { const auto index = static_cast(list); return _sourcesLoaded[index] || !_sourcesStates[index].isEmpty(); }; + const auto selfId = _owner->session().userPeerId(); + constexpr auto archive = kStoriesAlbumIdArchive; if (loading(StorySourcesList::NotHidden) || loading(StorySourcesList::Hidden)) { return; @@ -685,8 +679,8 @@ void Stories::preloadListsMore() { loadMore(StorySourcesList::NotHidden); } else if (!countLoaded(StorySourcesList::Hidden)) { loadMore(StorySourcesList::Hidden); - } else if (!archiveCountKnown(_owner->session().userPeerId())) { - archiveLoadMore(_owner->session().userPeerId()); + } else if (!albumIdsCountKnown(selfId, archive)) { + albumIdsLoadMore(selfId, archive); } } @@ -831,28 +825,24 @@ void Stories::applyDeleted(not_null peer, StoryId id) { story.get(), UpdateFlag::Destroyed); removeDependencyStory(story.get()); - if (hasArchive(story->peer())) { - if (const auto k = _archive.find(peerId) - ; k != end(_archive)) { - const auto archive = &k->second; - if (archive->ids.list.remove(id)) { - if (archive->total > 0) { - --archive->total; + const auto removeFromAlbum = [&](int albumId) { + if (const auto set = albumIdsSet(peerId, albumId, true)) { + if (set->ids.list.remove(id)) { + if (set->total > 0) { + --set->total; } - _archiveChanged.fire_copy(peerId); + _albumIdsChanged.fire({ peerId, albumId }); } } + }; + if (hasArchive(story->peer())) { + removeFromAlbum(kStoriesAlbumIdArchive); } if (story->inProfile()) { - if (const auto k = _saved.find(peerId); k != end(_saved)) { - const auto saved = &k->second; - if (saved->ids.list.remove(id)) { - if (saved->total > 0) { - --saved->total; - } - _savedChanged.fire_copy(peerId); - } - } + removeFromAlbum(kStoriesAlbumIdSaved); + } + for (const auto id : story->albumIds()) { + removeFromAlbum(id); } if (_preloading && _preloading->id() == fullId) { _preloading = nullptr; @@ -1465,7 +1455,7 @@ void Stories::loadReactionsSlice( slice.list.push_back({ .peer = story->peer(), .repostId = story->id(), - }); + }); } }, [&](const MTPDstoryReactionPublicForward &data) { const auto item = _owner->addNewMessage( @@ -1613,153 +1603,140 @@ bool Stories::hasArchive(not_null peer) const { return false; } -const StoriesIds &Stories::archive(PeerId peerId) const { +const Stories::Set *Stories::albumIdsSet(PeerId peerId, int albumId) const { + return const_cast(this)->albumIdsSet(peerId, albumId, true); +} + +Stories::Set *Stories::albumIdsSet(PeerId peerId, int albumId, bool lazy) { + if (albumId == kStoriesAlbumIdArchive) { + const auto peer = _owner->peer(peerId); + if (!hasArchive(peer)) { + clearArchive(peer); + return nullptr; + } + const auto i = _archive.find(peerId); + return (i != end(_archive)) + ? &i->second + : lazy + ? nullptr + : &_archive.emplace(peerId, Set()).first->second; + } else if (albumId == kStoriesAlbumIdSaved) { + const auto i = _saved.find(peerId); + return (i != end(_saved)) + ? &i->second + : lazy + ? nullptr + : &_saved.emplace(peerId, Set()).first->second; + } + auto i = _albums.find(peerId); + if (i == end(_albums)) { + if (lazy) { + return nullptr; + } + i = _albums.emplace(peerId, Albums()).first; + } + const auto j = i->second.sets.find(albumId); + return (j != end(i->second.sets)) + ? &j->second + : lazy + ? nullptr + : &i->second.sets.emplace(albumId).first->second; +} + +const StoriesIds &Stories::albumIds(PeerId peerId, int albumId) const { static const auto empty = StoriesIds(); - const auto i = _archive.find(peerId); - return (i != end(_archive)) ? i->second.ids : empty; + const auto set = albumIdsSet(peerId, albumId); + return set ? set->ids : empty; } -rpl::producer Stories::archiveChanged() const { - return _archiveChanged.events(); +rpl::producer Stories::albumIdsChanged() const { + return _albumIdsChanged.events(); } -int Stories::archiveCount(PeerId peerId) const { - const auto i = _archive.find(peerId); - return (i != end(_archive)) ? i->second.total : 0; +int Stories::albumIdsCount(PeerId peerId, int albumId) const { + const auto set = albumIdsSet(peerId, albumId); + return set ? set->total : 0; } -bool Stories::archiveCountKnown(PeerId peerId) const { - const auto i = _archive.find(peerId); - return (i != end(_archive)) && (i->second.total >= 0); +bool Stories::albumIdsCountKnown(PeerId peerId, int albumId) const { + const auto set = albumIdsSet(peerId, albumId); + return set && (set->total >= 0); } -bool Stories::archiveLoaded(PeerId peerId) const { - const auto i = _archive.find(peerId); - return (i != end(_archive)) && i->second.loaded; +bool Stories::albumIdsLoaded(PeerId peerId, int albumId) const { + const auto set = albumIdsSet(peerId, albumId); + return set && set->loaded; } -const StoriesIds &Stories::saved(PeerId peerId) const { - static const auto empty = StoriesIds(); - const auto i = _saved.find(peerId); - return (i != end(_saved)) ? i->second.ids : empty; -} - -rpl::producer Stories::savedChanged() const { - return _savedChanged.events(); -} - -int Stories::savedCount(PeerId peerId) const { - const auto i = _saved.find(peerId); - return (i != end(_saved)) ? i->second.total : 0; -} - -bool Stories::savedCountKnown(PeerId peerId) const { - const auto i = _saved.find(peerId); - return (i != end(_saved)) && (i->second.total >= 0); -} - -bool Stories::savedLoaded(PeerId peerId) const { - const auto i = _saved.find(peerId); - return (i != end(_saved)) && i->second.loaded; -} - -void Stories::archiveLoadMore(PeerId peerId) { +void Stories::albumIdsLoadMore(PeerId peerId, int albumId) { const auto peer = _owner->peer(peerId); - const auto archive = lookupArchive(peer); - if (!archive || archive->requestId || archive->loaded) { + const auto set = albumIdsSet(peerId, albumId); + if (!set || set->requestId || set->loaded) { return; } const auto api = &_owner->session().api(); - archive->requestId = api->request(MTPstories_GetStoriesArchive( - peer->input, - MTP_int(archive->lastId), - MTP_int(archive->lastId ? kArchivePerPage : kArchiveFirstPerPage) - )).done([=](const MTPstories_Stories &result) { - const auto archive = lookupArchive(peer); - if (!archive) { + const auto done = [=](const MTPstories_Stories &result) { + const auto set = albumIdsSet(peerId, albumId); + if (!set) { return; } - archive->requestId = 0; - - const auto &data = result.data(); - const auto now = base::unixtime::now(); - archive->total = data.vcount().v; - for (const auto &story : data.vstories().v) { - const auto id = story.match([&](const auto &id) { - return id.vid().v; - }); - archive->ids.list.emplace(id); - archive->lastId = id; - if (!parseAndApply(peer, story, now)) { - archive->ids.list.remove(id); - if (archive->total > 0) { - --archive->total; - } - } - } - const auto ids = int(archive->ids.list.size()); - archive->loaded = data.vstories().v.empty(); - archive->total = archive->loaded ? ids : std::max(archive->total, ids); - _archiveChanged.fire_copy(peerId); - }).fail([=] { - const auto archive = lookupArchive(peer); - if (!archive) { - return; - } - archive->requestId = 0; - archive->loaded = true; - archive->total = int(archive->ids.list.size()); - _archiveChanged.fire_copy(peerId); - }).send(); -} - -void Stories::savedLoadMore(PeerId peerId) { - auto &saved = _saved[peerId]; - if (saved.requestId || saved.loaded) { - return; - } - const auto api = &_owner->session().api(); - const auto peer = _owner->peer(peerId); - saved.requestId = api->request(MTPstories_GetPinnedStories( - peer->input, - MTP_int(saved.lastId), - MTP_int(saved.lastId ? kSavedPerPage : kSavedFirstPerPage) - )).done([=](const MTPstories_Stories &result) { - auto &saved = _saved[peerId]; - saved.requestId = 0; - + set->requestId = 0; const auto &data = result.data(); const auto now = base::unixtime::now(); auto pinnedToTopIds = data.vpinned_to_top().value_or_empty(); auto pinnedToTop = pinnedToTopIds | ranges::views::transform(&MTPint::v) | ranges::to_vector; - saved.total = data.vcount().v; + set->total = data.vcount().v; for (const auto &story : data.vstories().v) { const auto id = story.match([&](const auto &id) { return id.vid().v; }); - saved.ids.list.emplace(id); - saved.lastId = id; + set->ids.list.emplace(id); + set->lastId = id; if (!parseAndApply(peer, story, now)) { - saved.ids.list.remove(id); - if (saved.total > 0) { - --saved.total; + set->ids.list.remove(id); + if (set->total > 0) { + --set->total; } } } - const auto ids = int(saved.ids.list.size()); - saved.loaded = data.vstories().v.empty(); - saved.total = saved.loaded ? ids : std::max(saved.total, ids); - setPinnedToTop(peerId, std::move(pinnedToTop)); - _savedChanged.fire_copy(peerId); - }).fail([=] { - auto &saved = _saved[peerId]; - saved.requestId = 0; - saved.loaded = true; - saved.total = int(saved.ids.list.size()); - _savedChanged.fire_copy(peerId); - }).send(); + const auto count = int(set->ids.list.size()); + set->loaded = data.vstories().v.empty(); + set->total = set->loaded ? count : std::max(set->total, count); + if (albumId == kStoriesAlbumIdSaved) { + setPinnedToTop(peerId, std::move(pinnedToTop)); + } + _albumIdsChanged.fire({ peerId, albumId }); + }; + const auto fail = [=] { + const auto set = albumIdsSet(peerId, albumId); + if (!set) { + return; + } + set->requestId = 0; + set->loaded = true; + set->total = int(set->ids.list.size()); + _albumIdsChanged.fire({ peerId, albumId }); + }; + set->requestId = (albumId == kStoriesAlbumIdArchive) + ? api->request(MTPstories_GetStoriesArchive( + peer->input, + MTP_int(set->lastId), + MTP_int(set->lastId ? kArchivePerPage : kArchiveFirstPerPage) + )).done(done).fail(fail).send() + : (albumId == kStoriesAlbumIdSaved) + ? api->request(MTPstories_GetPinnedStories( + peer->input, + MTP_int(set->lastId), + MTP_int(set->lastId ? kSavedPerPage : kSavedFirstPerPage) + )).done(done).fail(fail).send() + : api->request(MTPstories_GetAlbumStories( + peer->input, + MTP_int(albumId), + MTP_int(set->lastId), + MTP_int(set->lastId ? kSavedPerPage : kSavedFirstPerPage) + )).done(done).fail(fail).send(); } auto Stories::albumsListValue(PeerId peerId) @@ -1976,9 +1953,9 @@ void Stories::toggleInProfileList( } } if (dirty) { - savedLoadMore(peerId); + albumIdsLoadMore(peerId, kStoriesAlbumIdSaved); } else { - _savedChanged.fire_copy(peerId); + _albumIdsChanged.fire({ peerId, kStoriesAlbumIdSaved }); } }).send(); } @@ -2047,7 +2024,7 @@ void Stories::togglePinnedList( setPinnedToTop(peerId, list | ranges::views::transform(&MTPint::v) | ranges::to_vector); - _savedChanged.fire_copy(peerId); + _albumIdsChanged.fire({ peerId, kStoriesAlbumIdSaved }); }).send(); } diff --git a/Telegram/SourceFiles/data/data_stories.h b/Telegram/SourceFiles/data/data_stories.h index 24e85ebe0d..08c4390b62 100644 --- a/Telegram/SourceFiles/data/data_stories.h +++ b/Telegram/SourceFiles/data/data_stories.h @@ -133,6 +133,18 @@ struct StoryAlbumUpdate { inline constexpr auto kStorySourcesListCount = 2; +struct StoryAlbumIdsKey { + PeerId peerId; + int albumId = 0; + + friend inline auto operator<=>( + StoryAlbumIdsKey, + StoryAlbumIdsKey) = default; + friend inline bool operator==( + StoryAlbumIdsKey, + StoryAlbumIdsKey) = default; +}; + class Stories final : public base::has_weak_ptr { public: explicit Stories(not_null owner); @@ -197,19 +209,14 @@ public: [[nodiscard]] bool hasArchive(not_null peer) const; - [[nodiscard]] const StoriesIds &archive(PeerId peerId) const; - [[nodiscard]] rpl::producer archiveChanged() const; - [[nodiscard]] int archiveCount(PeerId peerId) const; - [[nodiscard]] bool archiveCountKnown(PeerId peerId) const; - [[nodiscard]] bool archiveLoaded(PeerId peerId) const; - void archiveLoadMore(PeerId peerId); - - [[nodiscard]] const StoriesIds &saved(PeerId peerId) const; - [[nodiscard]] rpl::producer savedChanged() const; - [[nodiscard]] int savedCount(PeerId peerId) const; - [[nodiscard]] bool savedCountKnown(PeerId peerId) const; - [[nodiscard]] bool savedLoaded(PeerId peerId) const; - void savedLoadMore(PeerId peerId); + [[nodiscard]] const StoriesIds &albumIds( + PeerId peerId, + int albumId) const; + [[nodiscard]] rpl::producer albumIdsChanged() const; + [[nodiscard]] int albumIdsCount(PeerId peerIdl, int albumId) const; + [[nodiscard]] bool albumIdsCountKnown(PeerId peerId, int albumId) const; + [[nodiscard]] bool albumIdsLoaded(PeerId peerId, int albumId) const; + void albumIdsLoadMore(PeerId peerId, int albumId); [[nodiscard]] auto albumsListValue(PeerId peerId) -> rpl::producer>; @@ -319,6 +326,9 @@ private: [[nodiscard]] Set *lookupArchive(not_null peer); void clearArchive(not_null peer); + const Set *albumIdsSet(PeerId peerId, int albumId) const; + Set *albumIdsSet(PeerId peerId, int albumId, bool lazy = false); + void applyDeleted(not_null peer, StoryId id); void applyExpired(FullStoryId id); void applyRemovedFromActive(FullStoryId id); @@ -403,13 +413,10 @@ private: rpl::event_stream _itemsChanged; std::unordered_map _archive; - rpl::event_stream _archiveChanged; - std::unordered_map _saved; - rpl::event_stream _savedChanged; - std::unordered_map _albums; rpl::event_stream _albumUpdates; + rpl::event_stream _albumIdsChanged; base::flat_set _markReadPending; base::Timer _markReadTimer; diff --git a/Telegram/SourceFiles/data/data_stories_ids.cpp b/Telegram/SourceFiles/data/data_stories_ids.cpp index d2ac334272..91eadee34f 100644 --- a/Telegram/SourceFiles/data/data_stories_ids.cpp +++ b/Telegram/SourceFiles/data/data_stories_ids.cpp @@ -16,8 +16,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { -rpl::producer SavedStoriesIds( +rpl::producer AlbumStoriesIds( not_null peer, + int albumId, StoryId aroundId, int limit) { return [=](auto consumer) { @@ -35,22 +36,21 @@ rpl::producer SavedStoriesIds( const auto peerId = peer->id; const auto stories = &peer->owner().stories(); - if (!stories->savedCountKnown(peerId)) { + if (!stories->albumIdsCountKnown(peerId, albumId)) { return; } - - const auto &saved = stories->saved(peerId); - const auto sorted = RespectingPinned(saved); - const auto count = stories->savedCount(peerId); + const auto &loaded = stories->albumIds(peerId, albumId); + const auto sorted = RespectingPinned(loaded); + const auto count = stories->albumIdsCount(peerId, albumId); auto i = ranges::find(sorted, aroundId); if (i == end(sorted)) { - const auto j = saved.list.lower_bound(aroundId); - i = begin(sorted) + int(j - begin(saved.list)); + const auto j = loaded.list.lower_bound(aroundId); + i = begin(sorted) + int(j - begin(loaded.list)); } const auto hasBefore = int(i - begin(sorted)); const auto hasAfter = int(end(sorted) - i); if (hasAfter < limit) { - stories->savedLoadMore(peerId); + stories->albumIdsLoadMore(peerId, albumId); } const auto takeBefore = std::min(hasBefore, limit); const auto takeAfter = std::min(hasAfter, limit); @@ -81,91 +81,13 @@ rpl::producer SavedStoriesIds( const auto peerId = peer->id; const auto stories = &peer->owner().stories(); - stories->savedChanged( + stories->albumIdsChanged( ) | rpl::filter( - rpl::mappers::_1 == peerId + rpl::mappers::_1 == Data::StoryAlbumIdsKey{ peerId, albumId } ) | rpl::start_with_next(schedule, lifetime); - if (!stories->savedCountKnown(peerId)) { - stories->savedLoadMore(peerId); - } - - push(); - - return lifetime; - }; -} - -rpl::producer ArchiveStoriesIds( - not_null peer, - StoryId aroundId, - int limit) { - return [=](auto consumer) { - auto lifetime = rpl::lifetime(); - - struct State { - StoriesIdsSlice slice; - base::has_weak_ptr guard; - bool scheduled = false; - }; - const auto state = lifetime.make_state(); - - const auto push = [=] { - state->scheduled = false; - - const auto peerId = peer->id; - const auto stories = &peer->owner().stories(); - if (!stories->archiveCountKnown(peerId)) { - return; - } - - const auto &archive = stories->archive(peerId); - const auto sorted = RespectingPinned(archive); - const auto count = stories->savedCount(peerId); - auto i = ranges::find(sorted, aroundId); - if (i == end(sorted)) { - const auto j = archive.list.lower_bound(aroundId); - i = begin(sorted) + int(j - begin(archive.list)); - } - const auto hasBefore = int(i - begin(sorted)); - const auto hasAfter = int(end(sorted) - i); - if (hasAfter < limit) { - stories->archiveLoadMore(peerId); - } - const auto takeBefore = std::min(hasBefore, limit); - const auto takeAfter = std::min(hasAfter, limit); - auto ids = std::vector(); - ids.reserve(takeBefore + takeAfter); - for (auto j = i - takeBefore; j != i + takeAfter; ++j) { - ids.push_back(*j); - } - const auto added = int(ids.size()); - state->slice = StoriesIdsSlice( - std::move(ids), - count, - (hasBefore - takeBefore), - count - hasBefore - added); - consumer.put_next_copy(state->slice); - }; - const auto schedule = [=] { - if (state->scheduled) { - return; - } - state->scheduled = true; - Ui::PostponeCall(&state->guard, [=] { - if (state->scheduled) { - push(); - } - }); - }; - - const auto peerId = peer->id; - const auto stories = &peer->owner().stories(); - stories->archiveChanged( - ) | rpl::start_with_next(schedule, lifetime); - - if (!stories->archiveCountKnown(peerId)) { - stories->archiveLoadMore(peerId); + if (!stories->albumIdsCountKnown(peerId, albumId)) { + stories->albumIdsLoadMore(peerId, albumId); } push(); diff --git a/Telegram/SourceFiles/data/data_stories_ids.h b/Telegram/SourceFiles/data/data_stories_ids.h index 88a5103b3b..67d651ca53 100644 --- a/Telegram/SourceFiles/data/data_stories_ids.h +++ b/Telegram/SourceFiles/data/data_stories_ids.h @@ -19,13 +19,9 @@ namespace Data { using StoriesIdsSlice = AbstractSparseIds>; -[[nodiscard]] rpl::producer SavedStoriesIds( - not_null peer, - StoryId aroundId, - int limit); - -[[nodiscard]] rpl::producer ArchiveStoriesIds( +[[nodiscard]] rpl::producer AlbumStoriesIds( not_null peer, + int albumId, StoryId aroundId, int limit); diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index a5ed7ee279..9ff972022d 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -824,9 +824,12 @@ void TopBarWidget::setActiveChat( if (const auto channel = peer->asChannel()) { if (channel->canEditStories() - && !channel->owner().stories().archiveCountKnown( - channel->id)) { - channel->owner().stories().archiveLoadMore(channel->id); + && !channel->owner().stories().albumIdsCountKnown( + channel->id, + Data::kStoriesAlbumIdArchive)) { + channel->owner().stories().albumIdsLoadMore( + channel->id, + Data::kStoriesAlbumIdArchive); } } } diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp index 449c942eaf..9fb1b5447d 100644 --- a/Telegram/SourceFiles/info/info_controller.cpp +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -299,6 +299,10 @@ Controller::Controller( setupTopicViewer(); } +void Controller::replaceKey(Key key) { + _key = key; +} + void Controller::setupMigrationViewer() { const auto peer = _key.peer(); if (_key.topic() diff --git a/Telegram/SourceFiles/info/info_controller.h b/Telegram/SourceFiles/info/info_controller.h index 59b9f2ce24..7e3fff34d5 100644 --- a/Telegram/SourceFiles/info/info_controller.h +++ b/Telegram/SourceFiles/info/info_controller.h @@ -293,6 +293,7 @@ public: return _section; } + void replaceKey(Key key); [[nodiscard]] bool validateMementoPeer( not_null memento) const; diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.cpp b/Telegram/SourceFiles/info/media/info_media_buttons.cpp index ad908c7e43..f40a2851b0 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.cpp +++ b/Telegram/SourceFiles/info/media/info_media_buttons.cpp @@ -246,8 +246,9 @@ not_null AddStoriesButton( not_null navigation, not_null peer, Ui::MultiSlideTracker &tracker) { - auto count = rpl::single(0) | rpl::then(Data::SavedStoriesIds( + auto count = rpl::single(0) | rpl::then(Data::AlbumStoriesIds( peer, + 0, // = Data::kStoriesAlbumIdSaved ServerMaxStoryId - 1, 0 ) | rpl::map([](const Data::StoriesIdsSlice &slice) { diff --git a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp index b09962071c..4b6fbaa341 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.cpp @@ -105,22 +105,32 @@ void EmptyWidget::paintEvent(QPaintEvent *e) { InnerWidget::InnerWidget( QWidget *parent, - not_null controller) + not_null controller, + rpl::producer albumId, + int addingToAlbumId) : RpWidget(parent) , _controller(controller) , _peer(controller->key().storiesPeer()) -, _addingToAlbumId(0) -, _albumId(controller->key().storiesAlbumId()) +, _addingToAlbumId(addingToAlbumId) +, _albumId(std::move(albumId)) , _albumChanges(Data::StoryAlbumUpdate{ .peer = _peer, .albumId = _addingToAlbumId, }) , _empty(this) { _empty->heightValue( - ) | rpl::start_with_next( - [this] { refreshHeight(); }, - _empty->lifetime()); - _list = setupList(); + ) | rpl::start_with_next([=] { + refreshHeight(); + }, _empty->lifetime()); + setupList(); + + _albumId.changes( + ) | rpl::start_with_next([=](int albumId) { + _list.destroy(); + _controller->replaceKey(Key(Tag(_peer, albumId))); + setupList(); + resizeToWidth(width()); + }, lifetime()); } void InnerWidget::setupAlbums() { @@ -200,19 +210,20 @@ void InnerWidget::addArchiveButton(Ui::MultiSlideTracker &tracker) { const auto stories = &_peer->owner().stories(); - if (!stories->archiveCountKnown(_peer->id)) { - stories->archiveLoadMore(_peer->id); + constexpr auto kArchive = Data::kStoriesAlbumIdArchive; + if (!stories->albumIdsCountKnown(_peer->id, kArchive)) { + stories->albumIdsLoadMore(_peer->id, kArchive); } auto count = rpl::single( rpl::empty ) | rpl::then( - stories->archiveChanged( + stories->albumIdsChanged( ) | rpl::filter( - rpl::mappers::_1 == _peer->id + rpl::mappers::_1 == Data::StoryAlbumIdsKey{ _peer->id, kArchive } ) | rpl::to_empty ) | rpl::map([=] { - return stories->archiveCount(_peer->id); + return stories->albumIdsCount(_peer->id, kArchive); }) | rpl::start_spawning(_top->lifetime()); const auto archiveWrap = _top->add( @@ -228,8 +239,7 @@ void InnerWidget::addArchiveButton(Ui::MultiSlideTracker &tracker) { const auto archive = archiveWrap->entity(); archive->addClickHandler([=] { - _controller->showSection( - Make(_peer, Data::kStoriesAlbumIdArchive)); + _controller->showSection(Make(_peer, kArchive)); }); auto label = rpl::duplicate( count @@ -401,27 +411,30 @@ bool InnerWidget::showInternal(not_null memento) { return false; } -object_ptr InnerWidget::setupList() { - auto result = object_ptr( +void InnerWidget::setupList() { + Expects(!_list); + + _list = object_ptr( this, _controller); - result->heightValue( - ) | rpl::start_with_next( - [this] { refreshHeight(); }, - result->lifetime()); + const auto raw = _list.data(); + + raw->heightValue( + ) | rpl::start_with_next([=] { + refreshHeight(); + }, raw->lifetime()); using namespace rpl::mappers; - result->scrollToRequests( - ) | rpl::map([widget = result.data()](int to) { + raw->scrollToRequests( + ) | rpl::map([=](int to) { return Ui::ScrollToRequest { - widget->y() + to, + raw->y() + to, -1 }; - }) | rpl::start_to_stream( - _scrollToRequests, - result->lifetime()); - _selectedLists.fire(result->selectedListValue()); - _listTops.fire(result->topValue()); - return result; + }) | rpl::start_to_stream(_scrollToRequests, raw->lifetime()); + _selectedLists.fire(raw->selectedListValue()); + _listTops.fire(raw->topValue()); + + raw->show(); } void InnerWidget::refreshAlbumsTabs() { @@ -435,6 +448,7 @@ void InnerWidget::refreshAlbumsTabs() { return; } auto tabs = std::vector(); + auto selected = QString(); if (!_albums.empty()) { tabs.push_back({ .id = u"all"_q, @@ -449,6 +463,12 @@ void InnerWidget::refreshAlbumsTabs() { .id = QString::number(album.id), .text = std::move(title), }); + if (_albumId.current() == album.id) { + selected = tabs.back().id; + } + } + if (selected.isEmpty()) { + selected = tabs.front().id; } } if (_peer->canEditStories()) { @@ -461,7 +481,7 @@ void InnerWidget::refreshAlbumsTabs() { _albumsTabs = std::make_unique( _albumsWrap, Ui::SubTabs::Options{ - .selected = _albums.empty() ? QString() : u"all"_q, + .selected = selected, .centered = true, }, std::move(tabs)); @@ -490,10 +510,7 @@ void InnerWidget::refreshAlbumsTabs() { added)); } else { _albumsTabs->setActiveTab(id); - - //auto now = _descriptor.current(); - //now.collectionId = (id == u"all"_q) ? 0 : id.toInt(); - //_descriptorChanges.fire(std::move(now)); + _albumIdChanges.fire((id == u"all"_q) ? 0 : id.toInt()); } }, _albumsTabs->lifetime()); @@ -508,6 +525,9 @@ void InnerWidget::refreshAlbumsTabs() { }, _albumsTabs->lifetime()); } else { _albumsTabs->setTabs(std::move(tabs)); + if (!selected.isEmpty()) { + _albumsTabs->setActiveTab(selected); + } } resizeToWidth(width()); } @@ -533,6 +553,10 @@ void InnerWidget::showMenuForAlbum(int id) { _menu->popup(QCursor::pos()); } +rpl::producer InnerWidget::albumIdChanges() const { + return _albumIdChanges.events(); +} + rpl::producer InnerWidget::changes() const { return _albumChanges.value(); } @@ -562,7 +586,9 @@ void InnerWidget::editAlbumStories(int id) { const auto content = box->addRow( object_ptr( box, - _controller/*, + _controller, + rpl::single(Data::kStoriesAlbumIdArchive), + id/*, _peer, state->descriptor.value(), id, diff --git a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h index cda2fac090..7af0cf100d 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h +++ b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h @@ -45,7 +45,11 @@ class EmptyWidget; class InnerWidget final : public Ui::RpWidget { public: - InnerWidget(QWidget *parent, not_null controller); + InnerWidget( + QWidget *parent, + not_null controller, + rpl::producer albumId, + int addingToAlbumId = 0); ~InnerWidget(); bool showInternal(not_null memento); @@ -69,6 +73,7 @@ public: void confirmDeleteAlbum(int id); void albumAdded(Data::StoryAlbum result); + [[nodiscard]] rpl::producer albumIdChanges() const; [[nodiscard]] rpl::producer changes() const; protected: @@ -82,6 +87,7 @@ private: void refreshHeight(); void setupTop(); + void setupList(); void setupAlbums(); void createButtons(); void createProfileTop(); @@ -93,8 +99,6 @@ private: void addGiftsButton(Ui::MultiSlideTracker &tracker); void finalizeTop(); - [[nodiscard]] object_ptr setupList(); - void refreshAlbumsTabs(); void showMenuForAlbum(int id); @@ -107,6 +111,7 @@ private: std::vector _albums; rpl::variable _albumId; + rpl::event_stream _albumIdChanges; Ui::RpWidget *_albumsWrap = nullptr; std::unique_ptr _albumsTabs; rpl::variable _albumChanges; diff --git a/Telegram/SourceFiles/info/stories/info_stories_provider.cpp b/Telegram/SourceFiles/info/stories/info_stories_provider.cpp index b33bd12062..d81bb06821 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_provider.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_provider.cpp @@ -179,10 +179,8 @@ void Provider::setSearchQuery(QString query) { void Provider::refreshViewer() { _viewerLifetime.destroy(); - const auto idForViewer = _aroundId; - auto ids = (_albumId == Data::kStoriesAlbumIdArchive) - ? Data::ArchiveStoriesIds(_peer, idForViewer, _idsLimit) - : Data::SavedStoriesIds(_peer, idForViewer, _idsLimit); // #TODO stories + const auto aroundId = _aroundId; + auto ids = Data::AlbumStoriesIds(_peer, _albumId, aroundId, _idsLimit); std::move( ids ) | rpl::start_with_next([=](Data::StoriesIdsSlice &&slice) { @@ -195,8 +193,8 @@ void Provider::refreshViewer() { auto nearestId = std::optional(); for (auto i = 0; i != _slice.size(); ++i) { if (!nearestId - || std::abs(*nearestId - idForViewer) - > std::abs(_slice[i] - idForViewer)) { + || std::abs(*nearestId - aroundId) + > std::abs(_slice[i] - aroundId)) { nearestId = _slice[i]; } } diff --git a/Telegram/SourceFiles/info/stories/info_stories_widget.cpp b/Telegram/SourceFiles/info/stories/info_stories_widget.cpp index f861636331..1835a0a336 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_widget.cpp +++ b/Telegram/SourceFiles/info/stories/info_stories_widget.cpp @@ -52,10 +52,17 @@ object_ptr Memento::createWidget( Widget::Widget( QWidget *parent, not_null controller) -: ContentWidget(parent, controller) { +: ContentWidget(parent, controller) +, _albumId(controller->key().storiesAlbumId()) { _inner = setInnerWidget(object_ptr( this, - controller)); + controller, + _albumId.value())); + _inner->albumIdChanges() | rpl::start_with_next([=](int id) { + controller->showSection( + Make(controller->storiesPeer(), id), + Window::SectionShow::Way::Backward); + }, _inner->lifetime()); _inner->setScrollHeightValue(scrollHeightValue()); _inner->scrollToRequests( ) | rpl::start_with_next([this](Ui::ScrollToRequest request) { @@ -73,10 +80,15 @@ bool Widget::showInternal(not_null memento) { return false; } if (auto storiesMemento = dynamic_cast(memento.get())) { - const auto albumId = controller()->key().storiesAlbumId(); - if (storiesMemento->storiesAlbumId() == albumId) { + const auto myId = controller()->key().storiesAlbumId(); + const auto hisId = storiesMemento->storiesAlbumId(); + constexpr auto kArchive = Data::kStoriesAlbumIdArchive; + if (myId == hisId) { restoreState(storiesMemento); return true; + } else if (myId != kArchive && hisId != kArchive) { + _albumId = hisId; + return true; } } return false; diff --git a/Telegram/SourceFiles/info/stories/info_stories_widget.h b/Telegram/SourceFiles/info/stories/info_stories_widget.h index 5a194917c6..84911ceb49 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_widget.h +++ b/Telegram/SourceFiles/info/stories/info_stories_widget.h @@ -64,6 +64,7 @@ private: std::shared_ptr doCreateMemento() override; + rpl::variable _albumId; InnerWidget *_inner = nullptr; }; diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index d1e78cf793..2b473eb935 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -705,22 +705,15 @@ void Controller::rebuildFromContext( source = stories.source(peerId); hideSiblings(); }, [&](StoriesContextAlbum album) { - const auto archive = (album.id == Data::kStoriesAlbumIdArchive); - const auto known = archive - ? stories.archiveCountKnown(peerId) - : stories.savedCountKnown(peerId); + const auto known = stories.albumIdsCountKnown(peerId, album.id); if (known) { - const auto &ids = archive - ? stories.archive(peerId) - : stories.saved(peerId); + const auto &ids = stories.albumIds(peerId, album.id); auto sorted = RespectingPinned(ids); const auto i = ranges::find(sorted, id); const auto tillEnd = int(end(sorted) - i); if (tillEnd > 0) { _index = int(i - begin(sorted)); - const auto total = archive - ? stories.archiveCount(peerId) - : stories.savedCount(peerId); + const auto total = stories.albumIdsCount(peerId, album.id); list = StoriesList{ .peer = peer, .ids = ids, @@ -729,11 +722,7 @@ void Controller::rebuildFromContext( }; if (ids.list.size() < list->total && tillEnd < kPreloadStoriesCount) { - if (archive) { - stories.archiveLoadMore(peerId); - } else { - stories.savedLoadMore(peerId); - } + stories.albumIdsLoadMore(peerId, album.id); } } } @@ -854,20 +843,13 @@ void Controller::show( }, [&](Data::StoriesContextPeer) { subscribeToSource(); }, [&](Data::StoriesContextAlbum album) { - if (album.id == Data::kStoriesAlbumIdArchive) { - stories.archiveChanged( - ) | rpl::start_with_next([=] { - rebuildFromContext(peer, storyId); - checkMoveByDelta(); - }, _contextLifetime); - } else { - stories.savedChanged() | rpl::filter( - rpl::mappers::_1 == storyId.peer - ) | rpl::start_with_next([=] { - rebuildFromContext(peer, storyId); - checkMoveByDelta(); - }, _contextLifetime); - } + const auto key = Data::StoryAlbumIdsKey{ storyId.peer, album.id }; + stories.albumIdsChanged() | rpl::filter( + rpl::mappers::_1 == key + ) | rpl::start_with_next([=] { + rebuildFromContext(peer, storyId); + checkMoveByDelta(); + }, _contextLifetime); }, [&](Data::StorySourcesList) { subscribeToSource(); }); @@ -1597,11 +1579,7 @@ void Controller::loadMoreToList() { const auto peerId = _shown.peer; auto &stories = peer->owner().stories(); v::match(_context.data, [&](StoriesContextAlbum album) { - if (album.id == Data::kStoriesAlbumIdArchive) { - stories.archiveLoadMore(peerId); - } else { - stories.savedLoadMore(peerId); // #TODO stories - } + stories.albumIdsLoadMore(peerId, album.id); }, [](const auto &) { }); }