From b71d72ca7c028e0cf5a7c34f481c515c480f03da Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 5 Jun 2023 16:10:34 +0400 Subject: [PATCH] Allow showing stories in different contexts. --- .../boxes/peer_list_controllers.cpp | 4 +- Telegram/SourceFiles/data/data_stories.cpp | 8 +- Telegram/SourceFiles/data/data_stories.h | 28 ++++- .../dialogs/ui/dialogs_stories_content.cpp | 2 +- .../dialogs/ui/dialogs_stories_list.cpp | 15 +-- .../dialogs/ui/dialogs_stories_list.h | 1 + .../SourceFiles/ffmpeg/ffmpeg_utility.cpp | 5 +- .../stories/media_stories_controller.cpp | 101 +++++++++++------- .../media/stories/media_stories_controller.h | 4 +- .../media/stories/media_stories_delegate.h | 7 +- .../media/stories/media_stories_view.cpp | 6 +- .../media/stories/media_stories_view.h | 4 +- .../media/streaming/media_streaming_common.h | 2 + .../media/streaming/media_streaming_file.cpp | 42 +++++--- .../media/streaming/media_streaming_file.h | 16 +-- .../streaming/media_streaming_player.cpp | 10 +- .../media/view/media_view_open_common.h | 20 ++-- .../media/view/media_view_overlay_widget.cpp | 43 ++++++-- .../media/view/media_view_overlay_widget.h | 16 +-- .../window/window_session_controller.cpp | 6 +- .../window/window_session_controller.h | 3 +- 21 files changed, 231 insertions(+), 112 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index dc757dc819..7fa6e5384c 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -95,7 +95,9 @@ object_ptr PrepareContactsBox( raw->clicks( ) | rpl::start_with_next([=](uint64 id) { - sessionController->openPeerStories(PeerId(int64(id)), {}); + sessionController->openPeerStories( + PeerId(int64(id)), + Data::StorySourcesList::All); }, raw->lifetime()); raw->showProfileRequests( diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index b801dad8dd..69b14f0a74 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -744,7 +744,13 @@ void Stories::resolve(FullStoryId id, Fn done) { } } -void Stories::loadAround(FullStoryId id) { +void Stories::loadAround(FullStoryId id, StoriesContext context) { + if (v::is(context.data)) { + return; + } else if (v::is(context.data) + || v::is(context.data)) { + return; + } const auto i = _all.find(id.peer); if (i == end(_all)) { return; diff --git a/Telegram/SourceFiles/data/data_stories.h b/Telegram/SourceFiles/data/data_stories.h index ded86dce36..f8f152b776 100644 --- a/Telegram/SourceFiles/data/data_stories.h +++ b/Telegram/SourceFiles/data/data_stories.h @@ -139,6 +139,32 @@ enum class StorySourcesList : uchar { All, }; +struct StoriesContextSingle { +}; + +struct StoriesContextPeer { +}; + +struct StoriesContextSaved { +}; + +struct StoriesContextArchive { +}; + +struct StoriesContext { + std::variant< + StoriesContextSingle, + StoriesContextPeer, + StoriesContextSaved, + StoriesContextArchive, + StorySourcesList> data; + + friend inline auto operator<=>( + StoriesContext, + StoriesContext) = default; + friend inline bool operator==(StoriesContext, StoriesContext) = default; +}; + inline constexpr auto kStorySourcesListCount = 2; class Stories final { @@ -159,7 +185,7 @@ public: void loadMore(StorySourcesList list); void apply(const MTPDupdateStory &data); - void loadAround(FullStoryId id); + void loadAround(FullStoryId id, StoriesContext context); [[nodiscard]] const base::flat_map &all() const; [[nodiscard]] const std::vector &sources( diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp index bb9fd75784..8309504162 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_content.cpp @@ -127,7 +127,7 @@ State::State(not_null data, Data::StorySourcesList list) } Content State::next() { - auto result = Content(); + auto result = Content{ .full = (_list == Data::StorySourcesList::All) }; const auto &all = _data->all(); const auto &sources = _data->sources(_list); result.users.reserve(sources.size()); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index 78a3dc3a37..ec470a92dd 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -265,7 +265,8 @@ List::Layout List::computeLayout() const { + st::defaultDialogRow.photoSize + st::defaultDialogRow.padding.left(); const auto narrow = (width() <= narrowWidth); - const auto smallWidth = st.photo + (itemsCount - 1) * st.shift; + const auto smallCount = std::min(kSmallUserpicsShown, itemsCount); + const auto smallWidth = st.photo + (smallCount - 1) * st.shift; const auto leftSmall = narrow ? ((narrowWidth - smallWidth) / 2 - st.photoLeft) : st.left; @@ -278,7 +279,7 @@ List::Layout List::computeLayout() const { (width() - leftFull + singleFull - 1) / singleFull, itemsCount); const auto startIndexSmall = 0; - const auto endIndexSmall = std::min(kSmallUserpicsShown, itemsCount); + const auto endIndexSmall = smallCount; const auto cellLeftSmall = leftSmall; const auto userpicLeftFull = cellLeftFull + full.photoLeft; const auto userpicLeftSmall = cellLeftSmall + st.photoLeft; @@ -714,10 +715,12 @@ void List::contextMenuEvent(QContextMenuEvent *e) { _menu->addAction(tr::lng_context_view_profile(tr::now), [=] { _showProfileRequests.fire_copy(id); }); - _menu->addAction(hidden - ? tr::lng_stories_show_in_chats(tr::now) - : tr::lng_stories_hide_to_contacts(tr::now), - [=] { _toggleShown.fire({ .id = id, .shown = hidden }); }); + if (!_content.full || hidden) { + _menu->addAction(hidden + ? tr::lng_stories_show_in_chats(tr::now) + : tr::lng_stories_hide_to_contacts(tr::now), + [=] { _toggleShown.fire({ .id = id, .shown = hidden }); }); + } const auto updateAfterMenuDestroyed = [=] { const auto globalPosition = QCursor::pos(); if (rect().contains(mapFromGlobal(globalPosition))) { diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h index 6789765dbc..4221dcbc3f 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.h @@ -37,6 +37,7 @@ struct User { struct Content { std::vector users; + bool full = false; friend inline bool operator==( const Content &a, diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp index a674a4b82e..d1642c0d4c 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp @@ -230,6 +230,7 @@ FormatPointer MakeFormatPointer( if (!io) { return {}; } + io->seekable = (seek != nullptr); auto result = avformat_alloc_context(); if (!result) { LogError(u"avformat_alloc_context"_q); @@ -250,7 +251,9 @@ FormatPointer MakeFormatPointer( LogError(u"avformat_open_input"_q, error); return {}; } - result->flags |= AVFMT_FLAG_FAST_SEEK; + if (seek) { + result->flags |= AVFMT_FLAG_FAST_SEEK; + } // Now FormatPointer will own and free the IO context. io.release(); diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 716da7feee..c343a62146 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -387,29 +387,54 @@ auto Controller::stickerOrEmojiChosen() const void Controller::show( not_null story, - Data::StorySourcesList list) { + Data::StoriesContext context) { + using namespace Data; + auto &stories = story->owner().stories(); - const auto &all = stories.all(); - const auto &sources = stories.sources(list); const auto storyId = story->fullId(); const auto id = storyId.story; - const auto i = ranges::find( - sources, - storyId.peer, - &Data::StoriesSourceInfo::id); - if (i == end(sources)) { + const auto &all = stories.all(); + const auto inAll = all.find(storyId.peer); + auto source = (inAll != end(all)) ? &inAll->second : nullptr; + auto single = StoriesSource{ story->peer()->asUser() }; + v::match(context.data, [&](StoriesContextSingle) { + source = &single; + hideSiblings(); + }, [&](StoriesContextPeer) { + hideSiblings(); + }, [&](StoriesContextSaved) { + hideSiblings(); + }, [&](StoriesContextArchive) { + hideSiblings(); + }, [&](StorySourcesList list) { + 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); + } + }); + const auto idDate = story->idDate(); + if (!source) { return; + } else if (source == &single) { + single.ids.emplace(idDate); + _index = 0; + } else { + const auto k = source->ids.find(idDate); + if (k == end(source->ids)) { + return; + } + _index = (k - begin(source->ids)); } - const auto j = all.find(storyId.peer); - if (j == end(all)) { - return; - } - const auto &source = j->second; - const auto k = source.ids.lower_bound(Data::StoryIdDate{ id }); - if (k == end(source.ids) || k->id != id) { - return; - } - showSiblings(&story->session(), sources, (i - begin(sources))); const auto guard = gsl::finally([&] { _paused = false; _started = false; @@ -419,12 +444,11 @@ void Controller::show( _photoPlayback = nullptr; } }); - if (_source != source) { - _source = source; + if (_source != *source) { + _source = *source; } - _index = (k - begin(source.ids)); + _context = context; _waitingForId = {}; - if (_shown == storyId) { return; } @@ -436,13 +460,13 @@ 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 = source->user, .date = story->date() }); + _slider->show({ .index = _index, .total = int(source->ids.size()) }); + _replyArea->show({ .user = source->user, .id = id }); _recentViews->show({ .list = story->recentViewers(), .total = story->views(), - .valid = source.user->isSelf(), + .valid = source->user->isSelf(), }); const auto session = &story->session(); @@ -463,13 +487,10 @@ void Controller::show( }, _sessionLifetime); } - if (int(sources.end() - i) < kPreloadUsersCount) { - stories.loadMore(list); - } - stories.loadAround(storyId); + stories.loadAround(storyId, context); updatePlayingAllowed(); - source.user->updateFull(); + source->user->updateFull(); } void Controller::updatePlayingAllowed() { @@ -509,6 +530,11 @@ void Controller::showSiblings( (index + 1 < sources.size()) ? sources[index + 1].id : PeerId()); } +void Controller::hideSiblings() { + _siblingLeft = nullptr; + _siblingRight = nullptr; +} + void Controller::showSibling( std::unique_ptr &sibling, not_null session, @@ -616,10 +642,10 @@ void Controller::subjumpTo(int index) { }; auto &stories = _source->user->owner().stories(); if (stories.lookup(id)) { - _delegate->storiesJumpTo(&_source->user->session(), id); + _delegate->storiesJumpTo(&_source->user->session(), id, _context); } else if (_waitingForId != id) { _waitingForId = id; - stories.loadAround(id); + stories.loadAround(id, _context); } } @@ -637,7 +663,8 @@ void Controller::checkWaitingFor() { } _delegate->storiesJumpTo( &_source->user->session(), - base::take(_waitingForId)); + base::take(_waitingForId), + _context); } bool Controller::jumpFor(int delta) { @@ -645,7 +672,8 @@ bool Controller::jumpFor(int delta) { if (const auto left = _siblingLeft.get()) { _delegate->storiesJumpTo( &left->peer()->session(), - left->shownId()); + left->shownId(), + _context); return true; } } else if (delta == 1) { @@ -655,7 +683,8 @@ bool Controller::jumpFor(int delta) { if (const auto right = _siblingRight.get()) { _delegate->storiesJumpTo( &right->peer()->session(), - right->shownId()); + right->shownId(), + _context); return true; } } diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.h b/Telegram/SourceFiles/media/stories/media_stories_controller.h index d6081d84b6..4fd02ac39b 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.h +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.h @@ -99,7 +99,7 @@ public: [[nodiscard]] auto stickerOrEmojiChosen() const -> rpl::producer; - void show(not_null story, Data::StorySourcesList list); + void show(not_null story, Data::StoriesContext context); void ready(); void updateVideoPlayback(const Player::TrackState &state); @@ -137,6 +137,7 @@ private: void updatePlayingAllowed(); void setPlayingAllowed(bool allowed); + void hideSiblings(); void showSiblings( not_null session, const std::vector &lists, @@ -178,6 +179,7 @@ private: FullStoryId _shown; TextWithEntities _captionText; + Data::StoriesContext _context; std::optional _source; FullStoryId _waitingForId; int _index = 0; diff --git a/Telegram/SourceFiles/media/stories/media_stories_delegate.h b/Telegram/SourceFiles/media/stories/media_stories_delegate.h index 549788c849..9f8d7ce4d3 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_delegate.h +++ b/Telegram/SourceFiles/media/stories/media_stories_delegate.h @@ -12,6 +12,10 @@ class Show; struct FileChosen; } // namespace ChatHelpers +namespace Data { +struct StoriesContext; +} // namespace Data + namespace Main { class Session; } // namespace Main @@ -41,7 +45,8 @@ public: -> rpl::producer = 0; virtual void storiesJumpTo( not_null session, - FullStoryId id) = 0; + FullStoryId id, + Data::StoriesContext context) = 0; virtual void storiesClose() = 0; [[nodiscard]] virtual bool storiesPaused() = 0; [[nodiscard]] virtual rpl::producer storiesLayerShown() = 0; diff --git a/Telegram/SourceFiles/media/stories/media_stories_view.cpp b/Telegram/SourceFiles/media/stories/media_stories_view.cpp index 0fbc387218..de254b8707 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_view.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_view.cpp @@ -22,8 +22,10 @@ View::View(not_null delegate) View::~View() = default; -void View::show(not_null story, Data::StorySourcesList list) { - _controller->show(story, list); +void View::show( + not_null story, + Data::StoriesContext context) { + _controller->show(story, context); } void View::ready() { diff --git a/Telegram/SourceFiles/media/stories/media_stories_view.h b/Telegram/SourceFiles/media/stories/media_stories_view.h index a671bdbde6..b25011de5e 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_view.h +++ b/Telegram/SourceFiles/media/stories/media_stories_view.h @@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { class Story; -enum class StorySourcesList : uchar; +struct StoriesContext; struct FileOrigin; } // namespace Data @@ -53,7 +53,7 @@ public: explicit View(not_null delegate); ~View(); - void show(not_null story, Data::StorySourcesList list); + void show(not_null story, Data::StoriesContext context); void ready(); [[nodiscard]] bool canDownload() const; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_common.h b/Telegram/SourceFiles/media/streaming/media_streaming_common.h index d1abf2011e..f91afead25 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_common.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_common.h @@ -40,11 +40,13 @@ enum class Mode { struct PlaybackOptions { Mode mode = Mode::Both; crl::time position = 0; + crl::time durationOverride = 0; float64 speed = 1.; // Valid values between 0.5 and 2. AudioMsgId audioId; bool syncVideoByAudio = true; bool waitForMarkAsShown = false; bool hwAllowed = false; + bool seekable = true; bool loop = false; }; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp index 6a815e8880..22427c2ff0 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp @@ -150,7 +150,7 @@ Stream File::Context::initStream( not_null format, AVMediaType type, Mode mode, - bool hwAllowed) { + StartOptions options) { auto result = Stream(); const auto index = result.index = av_find_best_stream( format, @@ -171,7 +171,7 @@ Stream File::Context::initStream( } result.codec = FFmpeg::MakeCodecPointer({ .stream = info, - .hwAllowed = hwAllowed, + .hwAllowed = options.hwAllow, }); if (!result.codec) { return result; @@ -196,7 +196,9 @@ Stream File::Context::initStream( return result; } result.timeBase = info->time_base; - result.duration = (info->duration != AV_NOPTS_VALUE) + result.duration = options.durationOverride + ? options.durationOverride + : (info->duration != AV_NOPTS_VALUE) ? FFmpeg::PtsToTime(info->duration, result.timeBase) : UnreliableFormatDuration(format, info, mode) ? kTimeUnknown @@ -269,17 +271,19 @@ std::variant File::Context::readPacket() { return error; } -void File::Context::start(crl::time position, bool hwAllow) { +void File::Context::start(StartOptions options) { + Expects(options.seekable || !options.position); + auto error = FFmpeg::AvErrorWrap(); if (unroll()) { return; } auto format = FFmpeg::MakeFormatPointer( - static_cast(this), + static_cast(this), &Context::Read, nullptr, - &Context::Seek); + options.seekable ? &Context::Seek : nullptr); if (!format) { return fail(Error::OpenFailed); } @@ -289,12 +293,20 @@ void File::Context::start(crl::time position, bool hwAllow) { } const auto mode = _delegate->fileOpenMode(); - auto video = initStream(format.get(), AVMEDIA_TYPE_VIDEO, mode, hwAllow); + auto video = initStream( + format.get(), + AVMEDIA_TYPE_VIDEO, + mode, + options); if (unroll()) { return; } - auto audio = initStream(format.get(), AVMEDIA_TYPE_AUDIO, mode, false); + auto audio = initStream( + format.get(), + AVMEDIA_TYPE_AUDIO, + mode, + options); if (unroll()) { return; } @@ -303,8 +315,11 @@ void File::Context::start(crl::time position, bool hwAllow) { if (_reader->isRemoteLoader()) { sendFullInCache(true); } - if (video.codec || audio.codec) { - seekToPosition(format.get(), video.codec ? video : audio, position); + if (options.seekable && (video.codec || audio.codec)) { + seekToPosition( + format.get(), + video.codec ? video : audio, + options.position); } if (unroll()) { return; @@ -434,10 +449,7 @@ File::File(std::shared_ptr reader) : _reader(std::move(reader)) { } -void File::start( - not_null delegate, - crl::time position, - bool hwAllow) { +void File::start(not_null delegate, StartOptions options) { stop(true); _reader->startStreaming(); @@ -445,7 +457,7 @@ void File::start( _thread = std::thread([=, context = &*_context] { crl::toggle_fp_exceptions(true); - context->start(position, hwAllow); + context->start(options); while (!context->finished()) { context->readNextPacket(); } diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_file.h b/Telegram/SourceFiles/media/streaming/media_streaming_file.h index 8ffea94309..38af455378 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_file.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_file.h @@ -21,6 +21,13 @@ namespace Streaming { class FileDelegate; +struct StartOptions { + crl::time position = 0; + crl::time durationOverride = 0; + bool seekable = true; + bool hwAllow = false; +}; + class File final { public: explicit File(std::shared_ptr reader); @@ -28,10 +35,7 @@ public: File(const File &other) = delete; File &operator=(const File &other) = delete; - void start( - not_null delegate, - crl::time position, - bool hwAllow); + void start(not_null delegate, StartOptions options); void wake(); void stop(bool stillActive = false); @@ -46,7 +50,7 @@ private: Context(not_null delegate, not_null reader); ~Context(); - void start(crl::time position, bool hwAllow); + void start(StartOptions options); void readNextPacket(); void interrupt(); @@ -79,7 +83,7 @@ private: not_null format, AVMediaType type, Mode mode, - bool hwAllowed); + StartOptions options); void seekToPosition( not_null format, const Stream &stream, diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp index 6662ec8621..d305660721 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp @@ -544,8 +544,16 @@ void Player::play(const PlaybackOptions &options) { if (!Media::Audio::SupportsSpeedControl()) { _options.speed = 1.; } + if (!_options.seekable) { + _options.position = 0; + } _stage = Stage::Initializing; - _file->start(delegate(), _options.position, _options.hwAllowed); + _file->start(delegate(), { + .position = _options.position, + .durationOverride = options.durationOverride, + .seekable = _options.seekable, + .hwAllow = _options.hwAllowed, + }); } void Player::savePreviousReceivedTill( diff --git a/Telegram/SourceFiles/media/view/media_view_open_common.h b/Telegram/SourceFiles/media/view/media_view_open_common.h index aed2fde585..ff56af25da 100644 --- a/Telegram/SourceFiles/media/view/media_view_open_common.h +++ b/Telegram/SourceFiles/media/view/media_view_open_common.h @@ -8,17 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "data/data_cloud_themes.h" +#include "data/data_stories.h" class DocumentData; class PeerData; class PhotoData; class HistoryItem; -namespace Data { -class Story; -enum class StorySourcesList : uchar; -} // namespace Data - namespace Window { class SessionController; } // namespace Window @@ -75,14 +71,10 @@ public: OpenRequest( Window::SessionController *controller, not_null story, - Data::StorySourcesList list, - bool continueStreaming = false, - crl::time startTime = 0) + Data::StoriesContext context) : _controller(controller) , _story(story) - , _storiesList(list) - , _continueStreaming(continueStreaming) - , _startTime(startTime) { + , _storiesContext(context) { } [[nodiscard]] PeerData *peer() const { @@ -108,8 +100,8 @@ public: [[nodiscard]] Data::Story *story() const { return _story; } - [[nodiscard]] Data::StorySourcesList storiesList() const { - return _storiesList; + [[nodiscard]] Data::StoriesContext storiesContext() const { + return _storiesContext; } [[nodiscard]] std::optional cloudTheme() const { @@ -133,7 +125,7 @@ private: DocumentData *_document = nullptr; PhotoData *_photo = nullptr; Data::Story *_story = nullptr; - Data::StorySourcesList _storiesList = {}; + Data::StoriesContext _storiesContext; PeerData *_peer = nullptr; HistoryItem *_item = nullptr; MsgId _topicRootId = 0; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 75c7a43bba..2bbda9a431 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -287,6 +287,17 @@ struct OverlayWidget::PipWrap { rpl::lifetime lifetime; }; +struct OverlayWidget::ItemContext { + not_null item; + MsgId topicRootId = 0; +}; + +struct OverlayWidget::StoriesContext { + not_null peer; + StoryId id = 0; + Data::StoriesContext within; +}; + class OverlayWidget::Show final : public ChatHelpers::Show { public: explicit Show(not_null widget) : _widget(widget) { @@ -3064,7 +3075,7 @@ void OverlayWidget::show(OpenRequest request) { setContext(StoriesContext{ story->peer(), story->id(), - request.storiesList(), + request.storiesContext(), }); } else if (contextPeer) { setContext(contextPeer); @@ -3085,7 +3096,11 @@ void OverlayWidget::show(OpenRequest request) { setSession(&document->session()); if (story) { - setContext(StoriesContext{ story->peer(), story->id() }); + setContext(StoriesContext{ + story->peer(), + story->id(), + request.storiesContext(), + }); } else if (contextItem) { setContext(ItemContext{ contextItem, contextTopicRootId }); } else { @@ -3868,9 +3883,16 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) { _rotation = saved; updateContentRect(); } - auto options = Streaming::PlaybackOptions(); - options.position = position; - options.hwAllowed = Core::App().settings().hardwareAcceleratedVideo(); + auto options = Streaming::PlaybackOptions{ + .position = position, + .durationOverride = ((_stories + && _document + && _document->getDuration() > 0) + ? (_document->getDuration() * crl::time(1000) + crl::time(999)) + : crl::time(0)), + .hwAllowed = Core::App().settings().hardwareAcceleratedVideo(), + .seekable = !_stories, + }; if (!_streamed->withSound) { options.mode = Streaming::Mode::Video; options.loop = true; @@ -4025,7 +4047,8 @@ auto OverlayWidget::storiesStickerOrEmojiChosen() void OverlayWidget::storiesJumpTo( not_null session, - FullStoryId id) { + FullStoryId id, + Data::StoriesContext context) { Expects(_stories != nullptr); Expects(id.valid()); @@ -4035,7 +4058,11 @@ void OverlayWidget::storiesJumpTo( return; } const auto story = *maybeStory; - setContext(StoriesContext{ story->peer(), story->id() }); + setContext(StoriesContext{ + story->peer(), + story->id(), + context, + }); clearStreaming(); _streamingStartPaused = false; v::match(story->media().data, [&](not_null photo) { @@ -4982,7 +5009,7 @@ void OverlayWidget::setContext( const auto maybeStory = stories.lookup( { story->peer->id, story->id }); if (maybeStory) { - _stories->show(*maybeStory, story->list); + _stories->show(*maybeStory, story->within); } } else { _message = nullptr; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 8376786755..2085fef99a 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -30,7 +30,7 @@ enum class activation : uchar; namespace Data { class PhotoMedia; class DocumentMedia; -enum class StorySourcesList : uchar; +struct StoriesContext; } // namespace Data namespace Ui { @@ -134,6 +134,8 @@ private: class Show; struct Streamed; struct PipWrap; + struct ItemContext; + struct StoriesContext; class Renderer; class RendererSW; class RendererGL; @@ -245,7 +247,8 @@ private: -> rpl::producer override; void storiesJumpTo( not_null session, - FullStoryId id) override; + FullStoryId id, + Data::StoriesContext context) override; void storiesClose() override; bool storiesPaused() override; rpl::producer storiesLayerShown() override; @@ -300,15 +303,6 @@ private: Entity entityForItemId(const FullMsgId &itemId) const; bool moveToEntity(const Entity &entity, int preloadDelta = 0); - struct ItemContext { - not_null item; - MsgId topicRootId = 0; - }; - struct StoriesContext { - not_null peer; - StoryId id = 0; - Data::StorySourcesList list = {}; - }; void setContext(std::variant< v::null_t, ItemContext, diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 793964d9ee..fd26e5e285 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -2467,13 +2467,13 @@ Ui::ChatThemeBackgroundData SessionController::backgroundData( void SessionController::openPeerStory( not_null peer, StoryId storyId, - Data::StorySourcesList list) { + Data::StoriesContext context) { using namespace Media::View; using namespace Data; auto &stories = session().data().stories(); if (const auto from = stories.lookup({ peer->id, storyId })) { - window().openInMediaView(OpenRequest(this, *from, list)); + window().openInMediaView(OpenRequest(this, *from, context)); } } @@ -2492,7 +2492,7 @@ void SessionController::openPeerStories( openPeerStory( i->second.user, j != i->second.ids.end() ? j->id : i->second.ids.front().id, - list); + { list }); } } diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 5891696553..5e1139ad16 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -30,6 +30,7 @@ enum class WindowLayout; } // namespace Adaptive namespace Data { +struct StoriesContext; enum class StorySourcesList : uchar; } // namespace Data @@ -571,7 +572,7 @@ public: void openPeerStory( not_null peer, StoryId storyId, - Data::StorySourcesList list); + Data::StoriesContext context); void openPeerStories(PeerId peerId, Data::StorySourcesList list); struct PaintContextArgs {