Load more saved / archive in the viewer.

This commit is contained in:
John Preston 2023-06-13 19:51:08 +04:00
parent 1c41df364c
commit 881867186a
15 changed files with 301 additions and 109 deletions

View file

@ -254,7 +254,10 @@ void ResolveDocument(
&& !document->filepath().isEmpty()) { && !document->filepath().isEmpty()) {
File::Launch(document->location(false).fname); File::Launch(document->location(false).fname);
} else if (controller) { } else if (controller) {
controller->openDocument(document, msgId, topicRootId, true); controller->openDocument(
document,
true,
{ msgId, topicRootId });
} }
}; };

View file

@ -1109,8 +1109,7 @@ void Stories::markAsRead(FullStoryId id, bool viewed) {
} }
} }
const auto i = _all.find(id.peer); const auto i = _all.find(id.peer);
Assert(i != end(_all)); if (i == end(_all) || i->second.readTill >= id.story) {
if (i->second.readTill >= id.story) {
return; return;
} else if (!_markReadPending.contains(id.peer)) { } else if (!_markReadPending.contains(id.peer)) {
sendMarkAsReadRequests(); sendMarkAsReadRequests();

View file

@ -44,7 +44,7 @@ rpl::producer<StoriesIdsSlice> SavedStoriesIds(
const auto hasBefore = int(around - begin(saved->list)); const auto hasBefore = int(around - begin(saved->list));
const auto hasAfter = int(end(saved->list) - around); const auto hasAfter = int(end(saved->list) - around);
if (hasAfter < limit) { if (hasAfter < limit) {
stories->savedLoadMore(peer->id); //stories->savedLoadMore(peer->id);
} }
const auto takeBefore = std::min(hasBefore, limit); const auto takeBefore = std::min(hasBefore, limit);
const auto takeAfter = std::min(hasAfter, limit); const auto takeAfter = std::min(hasAfter, limit);
@ -116,7 +116,7 @@ rpl::producer<StoriesIdsSlice> ArchiveStoriesIds(
const auto hasBefore = int(i - begin(archive.list)); const auto hasBefore = int(i - begin(archive.list));
const auto hasAfter = int(end(archive.list) - i); const auto hasAfter = int(end(archive.list) - i);
if (hasAfter < limit) { if (hasAfter < limit) {
stories->archiveLoadMore(); //stories->archiveLoadMore();
} }
const auto takeBefore = std::min(hasBefore, limit); const auto takeBefore = std::min(hasBefore, limit);
const auto takeAfter = std::min(hasAfter, limit); const auto takeAfter = std::min(hasAfter, limit);

View file

@ -610,14 +610,14 @@ void InnerWidget::elementShowPollResults(
void InnerWidget::elementOpenPhoto( void InnerWidget::elementOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
_controller->openPhoto(photo, context, MsgId(0)); _controller->openPhoto(photo, { context });
} }
void InnerWidget::elementOpenDocument( void InnerWidget::elementOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
_controller->openDocument(document, context, MsgId(0), showInMediaView); _controller->openDocument(document, showInMediaView, { context });
} }
void InnerWidget::elementCancelUpload(const FullMsgId &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 item = session().data().message(itemId)) {
if (const auto media = item->media()) { if (const auto media = item->media()) {
if (const auto document = media->document()) { if (const auto document = media->document()) {
_controller->openDocument(document, itemId, MsgId(), true); _controller->openDocument(document, true, { itemId });
} }
} }
} }

View file

@ -2779,7 +2779,7 @@ void HistoryInner::openContextGif(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) { if (const auto item = session().data().message(itemId)) {
if (const auto media = item->media()) { if (const auto media = item->media()) {
if (const auto document = media->document()) { 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( void HistoryInner::elementOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
_controller->openPhoto(photo, context, MsgId(0)); _controller->openPhoto(photo, { context });
} }
void HistoryInner::elementOpenDocument( void HistoryInner::elementOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
_controller->openDocument(document, context, MsgId(0), showInMediaView); _controller->openDocument(document, showInMediaView, { context });
} }
void HistoryInner::elementCancelUpload(const FullMsgId &context) { void HistoryInner::elementCancelUpload(const FullMsgId &context) {

View file

@ -1467,9 +1467,9 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
if (result.open) { if (result.open) {
const auto request = result.result->openRequest(); const auto request = result.result->openRequest();
if (const auto photo = request.photo()) { if (const auto photo = request.photo()) {
controller()->openPhoto(photo, {}, {}); controller()->openPhoto(photo, {});
} else if (const auto document = request.document()) { } else if (const auto document = request.document()) {
controller()->openDocument(document, {}, {}); controller()->openDocument(document, false, {});
} }
} else { } else {
sendInlineResult(result); sendInlineResult(result);

View file

@ -3059,9 +3059,9 @@ void ComposeControls::applyInlineBotQuery(
if (result.open) { if (result.open) {
const auto request = result.result->openRequest(); const auto request = result.result->openRequest();
if (const auto photo = request.photo()) { if (const auto photo = request.photo()) {
_regularWindow->openPhoto(photo, {}, {}); _regularWindow->openPhoto(photo, {});
} else if (const auto document = request.document()) { } else if (const auto document = request.document()) {
_regularWindow->openDocument(document, {}, {}); _regularWindow->openDocument(document, false, {});
} }
} else { } else {
_inlineResultChosen.fire_copy(result); _inlineResultChosen.fire_copy(result);

View file

@ -643,14 +643,14 @@ void PinnedWidget::listShowPremiumToast(not_null<DocumentData*> document) {
void PinnedWidget::listOpenPhoto( void PinnedWidget::listOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
controller()->openPhoto(photo, context, MsgId()); controller()->openPhoto(photo, { context });
} }
void PinnedWidget::listOpenDocument( void PinnedWidget::listOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
controller()->openDocument(document, context, MsgId(), showInMediaView); controller()->openDocument(document, showInMediaView, { context });
} }
void PinnedWidget::listPaintEmpty( void PinnedWidget::listPaintEmpty(

View file

@ -2553,14 +2553,17 @@ void RepliesWidget::listShowPremiumToast(not_null<DocumentData*> document) {
void RepliesWidget::listOpenPhoto( void RepliesWidget::listOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
controller()->openPhoto(photo, context, _rootId); controller()->openPhoto(photo, { context, _rootId });
} }
void RepliesWidget::listOpenDocument( void RepliesWidget::listOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
controller()->openDocument(document, context, _rootId, showInMediaView); controller()->openDocument(
document,
showInMediaView,
{ context, _rootId });
} }
void RepliesWidget::listPaintEmpty( void RepliesWidget::listPaintEmpty(

View file

@ -1290,14 +1290,14 @@ void ScheduledWidget::listShowPremiumToast(
void ScheduledWidget::listOpenPhoto( void ScheduledWidget::listOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
controller()->openPhoto(photo, context, MsgId()); controller()->openPhoto(photo, { context });
} }
void ScheduledWidget::listOpenDocument( void ScheduledWidget::listOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
controller()->openDocument(document, context, MsgId(), showInMediaView); controller()->openDocument(document, showInMediaView, { context });
} }
void ScheduledWidget::listPaintEmpty( void ScheduledWidget::listPaintEmpty(

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_peer_values.h" #include "data/data_peer_values.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_stories.h"
#include "data/data_file_click_handler.h" #include "data/data_file_click_handler.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_download_manager.h" #include "data/data_download_manager.h"
@ -476,18 +477,31 @@ bool ListWidget::tooltipWindowActive() const {
} }
void ListWidget::openPhoto(not_null<PhotoData*> photo, FullMsgId id) { void ListWidget::openPhoto(not_null<PhotoData*> 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( void ListWidget::openDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId id, FullMsgId id,
bool showInMediaView) { 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( _controller->parentController()->openDocument(
document, document,
id, showInMediaView,
topicRootId(), { id, topicRootId() },
showInMediaView); _controller->storiesPeer() ? &context : nullptr);
} }
void ListWidget::trackSession(not_null<Main::Session*> session) { void ListWidget::trackSession(not_null<Main::Session*> session) {

View file

@ -48,6 +48,7 @@ constexpr auto kSiblingOutsidePart = 0.24;
constexpr auto kSiblingUserpicSize = 0.3; constexpr auto kSiblingUserpicSize = 0.3;
constexpr auto kInnerHeightMultiplier = 1.6; constexpr auto kInnerHeightMultiplier = 1.6;
constexpr auto kPreloadUsersCount = 3; constexpr auto kPreloadUsersCount = 3;
constexpr auto kPreloadStoriesCount = 5;
constexpr auto kMarkAsReadAfterSeconds = 1; constexpr auto kMarkAsReadAfterSeconds = 1;
constexpr auto kMarkAsReadAfterProgress = 0.2; constexpr auto kMarkAsReadAfterProgress = 0.2;
@ -432,48 +433,142 @@ auto Controller::cachedReactionIconFactory() const
return _delegate->storiesCachedReactionIconFactory(); return _delegate->storiesCachedReactionIconFactory();
} }
void Controller::show( void Controller::rebuildFromContext(
not_null<Data::Story*> story, not_null<UserData*> user,
Data::StoriesContext context) { FullStoryId storyId) {
using namespace Data; using namespace Data;
auto &stories = story->owner().stories(); auto &stories = user->owner().stories();
const auto storyId = story->fullId(); auto list = std::optional<StoriesList>();
auto source = (const StoriesSource*)nullptr;
const auto peerId = storyId.peer;
const auto id = storyId.story; const auto id = storyId.story;
auto source = stories.source(storyId.peer); v::match(_context.data, [&](StoriesContextSingle) {
auto single = StoriesSource{ story->peer()->asUser() };
v::match(context.data, [&](StoriesContextSingle) {
source = nullptr;
hideSiblings(); hideSiblings();
}, [&](StoriesContextPeer) { }, [&](StoriesContextPeer) {
source = stories.source(peerId);
hideSiblings(); hideSiblings();
}, [&](StoriesContextSaved) { }, [&](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(); hideSiblings();
}, [&](StoriesContextArchive) { }, [&](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(); hideSiblings();
}, [&](StorySourcesList list) { }, [&](StorySourcesList list) {
source = stories.source(peerId);
const auto &sources = stories.sources(list); const auto &sources = stories.sources(list);
const auto i = ranges::find( const auto i = ranges::find(
sources, sources,
storyId.peer, storyId.peer,
&StoriesSourceInfo::id); &StoriesSourceInfo::id);
if (i == end(sources)) { if (i != end(sources)) {
source = nullptr; showSiblings(&user->session(), sources, (i - begin(sources)));
return; if (int(sources.end() - i) < kPreloadUsersCount) {
} stories.loadMore(list);
showSiblings(&story->session(), sources, (i - begin(sources))); }
if (int(sources.end() - i) < kPreloadUsersCount) {
stories.loadMore(list);
} }
}); });
const auto idDates = story->idDates(); if (list) {
_index = source ? (source->ids.find(idDates) - begin(source->ids)) : 0; _source = std::nullopt;
if (!source || _index == source->ids.size()) { if (_list != list) {
source = &single; _list = std::move(list);
single.ids.emplace(idDates); }
_index = 0; } 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<Data::Story*> 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([&] { const auto guard = gsl::finally([&] {
_paused = false; _paused = false;
_started = false; _started = false;
@ -483,11 +578,7 @@ void Controller::show(
_photoPlayback = nullptr; _photoPlayback = nullptr;
} }
}); });
if (_source != *source) {
_source = *source;
}
_context = context;
_waitingForId = {};
if (_shown == storyId) { if (_shown == storyId) {
return; return;
} }
@ -501,13 +592,12 @@ void Controller::show(
unfocusReply(); unfocusReply();
} }
_header->show({ .user = source->user, .date = story->date() }); _header->show({ .user = user, .date = story->date() });
_slider->show({ .index = _index, .total = int(source->ids.size()) }); _replyArea->show({ .user = user, .id = story->id() });
_replyArea->show({ .user = source->user, .id = id });
_recentViews->show({ _recentViews->show({
.list = story->recentViewers(), .list = story->recentViewers(),
.total = story->views(), .total = story->views(),
.valid = source->user->isSelf(), .valid = user->isSelf(),
}); });
const auto session = &story->session(); const auto session = &story->session();
@ -531,7 +621,7 @@ void Controller::show(
stories.loadAround(storyId, context); stories.loadAround(storyId, context);
updatePlayingAllowed(); updatePlayingAllowed();
source->user->updateFull(); user->updateFull();
} }
void Controller::updatePlayingAllowed() { void Controller::updatePlayingAllowed() {
@ -634,23 +724,23 @@ void Controller::maybeMarkAsRead(const Player::TrackState &state) {
} }
void Controller::markAsRead() { void Controller::markAsRead() {
Expects(_source.has_value()); Expects(shown());
if (_viewed) { if (_viewed) {
return; return;
} }
_viewed = true; _viewed = true;
_source->user->owner().stories().markAsRead(_shown, _started); shownUser()->owner().stories().markAsRead(_shown, _started);
} }
bool Controller::subjumpAvailable(int delta) const { bool Controller::subjumpAvailable(int delta) const {
const auto index = _index + delta; const auto index = _index + delta;
if (index < 0) { if (index < 0) {
return _siblingLeft && _siblingLeft->shownId().valid(); return _siblingLeft && _siblingLeft->shownId().valid();
} else if (index >= int(_source->ids.size())) { } else if (index >= shownCount()) {
return _siblingRight && _siblingRight->shownId().valid(); return _siblingRight && _siblingRight->shownId().valid();
} }
return index >= 0 && index < int(_source->ids.size()); return index >= 0 && index < shownCount();
} }
bool Controller::subjumpFor(int delta) { bool Controller::subjumpFor(int delta) {
@ -661,12 +751,12 @@ bool Controller::subjumpFor(int delta) {
if (index < 0) { if (index < 0) {
if (_siblingLeft && _siblingLeft->shownId().valid()) { if (_siblingLeft && _siblingLeft->shownId().valid()) {
return jumpFor(-1); return jumpFor(-1);
} else if (!_source || _source->ids.empty()) { } else if (!shown() || !shownCount()) {
return false; return false;
} }
subjumpTo(0); subjumpTo(0);
return true; return true;
} else if (index >= int(_source->ids.size())) { } else if (index >= shownCount()) {
return _siblingRight return _siblingRight
&& _siblingRight->shownId().valid() && _siblingRight->shownId().valid()
&& jumpFor(1); && jumpFor(1);
@ -677,27 +767,37 @@ bool Controller::subjumpFor(int delta) {
} }
void Controller::subjumpTo(int index) { void Controller::subjumpTo(int index) {
Expects(_source.has_value()); Expects(shown());
Expects(index >= 0 && index < _source->ids.size()); Expects(index >= 0 && index < shownCount());
const auto user = shownUser();
const auto id = FullStoryId{ const auto id = FullStoryId{
.peer = _source->user->id, .peer = user->id,
.story = (begin(_source->ids) + index)->id, .story = shownId(index),
}; };
auto &stories = _source->user->owner().stories(); auto &stories = user->owner().stories();
if (stories.lookup(id)) { if (!id.story) {
_delegate->storiesJumpTo(&_source->user->session(), id, _context); 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) { } else if (_waitingForId != id) {
_waitingForId = id; _waitingForId = id;
_waitingForDelta = 0;
stories.loadAround(id, _context); stories.loadAround(id, _context);
} }
} }
void Controller::checkWaitingFor() { void Controller::checkWaitingFor() {
Expects(_waitingForId.valid()); 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); const auto maybe = stories.lookup(_waitingForId);
if (!maybe) { if (!maybe) {
if (maybe.error() == Data::NoStory::Deleted) { if (maybe.error() == Data::NoStory::Deleted) {
@ -706,7 +806,7 @@ void Controller::checkWaitingFor() {
return; return;
} }
_delegate->storiesJumpTo( _delegate->storiesJumpTo(
&_source->user->session(), &user->session(),
base::take(_waitingForId), base::take(_waitingForId),
_context); _context);
} }
@ -721,7 +821,7 @@ bool Controller::jumpFor(int delta) {
return true; return true;
} }
} else if (delta == 1) { } else if (delta == 1) {
if (_source && _index + 1 >= int(_source->ids.size())) { if (shown() && _index + 1 >= shownCount()) {
markAsRead(); markAsRead();
} }
if (const auto right = _siblingRight.get()) { if (const auto right = _siblingRight.get()) {
@ -817,7 +917,8 @@ Fn<void(std::vector<Data::StoryView>)> Controller::viewsGotMoreCallback() {
return crl::guard(&_viewsLoadGuard, [=]( return crl::guard(&_viewsLoadGuard, [=](
const std::vector<Data::StoryView> &result) { const std::vector<Data::StoryView> &result) {
if (_viewsSlice.list.empty()) { 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)) { if (const auto maybeStory = stories.lookup(_shown)) {
_viewsSlice = { _viewsSlice = {
.list = result, .list = result,
@ -838,12 +939,57 @@ Fn<void(std::vector<Data::StoryView>)> Controller::viewsGotMoreCallback() {
}); });
} }
void Controller::refreshViewsFromData() { bool Controller::shown() const {
Expects(_source.has_value()); 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); const auto maybeStory = stories.lookup(_shown);
if (!maybeStory || !_source->user->isSelf()) { if (!maybeStory || !user->isSelf()) {
_viewsSlice = {}; _viewsSlice = {};
return; return;
} }
@ -861,11 +1007,12 @@ void Controller::refreshViewsFromData() {
} }
bool Controller::sliceViewsTo(PeerId offset) { 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); const auto maybeStory = stories.lookup(_shown);
if (!maybeStory || !_source->user->isSelf()) { if (!maybeStory || !user->isSelf()) {
_viewsSlice = {}; _viewsSlice = {};
return true; return true;
} }

View file

@ -135,6 +135,15 @@ public:
[[nodiscard]] rpl::lifetime &lifetime(); [[nodiscard]] rpl::lifetime &lifetime();
private: private:
struct StoriesList {
not_null<UserData*> user;
Data::StoriesIds ids;
int total = 0;
friend inline bool operator==(
const StoriesList &,
const StoriesList &) = default;
};
class PhotoPlayback; class PhotoPlayback;
void initLayout(); void initLayout();
@ -166,6 +175,14 @@ private:
[[nodiscard]] auto viewsGotMoreCallback() [[nodiscard]] auto viewsGotMoreCallback()
-> Fn<void(std::vector<Data::StoryView>)>; -> Fn<void(std::vector<Data::StoryView>)>;
[[nodiscard]] bool shown() const;
[[nodiscard]] UserData *shownUser() const;
[[nodiscard]] int shownCount() const;
[[nodiscard]] StoryId shownId(int index) const;
void rebuildFromContext(not_null<UserData*> user, FullStoryId storyId);
void checkMoveByDelta();
void loadMoreToList();
const not_null<Delegate*> _delegate; const not_null<Delegate*> _delegate;
rpl::variable<std::optional<Layout>> _layout; rpl::variable<std::optional<Layout>> _layout;
@ -194,7 +211,9 @@ private:
TextWithEntities _captionText; TextWithEntities _captionText;
Data::StoriesContext _context; Data::StoriesContext _context;
std::optional<Data::StoriesSource> _source; std::optional<Data::StoriesSource> _source;
std::optional<StoriesList> _list;
FullStoryId _waitingForId; FullStoryId _waitingForId;
int _waitingForDelta = 0;
int _index = 0; int _index = 0;
bool _started = false; bool _started = false;
bool _viewed = false; bool _viewed = false;
@ -211,6 +230,8 @@ private:
Main::Session *_session = nullptr; Main::Session *_session = nullptr;
rpl::lifetime _sessionLifetime; rpl::lifetime _sessionLifetime;
rpl::lifetime _contextLifetime;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;
}; };

View file

@ -2153,14 +2153,14 @@ void SessionController::hideLayer(anim::type animated) {
void SessionController::openPhoto( void SessionController::openPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId contextId, MessageContext message,
MsgId topicRootId) { const Data::StoriesContext *stories) {
const auto item = session().data().message(contextId); const auto item = session().data().message(message.id);
if (openSharedStory(item) || openFakeItemStory(contextId)) { if (openSharedStory(item) || openFakeItemStory(message.id, stories)) {
return; return;
} }
_window->openInMediaView( _window->openInMediaView(
Media::View::OpenRequest(this, photo, item, topicRootId)); Media::View::OpenRequest(this, photo, item, message.topicRootId));
} }
void SessionController::openPhoto( void SessionController::openPhoto(
@ -2171,18 +2171,21 @@ void SessionController::openPhoto(
void SessionController::openDocument( void SessionController::openDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId contextId, bool showInMediaView,
MsgId topicRootId, MessageContext message,
bool showInMediaView) { const Data::StoriesContext *stories) {
const auto item = session().data().message(contextId); const auto item = session().data().message(message.id);
if (openSharedStory(item) || openFakeItemStory(contextId)) { if (openSharedStory(item) || openFakeItemStory(message.id, stories)) {
return; return;
} else if (showInMediaView) { } else if (showInMediaView) {
_window->openInMediaView( _window->openInMediaView(Media::View::OpenRequest(
Media::View::OpenRequest(this, document, item, topicRootId)); this,
document,
item,
message.topicRootId));
return; return;
} }
Data::ResolveDocument(this, document, item, topicRootId); Data::ResolveDocument(this, document, item, message.topicRootId);
} }
bool SessionController::openSharedStory(HistoryItem *item) { bool SessionController::openSharedStory(HistoryItem *item) {
@ -2203,7 +2206,7 @@ bool SessionController::openSharedStory(HistoryItem *item) {
bool SessionController::openFakeItemStory( bool SessionController::openFakeItemStory(
FullMsgId fakeItemId, FullMsgId fakeItemId,
bool forceArchiveContext) { const Data::StoriesContext *stories) {
if (!peerIsUser(fakeItemId.peer) if (!peerIsUser(fakeItemId.peer)
|| !IsStoryMsgId(fakeItemId.msg)) { || !IsStoryMsgId(fakeItemId.msg)) {
return false; return false;
@ -2215,13 +2218,11 @@ bool SessionController::openFakeItemStory(
if (maybeStory) { if (maybeStory) {
using namespace Data; using namespace Data;
const auto story = *maybeStory; const auto story = *maybeStory;
const auto context = !story->expired() const auto context = stories
? StoriesContext{ StoriesContextPeer() } ? *stories
: (story->pinned() && !forceArchiveContext) : StoriesContext{ StoriesContextSingle() };
? StoriesContext{ StoriesContextSaved() }
: StoriesContext{ StoriesContextArchive() };
_window->openInMediaView( _window->openInMediaView(
::Media::View::OpenRequest(this, *maybeStory, context)); ::Media::View::OpenRequest(this, story, context));
} }
return true; return true;
} }

View file

@ -482,20 +482,24 @@ public:
void showPassportForm(const Passport::FormRequest &request); void showPassportForm(const Passport::FormRequest &request);
void clearPassportForm(); void clearPassportForm();
struct MessageContext {
FullMsgId id;
MsgId topicRootId;
};
void openPhoto( void openPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId contextId, MessageContext message,
MsgId topicRootId); const Data::StoriesContext *stories = nullptr);
void openPhoto(not_null<PhotoData*> photo, not_null<PeerData*> peer); void openPhoto(not_null<PhotoData*> photo, not_null<PeerData*> peer);
void openDocument( void openDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId contextId, bool showInMediaView,
MsgId topicRootId, MessageContext message,
bool showInMediaView = false); const Data::StoriesContext *stories = nullptr);
bool openSharedStory(HistoryItem *item); bool openSharedStory(HistoryItem *item);
bool openFakeItemStory( bool openFakeItemStory(
FullMsgId fakeItemId, FullMsgId fakeItemId,
bool forceArchiveContext = false); const Data::StoriesContext *stories = nullptr);
void showChooseReportMessages( void showChooseReportMessages(
not_null<PeerData*> peer, not_null<PeerData*> peer,