mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Load more saved / archive in the viewer.
This commit is contained in:
parent
1c41df364c
commit
881867186a
15 changed files with 301 additions and 109 deletions
|
@ -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 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue