From 881867186a3e0e714c9a780deb7688a11adb5386 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 13 Jun 2023 19:51:08 +0400 Subject: [PATCH] Load more saved / archive in the viewer. --- .../data/data_document_resolver.cpp | 5 +- Telegram/SourceFiles/data/data_stories.cpp | 3 +- .../SourceFiles/data/data_stories_ids.cpp | 4 +- .../admin_log/history_admin_log_inner.cpp | 6 +- .../history/history_inner_widget.cpp | 6 +- .../SourceFiles/history/history_widget.cpp | 4 +- .../history_view_compose_controls.cpp | 4 +- .../view/history_view_pinned_section.cpp | 4 +- .../view/history_view_replies_section.cpp | 7 +- .../view/history_view_scheduled_section.cpp | 4 +- .../info/media/info_media_list_widget.cpp | 22 +- .../stories/media_stories_controller.cpp | 263 ++++++++++++++---- .../media/stories/media_stories_controller.h | 21 ++ .../window/window_session_controller.cpp | 41 +-- .../window/window_session_controller.h | 16 +- 15 files changed, 301 insertions(+), 109 deletions(-) diff --git a/Telegram/SourceFiles/data/data_document_resolver.cpp b/Telegram/SourceFiles/data/data_document_resolver.cpp index 2a03aaa7c..2839eeb76 100644 --- a/Telegram/SourceFiles/data/data_document_resolver.cpp +++ b/Telegram/SourceFiles/data/data_document_resolver.cpp @@ -254,7 +254,10 @@ void ResolveDocument( && !document->filepath().isEmpty()) { File::Launch(document->location(false).fname); } else if (controller) { - controller->openDocument(document, msgId, topicRootId, true); + controller->openDocument( + document, + true, + { msgId, topicRootId }); } }; diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index 3952f9712..dedc741f9 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -1109,8 +1109,7 @@ void Stories::markAsRead(FullStoryId id, bool viewed) { } } const auto i = _all.find(id.peer); - Assert(i != end(_all)); - if (i->second.readTill >= id.story) { + if (i == end(_all) || i->second.readTill >= id.story) { return; } else if (!_markReadPending.contains(id.peer)) { sendMarkAsReadRequests(); diff --git a/Telegram/SourceFiles/data/data_stories_ids.cpp b/Telegram/SourceFiles/data/data_stories_ids.cpp index 7506abea5..31604f2eb 100644 --- a/Telegram/SourceFiles/data/data_stories_ids.cpp +++ b/Telegram/SourceFiles/data/data_stories_ids.cpp @@ -44,7 +44,7 @@ rpl::producer SavedStoriesIds( const auto hasBefore = int(around - begin(saved->list)); const auto hasAfter = int(end(saved->list) - around); if (hasAfter < limit) { - stories->savedLoadMore(peer->id); + //stories->savedLoadMore(peer->id); } const auto takeBefore = std::min(hasBefore, limit); const auto takeAfter = std::min(hasAfter, limit); @@ -116,7 +116,7 @@ rpl::producer ArchiveStoriesIds( const auto hasBefore = int(i - begin(archive.list)); const auto hasAfter = int(end(archive.list) - i); if (hasAfter < limit) { - stories->archiveLoadMore(); + //stories->archiveLoadMore(); } const auto takeBefore = std::min(hasBefore, limit); const auto takeAfter = std::min(hasAfter, limit); 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 ec8f4c593..f6e5c92d5 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -610,14 +610,14 @@ void InnerWidget::elementShowPollResults( void InnerWidget::elementOpenPhoto( not_null photo, FullMsgId context) { - _controller->openPhoto(photo, context, MsgId(0)); + _controller->openPhoto(photo, { context }); } void InnerWidget::elementOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - _controller->openDocument(document, context, MsgId(0), showInMediaView); + _controller->openDocument(document, showInMediaView, { context }); } void InnerWidget::elementCancelUpload(const FullMsgId &context) { @@ -1380,7 +1380,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, MsgId(), true); + _controller->openDocument(document, true, { itemId }); } } } diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 8d0d8b980..36a1a29e6 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2779,7 +2779,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, MsgId(), true); + _controller->openDocument(document, true, { itemId }); } } } @@ -3376,14 +3376,14 @@ void HistoryInner::elementShowPollResults( void HistoryInner::elementOpenPhoto( not_null photo, FullMsgId context) { - _controller->openPhoto(photo, context, MsgId(0)); + _controller->openPhoto(photo, { context }); } void HistoryInner::elementOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - _controller->openDocument(document, context, MsgId(0), showInMediaView); + _controller->openDocument(document, showInMediaView, { context }); } void HistoryInner::elementCancelUpload(const FullMsgId &context) { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 61c7c7237..8e50593be 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1467,9 +1467,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, {}, {}); + controller()->openPhoto(photo, {}); } else if (const auto document = request.document()) { - controller()->openDocument(document, {}, {}); + controller()->openDocument(document, false, {}); } } else { sendInlineResult(result); 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 c53650919..2b5523b28 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -3059,9 +3059,9 @@ void ComposeControls::applyInlineBotQuery( if (result.open) { const auto request = result.result->openRequest(); if (const auto photo = request.photo()) { - _regularWindow->openPhoto(photo, {}, {}); + _regularWindow->openPhoto(photo, {}); } else if (const auto document = request.document()) { - _regularWindow->openDocument(document, {}, {}); + _regularWindow->openDocument(document, false, {}); } } else { _inlineResultChosen.fire_copy(result); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 2a5cd65be..263d057ff 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -643,14 +643,14 @@ void PinnedWidget::listShowPremiumToast(not_null document) { void PinnedWidget::listOpenPhoto( not_null photo, FullMsgId context) { - controller()->openPhoto(photo, context, MsgId()); + controller()->openPhoto(photo, { context }); } void PinnedWidget::listOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - controller()->openDocument(document, context, MsgId(), showInMediaView); + controller()->openDocument(document, showInMediaView, { context }); } void PinnedWidget::listPaintEmpty( diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 4813dcc5b..65c9e503a 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -2553,14 +2553,17 @@ void RepliesWidget::listShowPremiumToast(not_null document) { void RepliesWidget::listOpenPhoto( not_null photo, FullMsgId context) { - controller()->openPhoto(photo, context, _rootId); + controller()->openPhoto(photo, { context, _rootId }); } void RepliesWidget::listOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - controller()->openDocument(document, context, _rootId, showInMediaView); + controller()->openDocument( + document, + showInMediaView, + { context, _rootId }); } void RepliesWidget::listPaintEmpty( diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index c8966ad9c..ca5e7b8bd 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -1290,14 +1290,14 @@ void ScheduledWidget::listShowPremiumToast( void ScheduledWidget::listOpenPhoto( not_null photo, FullMsgId context) { - controller()->openPhoto(photo, context, MsgId()); + controller()->openPhoto(photo, { context }); } void ScheduledWidget::listOpenDocument( not_null document, FullMsgId context, bool showInMediaView) { - controller()->openDocument(document, context, MsgId(), showInMediaView); + controller()->openDocument(document, showInMediaView, { context }); } void ScheduledWidget::listPaintEmpty( diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 9909cb23a..7940bca59 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer_values.h" #include "data/data_document.h" #include "data/data_session.h" +#include "data/data_stories.h" #include "data/data_file_click_handler.h" #include "data/data_file_origin.h" #include "data/data_download_manager.h" @@ -476,18 +477,31 @@ bool ListWidget::tooltipWindowActive() const { } void ListWidget::openPhoto(not_null photo, FullMsgId id) { - _controller->parentController()->openPhoto(photo, id, topicRootId()); + using namespace Data; + + const auto tab = _controller->storiesTab(); + const auto context = (tab == Stories::Tab::Archive) + ? Data::StoriesContext{ Data::StoriesContextArchive() } + : Data::StoriesContext{ Data::StoriesContextSaved() }; + _controller->parentController()->openPhoto( + photo, + { id, topicRootId() }, + _controller->storiesPeer() ? &context : nullptr); } void ListWidget::openDocument( not_null document, FullMsgId id, bool showInMediaView) { + const auto tab = _controller->storiesTab(); + const auto context = (tab == Stories::Tab::Archive) + ? Data::StoriesContext{ Data::StoriesContextArchive() } + : Data::StoriesContext{ Data::StoriesContextSaved() }; _controller->parentController()->openDocument( document, - id, - topicRootId(), - showInMediaView); + showInMediaView, + { id, topicRootId() }, + _controller->storiesPeer() ? &context : nullptr); } void ListWidget::trackSession(not_null session) { diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 3e6828ddf..7a187bcf8 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -48,6 +48,7 @@ constexpr auto kSiblingOutsidePart = 0.24; constexpr auto kSiblingUserpicSize = 0.3; constexpr auto kInnerHeightMultiplier = 1.6; constexpr auto kPreloadUsersCount = 3; +constexpr auto kPreloadStoriesCount = 5; constexpr auto kMarkAsReadAfterSeconds = 1; constexpr auto kMarkAsReadAfterProgress = 0.2; @@ -432,48 +433,142 @@ auto Controller::cachedReactionIconFactory() const return _delegate->storiesCachedReactionIconFactory(); } -void Controller::show( - not_null story, - Data::StoriesContext context) { +void Controller::rebuildFromContext( + not_null user, + FullStoryId storyId) { using namespace Data; - auto &stories = story->owner().stories(); - const auto storyId = story->fullId(); + auto &stories = user->owner().stories(); + auto list = std::optional(); + auto source = (const StoriesSource*)nullptr; + const auto peerId = storyId.peer; const auto id = storyId.story; - auto source = stories.source(storyId.peer); - auto single = StoriesSource{ story->peer()->asUser() }; - v::match(context.data, [&](StoriesContextSingle) { - source = nullptr; + v::match(_context.data, [&](StoriesContextSingle) { hideSiblings(); }, [&](StoriesContextPeer) { + source = stories.source(peerId); hideSiblings(); }, [&](StoriesContextSaved) { + if (stories.savedCountKnown(peerId)) { + if (const auto saved = stories.saved(peerId)) { + const auto &ids = saved->list; + const auto i = ids.find(id); + if (i != end(ids)) { + list = StoriesList{ + .user = user, + .ids = *saved, + .total = stories.savedCount(peerId), + }; + _index = int(i - begin(ids)); + if (ids.size() < list->total + && (end(ids) - i) < kPreloadStoriesCount) { + stories.savedLoadMore(peerId); + } + } + } + } hideSiblings(); }, [&](StoriesContextArchive) { + Expects(user->isSelf()); + + if (stories.archiveCountKnown()) { + const auto &archive = stories.archive(); + const auto &ids = archive.list; + const auto i = ids.find(id); + if (i != end(ids)) { + list = StoriesList{ + .user = user, + .ids = archive, + .total = stories.archiveCount(), + }; + _index = int(i - begin(ids)); + if (ids.size() < list->total + && (end(ids) - i) < kPreloadStoriesCount) { + stories.archiveLoadMore(); + } + } + } hideSiblings(); }, [&](StorySourcesList list) { + source = stories.source(peerId); const auto &sources = stories.sources(list); const auto i = ranges::find( sources, storyId.peer, &StoriesSourceInfo::id); - if (i == end(sources)) { - source = nullptr; - return; - } - showSiblings(&story->session(), sources, (i - begin(sources))); - - if (int(sources.end() - i) < kPreloadUsersCount) { - stories.loadMore(list); + if (i != end(sources)) { + showSiblings(&user->session(), sources, (i - begin(sources))); + if (int(sources.end() - i) < kPreloadUsersCount) { + stories.loadMore(list); + } } }); - const auto idDates = story->idDates(); - _index = source ? (source->ids.find(idDates) - begin(source->ids)) : 0; - if (!source || _index == source->ids.size()) { - source = &single; - single.ids.emplace(idDates); - _index = 0; + if (list) { + _source = std::nullopt; + if (_list != list) { + _list = std::move(list); + } + } else { + if (source) { + const auto i = source->ids.lower_bound(StoryIdDates{ id }); + if (i != end(source->ids) && i->id == id) { + _index = int(i - begin(source->ids)); + } else { + source = nullptr; + } + } + if (!source) { + _source = std::nullopt; + _list = StoriesList{ + .user = user, + .ids = { { id } }, + .total = 1, + }; + _index = 0; + } else { + _list = std::nullopt; + if (_source != *source) { + _source = *source; + } + } } + _slider->show({ .index = _index, .total = shownCount() }); +} + +void Controller::checkMoveByDelta() { + const auto index = _index + _waitingForDelta; + if (_waitingForDelta && shown() && index >= 0 && index < shownCount()) { + subjumpTo(index); + } +} + +void Controller::show( + not_null story, + Data::StoriesContext context) { + auto &stories = story->owner().stories(); + const auto storyId = story->fullId(); + const auto user = story->peer()->asUser(); + _context = context; + _waitingForId = {}; + _waitingForDelta = 0; + + rebuildFromContext(user, storyId); + _contextLifetime.destroy(); + v::match(_context.data, [&](Data::StoriesContextSaved) { + stories.savedChanged() | rpl::filter( + rpl::mappers::_1 == storyId.peer + ) | rpl::start_with_next([=] { + rebuildFromContext(user, storyId); + checkMoveByDelta(); + }, _contextLifetime); + }, [&](Data::StoriesContextArchive) { + stories.archiveChanged( + ) | rpl::start_with_next([=] { + rebuildFromContext(user, storyId); + checkMoveByDelta(); + }, _contextLifetime); + }, [](const auto &) {}); + const auto guard = gsl::finally([&] { _paused = false; _started = false; @@ -483,11 +578,7 @@ void Controller::show( _photoPlayback = nullptr; } }); - if (_source != *source) { - _source = *source; - } - _context = context; - _waitingForId = {}; + if (_shown == storyId) { return; } @@ -501,13 +592,12 @@ void Controller::show( unfocusReply(); } - _header->show({ .user = source->user, .date = story->date() }); - _slider->show({ .index = _index, .total = int(source->ids.size()) }); - _replyArea->show({ .user = source->user, .id = id }); + _header->show({ .user = user, .date = story->date() }); + _replyArea->show({ .user = user, .id = story->id() }); _recentViews->show({ .list = story->recentViewers(), .total = story->views(), - .valid = source->user->isSelf(), + .valid = user->isSelf(), }); const auto session = &story->session(); @@ -531,7 +621,7 @@ void Controller::show( stories.loadAround(storyId, context); updatePlayingAllowed(); - source->user->updateFull(); + user->updateFull(); } void Controller::updatePlayingAllowed() { @@ -634,23 +724,23 @@ void Controller::maybeMarkAsRead(const Player::TrackState &state) { } void Controller::markAsRead() { - Expects(_source.has_value()); + Expects(shown()); if (_viewed) { return; } _viewed = true; - _source->user->owner().stories().markAsRead(_shown, _started); + shownUser()->owner().stories().markAsRead(_shown, _started); } bool Controller::subjumpAvailable(int delta) const { const auto index = _index + delta; if (index < 0) { return _siblingLeft && _siblingLeft->shownId().valid(); - } else if (index >= int(_source->ids.size())) { + } else if (index >= shownCount()) { return _siblingRight && _siblingRight->shownId().valid(); } - return index >= 0 && index < int(_source->ids.size()); + return index >= 0 && index < shownCount(); } bool Controller::subjumpFor(int delta) { @@ -661,12 +751,12 @@ bool Controller::subjumpFor(int delta) { if (index < 0) { if (_siblingLeft && _siblingLeft->shownId().valid()) { return jumpFor(-1); - } else if (!_source || _source->ids.empty()) { + } else if (!shown() || !shownCount()) { return false; } subjumpTo(0); return true; - } else if (index >= int(_source->ids.size())) { + } else if (index >= shownCount()) { return _siblingRight && _siblingRight->shownId().valid() && jumpFor(1); @@ -677,27 +767,37 @@ bool Controller::subjumpFor(int delta) { } void Controller::subjumpTo(int index) { - Expects(_source.has_value()); - Expects(index >= 0 && index < _source->ids.size()); + Expects(shown()); + Expects(index >= 0 && index < shownCount()); + const auto user = shownUser(); const auto id = FullStoryId{ - .peer = _source->user->id, - .story = (begin(_source->ids) + index)->id, + .peer = user->id, + .story = shownId(index), }; - auto &stories = _source->user->owner().stories(); - if (stories.lookup(id)) { - _delegate->storiesJumpTo(&_source->user->session(), id, _context); + auto &stories = user->owner().stories(); + if (!id.story) { + const auto delta = index - _index; + if (_waitingForDelta != delta) { + _waitingForDelta = delta; + _waitingForId = {}; + loadMoreToList(); + } + } else if (stories.lookup(id)) { + _delegate->storiesJumpTo(&user->session(), id, _context); } else if (_waitingForId != id) { _waitingForId = id; + _waitingForDelta = 0; stories.loadAround(id, _context); } } void Controller::checkWaitingFor() { Expects(_waitingForId.valid()); - Expects(_source.has_value()); + Expects(shown()); - auto &stories = _source->user->owner().stories(); + const auto user = shownUser(); + auto &stories = user->owner().stories(); const auto maybe = stories.lookup(_waitingForId); if (!maybe) { if (maybe.error() == Data::NoStory::Deleted) { @@ -706,7 +806,7 @@ void Controller::checkWaitingFor() { return; } _delegate->storiesJumpTo( - &_source->user->session(), + &user->session(), base::take(_waitingForId), _context); } @@ -721,7 +821,7 @@ bool Controller::jumpFor(int delta) { return true; } } else if (delta == 1) { - if (_source && _index + 1 >= int(_source->ids.size())) { + if (shown() && _index + 1 >= shownCount()) { markAsRead(); } if (const auto right = _siblingRight.get()) { @@ -817,7 +917,8 @@ Fn)> Controller::viewsGotMoreCallback() { return crl::guard(&_viewsLoadGuard, [=]( const std::vector &result) { if (_viewsSlice.list.empty()) { - auto &stories = _source->user->owner().stories(); + const auto user = shownUser(); + auto &stories = user->owner().stories(); if (const auto maybeStory = stories.lookup(_shown)) { _viewsSlice = { .list = result, @@ -838,12 +939,57 @@ Fn)> Controller::viewsGotMoreCallback() { }); } -void Controller::refreshViewsFromData() { - Expects(_source.has_value()); +bool Controller::shown() const { + return _source || _list; +} - auto &stories = _source->user->owner().stories(); +UserData *Controller::shownUser() const { + return _source + ? _source->user.get() + : _list + ? _list->user.get() + : nullptr; +} + +int Controller::shownCount() const { + return _source ? int(_source->ids.size()) : _list ? _list->total : 0; +} + +StoryId Controller::shownId(int index) const { + Expects(index >= 0 && index < shownCount()); + + return _source + ? (_source->ids.begin() + index)->id + : (index < int(_list->ids.list.size())) + ? *(_list->ids.list.begin() + index) + : StoryId(); +} + +void Controller::loadMoreToList() { + Expects(shown()); + + using namespace Data; + + const auto user = shownUser(); + const auto peerId = _shown.peer; + auto &stories = user->owner().stories(); + v::match(_context.data, [&](StoriesContextSaved) { + stories.savedLoadMore(peerId); + }, [&](StoriesContextArchive) { + Expects(user->isSelf()); + + stories.archiveLoadMore(); + }, [](const auto &) { + }); +} + +void Controller::refreshViewsFromData() { + Expects(shown()); + + const auto user = shownUser(); + auto &stories = user->owner().stories(); const auto maybeStory = stories.lookup(_shown); - if (!maybeStory || !_source->user->isSelf()) { + if (!maybeStory || !user->isSelf()) { _viewsSlice = {}; return; } @@ -861,11 +1007,12 @@ void Controller::refreshViewsFromData() { } bool Controller::sliceViewsTo(PeerId offset) { - Expects(_source.has_value()); + Expects(shown()); - auto &stories = _source->user->owner().stories(); + const auto user = shownUser(); + auto &stories = user->owner().stories(); const auto maybeStory = stories.lookup(_shown); - if (!maybeStory || !_source->user->isSelf()) { + if (!maybeStory || !user->isSelf()) { _viewsSlice = {}; return true; } diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.h b/Telegram/SourceFiles/media/stories/media_stories_controller.h index 5c83202c8..277140db0 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.h +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.h @@ -135,6 +135,15 @@ public: [[nodiscard]] rpl::lifetime &lifetime(); private: + struct StoriesList { + not_null user; + Data::StoriesIds ids; + int total = 0; + + friend inline bool operator==( + const StoriesList &, + const StoriesList &) = default; + }; class PhotoPlayback; void initLayout(); @@ -166,6 +175,14 @@ private: [[nodiscard]] auto viewsGotMoreCallback() -> Fn)>; + [[nodiscard]] bool shown() const; + [[nodiscard]] UserData *shownUser() const; + [[nodiscard]] int shownCount() const; + [[nodiscard]] StoryId shownId(int index) const; + void rebuildFromContext(not_null user, FullStoryId storyId); + void checkMoveByDelta(); + void loadMoreToList(); + const not_null _delegate; rpl::variable> _layout; @@ -194,7 +211,9 @@ private: TextWithEntities _captionText; Data::StoriesContext _context; std::optional _source; + std::optional _list; FullStoryId _waitingForId; + int _waitingForDelta = 0; int _index = 0; bool _started = false; bool _viewed = false; @@ -211,6 +230,8 @@ private: Main::Session *_session = nullptr; rpl::lifetime _sessionLifetime; + rpl::lifetime _contextLifetime; + rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 2d447621c..c21ef8437 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -2153,14 +2153,14 @@ void SessionController::hideLayer(anim::type animated) { void SessionController::openPhoto( not_null photo, - FullMsgId contextId, - MsgId topicRootId) { - const auto item = session().data().message(contextId); - if (openSharedStory(item) || openFakeItemStory(contextId)) { + MessageContext message, + const Data::StoriesContext *stories) { + const auto item = session().data().message(message.id); + if (openSharedStory(item) || openFakeItemStory(message.id, stories)) { return; } _window->openInMediaView( - Media::View::OpenRequest(this, photo, item, topicRootId)); + Media::View::OpenRequest(this, photo, item, message.topicRootId)); } void SessionController::openPhoto( @@ -2171,18 +2171,21 @@ void SessionController::openPhoto( void SessionController::openDocument( not_null document, - FullMsgId contextId, - MsgId topicRootId, - bool showInMediaView) { - const auto item = session().data().message(contextId); - if (openSharedStory(item) || openFakeItemStory(contextId)) { + bool showInMediaView, + MessageContext message, + const Data::StoriesContext *stories) { + const auto item = session().data().message(message.id); + if (openSharedStory(item) || openFakeItemStory(message.id, stories)) { return; } else if (showInMediaView) { - _window->openInMediaView( - Media::View::OpenRequest(this, document, item, topicRootId)); + _window->openInMediaView(Media::View::OpenRequest( + this, + document, + item, + message.topicRootId)); return; } - Data::ResolveDocument(this, document, item, topicRootId); + Data::ResolveDocument(this, document, item, message.topicRootId); } bool SessionController::openSharedStory(HistoryItem *item) { @@ -2203,7 +2206,7 @@ bool SessionController::openSharedStory(HistoryItem *item) { bool SessionController::openFakeItemStory( FullMsgId fakeItemId, - bool forceArchiveContext) { + const Data::StoriesContext *stories) { if (!peerIsUser(fakeItemId.peer) || !IsStoryMsgId(fakeItemId.msg)) { return false; @@ -2215,13 +2218,11 @@ bool SessionController::openFakeItemStory( if (maybeStory) { using namespace Data; const auto story = *maybeStory; - const auto context = !story->expired() - ? StoriesContext{ StoriesContextPeer() } - : (story->pinned() && !forceArchiveContext) - ? StoriesContext{ StoriesContextSaved() } - : StoriesContext{ StoriesContextArchive() }; + const auto context = stories + ? *stories + : StoriesContext{ StoriesContextSingle() }; _window->openInMediaView( - ::Media::View::OpenRequest(this, *maybeStory, context)); + ::Media::View::OpenRequest(this, story, context)); } return true; } diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 845cdb223..4903c6be9 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -482,20 +482,24 @@ public: void showPassportForm(const Passport::FormRequest &request); void clearPassportForm(); + struct MessageContext { + FullMsgId id; + MsgId topicRootId; + }; void openPhoto( not_null photo, - FullMsgId contextId, - MsgId topicRootId); + MessageContext message, + const Data::StoriesContext *stories = nullptr); void openPhoto(not_null photo, not_null peer); void openDocument( not_null document, - FullMsgId contextId, - MsgId topicRootId, - bool showInMediaView = false); + bool showInMediaView, + MessageContext message, + const Data::StoriesContext *stories = nullptr); bool openSharedStory(HistoryItem *item); bool openFakeItemStory( FullMsgId fakeItemId, - bool forceArchiveContext = false); + const Data::StoriesContext *stories = nullptr); void showChooseReportMessages( not_null peer,