mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Add short-polling of stories.
This commit is contained in:
parent
12fe0a836a
commit
5ccb97668c
14 changed files with 308 additions and 52 deletions
|
@ -38,6 +38,8 @@ constexpr auto kSavedPerPage = 100;
|
|||
constexpr auto kMaxPreloadSources = 10;
|
||||
constexpr auto kStillPreloadFromFirst = 3;
|
||||
constexpr auto kMaxSegmentsCount = 180;
|
||||
constexpr auto kPollingIntervalChat = 5 * TimeId(60);
|
||||
constexpr auto kPollingIntervalViewer = 1 * TimeId(60);
|
||||
|
||||
using UpdateFlag = StoryUpdate::Flag;
|
||||
|
||||
|
@ -98,10 +100,12 @@ Stories::Stories(not_null<Session*> owner)
|
|||
: _owner(owner)
|
||||
, _expireTimer([=] { processExpired(); })
|
||||
, _markReadTimer([=] { sendMarkAsReadRequests(); })
|
||||
, _incrementViewsTimer([=] { sendIncrementViewsRequests(); }) {
|
||||
, _incrementViewsTimer([=] { sendIncrementViewsRequests(); })
|
||||
, _pollingTimer([=] { sendPollingRequests(); }) {
|
||||
}
|
||||
|
||||
Stories::~Stories() {
|
||||
Expects(_pollingSettings.empty());
|
||||
}
|
||||
|
||||
Session &Stories::owner() const {
|
||||
|
@ -348,7 +352,7 @@ Story *Stories::parseAndApply(
|
|||
const auto result = i->second.get();
|
||||
const auto pinned = result->pinned();
|
||||
const auto mediaChanged = (result->media() != *media);
|
||||
if (result->applyChanges(*media, data)) {
|
||||
if (result->applyChanges(*media, data, now)) {
|
||||
if (result->pinned() != pinned) {
|
||||
savedStateUpdated(result);
|
||||
}
|
||||
|
@ -358,6 +362,11 @@ Story *Stories::parseAndApply(
|
|||
if (const auto item = lookupItem(result)) {
|
||||
item->applyChanges(result);
|
||||
}
|
||||
_owner->refreshStoryItemViews(fullId);
|
||||
}
|
||||
const auto j = _pollingSettings.find(result);
|
||||
if (j != end(_pollingSettings)) {
|
||||
maybeSchedulePolling(result, j->second, now);
|
||||
}
|
||||
if (mediaChanged) {
|
||||
_preloaded.remove(fullId);
|
||||
|
@ -378,7 +387,7 @@ Story *Stories::parseAndApply(
|
|||
StoryMedia{ *media },
|
||||
data.vdate().v,
|
||||
data.vexpire_date().v)).first->second.get();
|
||||
result->applyChanges(*media, data);
|
||||
result->applyChanges(*media, data, now);
|
||||
if (result->pinned()) {
|
||||
savedStateUpdated(result);
|
||||
}
|
||||
|
@ -656,6 +665,7 @@ void Stories::applyDeleted(FullStoryId id) {
|
|||
preloadFinished(id);
|
||||
}
|
||||
_owner->refreshStoryItemViews(id);
|
||||
Assert(!_pollingSettings.contains(story.get()));
|
||||
if (i->second.empty()) {
|
||||
_stories.erase(i);
|
||||
}
|
||||
|
@ -818,13 +828,15 @@ base::expected<not_null<Story*>, NoStory> Stories::lookup(
|
|||
_deleted.contains(id) ? NoStory::Deleted : NoStory::Unknown);
|
||||
}
|
||||
|
||||
void Stories::resolve(FullStoryId id, Fn<void()> done) {
|
||||
const auto already = lookup(id);
|
||||
if (already.has_value() || already.error() != NoStory::Unknown) {
|
||||
if (done) {
|
||||
done();
|
||||
void Stories::resolve(FullStoryId id, Fn<void()> done, bool force) {
|
||||
if (!force) {
|
||||
const auto already = lookup(id);
|
||||
if (already.has_value() || already.error() != NoStory::Unknown) {
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (const auto i = _resolveSent.find(id.peer); i != end(_resolveSent)) {
|
||||
if (const auto j = i->second.find(id.story); j != end(i->second)) {
|
||||
|
@ -1493,6 +1505,84 @@ bool Stories::isUnread(not_null<Story*> story) {
|
|||
return (story->id() > readTill);
|
||||
}
|
||||
|
||||
void Stories::registerPolling(not_null<Story*> story, Polling polling) {
|
||||
auto &settings = _pollingSettings[story];
|
||||
switch (polling) {
|
||||
case Polling::Chat: ++settings.chat; break;
|
||||
case Polling::Viewer: ++settings.viewer; break;
|
||||
}
|
||||
maybeSchedulePolling(story, settings, base::unixtime::now());
|
||||
}
|
||||
|
||||
void Stories::unregisterPolling(not_null<Story*> story, Polling polling) {
|
||||
const auto i = _pollingSettings.find(story);
|
||||
Assert(i != end(_pollingSettings));
|
||||
|
||||
switch (polling) {
|
||||
case Polling::Chat:
|
||||
Assert(i->second.chat > 0);
|
||||
--i->second.chat;
|
||||
break;
|
||||
case Polling::Viewer:
|
||||
Assert(i->second.viewer > 0);
|
||||
--i->second.viewer;
|
||||
break;
|
||||
}
|
||||
if (!i->second.chat && !i->second.viewer) {
|
||||
_pollingSettings.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool Stories::registerPolling(FullStoryId id, Polling polling) {
|
||||
if (const auto maybeStory = lookup(id)) {
|
||||
registerPolling(*maybeStory, polling);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Stories::unregisterPolling(FullStoryId id, Polling polling) {
|
||||
const auto maybeStory = lookup(id);
|
||||
Assert(maybeStory.has_value());
|
||||
unregisterPolling(*maybeStory, polling);
|
||||
}
|
||||
|
||||
int Stories::pollingInterval(const PollingSettings &settings) const {
|
||||
return settings.viewer ? kPollingIntervalViewer : kPollingIntervalChat;
|
||||
}
|
||||
|
||||
void Stories::maybeSchedulePolling(
|
||||
not_null<Story*> story,
|
||||
const PollingSettings &settings,
|
||||
TimeId now) {
|
||||
const auto last = story->lastUpdateTime();
|
||||
const auto next = last + pollingInterval(settings);
|
||||
const auto left = std::max(next - now, 0) * crl::time(1000) + 1;
|
||||
if (!_pollingTimer.isActive() || _pollingTimer.remainingTime() > left) {
|
||||
_pollingTimer.callOnce(left);
|
||||
}
|
||||
}
|
||||
|
||||
void Stories::sendPollingRequests() {
|
||||
auto min = 0;
|
||||
const auto now = base::unixtime::now();
|
||||
for (const auto &[story, settings] : _pollingSettings) {
|
||||
const auto last = story->lastUpdateTime();
|
||||
const auto next = last + pollingInterval(settings);
|
||||
if (now >= next) {
|
||||
resolve(story->fullId(), nullptr, true);
|
||||
} else {
|
||||
const auto left = (next - now) * crl::time(1000) + 1;
|
||||
if (!min || left < min) {
|
||||
min = left;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (min > 0) {
|
||||
_pollingTimer.callOnce(min);
|
||||
}
|
||||
}
|
||||
|
||||
void Stories::updateUserStoriesState(not_null<PeerData*> peer) {
|
||||
const auto till = _readTill.find(peer->id);
|
||||
const auto readTill = (till != end(_readTill)) ? till->second : 0;
|
||||
|
|
|
@ -153,7 +153,7 @@ public:
|
|||
|
||||
[[nodiscard]] base::expected<not_null<Story*>, NoStory> lookup(
|
||||
FullStoryId id) const;
|
||||
void resolve(FullStoryId id, Fn<void()> done);
|
||||
void resolve(FullStoryId id, Fn<void()> done, bool force = false);
|
||||
[[nodiscard]] std::shared_ptr<HistoryItem> resolveItem(FullStoryId id);
|
||||
[[nodiscard]] std::shared_ptr<HistoryItem> resolveItem(
|
||||
not_null<Story*> story);
|
||||
|
@ -209,6 +209,16 @@ public:
|
|||
StoryId storyMaxId);
|
||||
[[nodiscard]] bool isUnread(not_null<Story*> story);
|
||||
|
||||
enum class Polling {
|
||||
Chat,
|
||||
Viewer,
|
||||
};
|
||||
void registerPolling(not_null<Story*> story, Polling polling);
|
||||
void unregisterPolling(not_null<Story*> story, Polling polling);
|
||||
|
||||
bool registerPolling(FullStoryId id, Polling polling);
|
||||
void unregisterPolling(FullStoryId id, Polling polling);
|
||||
|
||||
private:
|
||||
struct Saved {
|
||||
StoriesIds ids;
|
||||
|
@ -217,6 +227,10 @@ private:
|
|||
bool loaded = false;
|
||||
mtpRequestId requestId = 0;
|
||||
};
|
||||
struct PollingSettings {
|
||||
int chat = 0;
|
||||
int viewer = 0;
|
||||
};
|
||||
|
||||
void parseAndApply(const MTPUserStories &stories);
|
||||
[[nodiscard]] Story *parseAndApply(
|
||||
|
@ -265,6 +279,14 @@ private:
|
|||
void startPreloading(not_null<Story*> story);
|
||||
void preloadFinished(FullStoryId id, bool markAsPreloaded = false);
|
||||
|
||||
[[nodiscard]] int pollingInterval(
|
||||
const PollingSettings &settings) const;
|
||||
void maybeSchedulePolling(
|
||||
not_null<Story*> story,
|
||||
const PollingSettings &settings,
|
||||
TimeId now);
|
||||
void sendPollingRequests();
|
||||
|
||||
const not_null<Session*> _owner;
|
||||
std::unordered_map<
|
||||
PeerId,
|
||||
|
@ -336,6 +358,9 @@ private:
|
|||
mtpRequestId _readTillsRequestId = 0;
|
||||
bool _readTillReceived = false;
|
||||
|
||||
base::flat_map<not_null<Story*>, PollingSettings> _pollingSettings;
|
||||
base::Timer _pollingTimer;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -371,7 +371,12 @@ void Story::applyViewsSlice(
|
|||
}
|
||||
}
|
||||
|
||||
bool Story::applyChanges(StoryMedia media, const MTPDstoryItem &data) {
|
||||
bool Story::applyChanges(
|
||||
StoryMedia media,
|
||||
const MTPDstoryItem &data,
|
||||
TimeId now) {
|
||||
_lastUpdateTime = now;
|
||||
|
||||
const auto pinned = data.is_pinned();
|
||||
const auto edited = data.is_edited();
|
||||
const auto isPublic = data.is_public();
|
||||
|
@ -424,6 +429,10 @@ bool Story::applyChanges(StoryMedia media, const MTPDstoryItem &data) {
|
|||
return true;
|
||||
}
|
||||
|
||||
TimeId Story::lastUpdateTime() const {
|
||||
return _lastUpdateTime;
|
||||
}
|
||||
|
||||
StoryPreload::StoryPreload(not_null<Story*> story, Fn<void()> done)
|
||||
: _story(story)
|
||||
, _done(std::move(done)) {
|
||||
|
|
|
@ -113,7 +113,11 @@ public:
|
|||
const std::vector<StoryView> &slice,
|
||||
int total);
|
||||
|
||||
bool applyChanges(StoryMedia media, const MTPDstoryItem &data);
|
||||
bool applyChanges(
|
||||
StoryMedia media,
|
||||
const MTPDstoryItem &data,
|
||||
TimeId now);
|
||||
[[nodiscard]] TimeId lastUpdateTime() const;
|
||||
|
||||
private:
|
||||
const StoryId _id = 0;
|
||||
|
@ -125,6 +129,7 @@ private:
|
|||
int _views = 0;
|
||||
const TimeId _date = 0;
|
||||
const TimeId _expires = 0;
|
||||
TimeId _lastUpdateTime = 0;
|
||||
bool _pinned : 1 = false;
|
||||
bool _isPublic : 1 = false;
|
||||
bool _closeFriends : 1 = false;
|
||||
|
|
|
@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/effects/path_shift_gradient.h"
|
||||
#include "ui/effects/spoiler_mess.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_streaming.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_click_handler.h"
|
||||
|
@ -134,6 +135,7 @@ Gif::~Gif() {
|
|||
_parent->checkHeavyPart();
|
||||
}
|
||||
}
|
||||
togglePollingStory(false);
|
||||
}
|
||||
|
||||
bool Gif::CanPlayInline(not_null<DocumentData*> document) {
|
||||
|
@ -1432,6 +1434,22 @@ void Gif::dataMediaCreated() const {
|
|||
_dataMedia->videoThumbnailWanted(_realParent->fullId());
|
||||
}
|
||||
history()->owner().registerHeavyViewPart(_parent);
|
||||
togglePollingStory(true);
|
||||
}
|
||||
|
||||
void Gif::togglePollingStory(bool enabled) const {
|
||||
if (!_story || _pollingStory == enabled) {
|
||||
return;
|
||||
}
|
||||
const auto polling = Data::Stories::Polling::Chat;
|
||||
const auto media = _parent->data()->media();
|
||||
const auto id = media ? media->storyId() : FullStoryId();
|
||||
if (!enabled) {
|
||||
_data->owner().stories().unregisterPolling(id, polling);
|
||||
} else if (!_data->owner().stories().registerPolling(id, polling)) {
|
||||
return;
|
||||
}
|
||||
_pollingStory = enabled;
|
||||
}
|
||||
|
||||
bool Gif::uploading() const {
|
||||
|
@ -1686,6 +1704,7 @@ void Gif::unloadHeavyPart() {
|
|||
_thumbCache = QImage();
|
||||
_videoThumbnailFrame = nullptr;
|
||||
_caption.unloadPersistentAnimation();
|
||||
togglePollingStory(false);
|
||||
}
|
||||
|
||||
void Gif::refreshParentId(not_null<HistoryItem*> realParent) {
|
||||
|
@ -1815,6 +1834,7 @@ void Gif::setStreamed(std::unique_ptr<Streamed> value) {
|
|||
_streamed = std::move(value);
|
||||
if (set) {
|
||||
history()->owner().registerHeavyViewPart(_parent);
|
||||
togglePollingStory(true);
|
||||
} else if (removed) {
|
||||
_parent->checkHeavyPart();
|
||||
}
|
||||
|
|
|
@ -208,6 +208,8 @@ private:
|
|||
StateRequest request,
|
||||
QPoint position) const;
|
||||
|
||||
void togglePollingStory(bool enabled) const;
|
||||
|
||||
const not_null<DocumentData*> _data;
|
||||
Ui::Text::String _caption;
|
||||
std::unique_ptr<Streamed> _streamed;
|
||||
|
@ -222,6 +224,7 @@ private:
|
|||
mutable bool _thumbCacheBlurred : 1 = false;
|
||||
mutable bool _thumbIsEllipse : 1 = false;
|
||||
mutable bool _story : 1 = false;
|
||||
mutable bool _pollingStory : 1 = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/painter.h"
|
||||
#include "ui/power_saving.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "data/data_streaming.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
|
@ -101,6 +102,7 @@ Photo::~Photo() {
|
|||
_parent->checkHeavyPart();
|
||||
}
|
||||
}
|
||||
togglePollingStory(false);
|
||||
}
|
||||
|
||||
void Photo::create(FullMsgId contextId, PeerData *chat) {
|
||||
|
@ -145,6 +147,7 @@ void Photo::dataMediaCreated() const {
|
|||
_dataMedia->wanted(PhotoSize::Small, _realParent->fullId());
|
||||
}
|
||||
history()->owner().registerHeavyViewPart(_parent);
|
||||
togglePollingStory(true);
|
||||
}
|
||||
|
||||
bool Photo::hasHeavyPart() const {
|
||||
|
@ -160,6 +163,23 @@ void Photo::unloadHeavyPart() {
|
|||
}
|
||||
_imageCache = QImage();
|
||||
_caption.unloadPersistentAnimation();
|
||||
togglePollingStory(false);
|
||||
}
|
||||
|
||||
void Photo::togglePollingStory(bool enabled) const {
|
||||
const auto pollingStory = (enabled ? 1 : 0);
|
||||
if (!_story || _pollingStory == pollingStory) {
|
||||
return;
|
||||
}
|
||||
const auto polling = Data::Stories::Polling::Chat;
|
||||
const auto media = _parent->data()->media();
|
||||
const auto id = media ? media->storyId() : FullStoryId();
|
||||
if (!enabled) {
|
||||
_data->owner().stories().unregisterPolling(id, polling);
|
||||
} else if (!_data->owner().stories().registerPolling(id, polling)) {
|
||||
return;
|
||||
}
|
||||
_pollingStory = pollingStory;
|
||||
}
|
||||
|
||||
QSize Photo::countOptimalSize() {
|
||||
|
@ -926,6 +946,7 @@ void Photo::setStreamed(std::unique_ptr<Streamed> value) {
|
|||
_streamed = std::move(value);
|
||||
if (set) {
|
||||
history()->owner().registerHeavyViewPart(_parent);
|
||||
togglePollingStory(true);
|
||||
} else if (removed) {
|
||||
_parent->checkHeavyPart();
|
||||
}
|
||||
|
|
|
@ -160,6 +160,8 @@ private:
|
|||
|
||||
[[nodiscard]] QSize photoSize() const;
|
||||
|
||||
void togglePollingStory(bool enabled) const;
|
||||
|
||||
const not_null<PhotoData*> _data;
|
||||
Ui::Text::String _caption;
|
||||
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
|
||||
|
@ -167,10 +169,11 @@ private:
|
|||
const std::unique_ptr<MediaSpoiler> _spoiler;
|
||||
mutable QImage _imageCache;
|
||||
mutable std::optional<Ui::BubbleRounding> _imageCacheRounding;
|
||||
uint32 _serviceWidth : 29 = 0;
|
||||
uint32 _serviceWidth : 28 = 0;
|
||||
mutable uint32 _imageCacheForum : 1 = 0;
|
||||
mutable uint32 _imageCacheBlurred : 1 = 0;
|
||||
mutable uint32 _story : 1 = 0;
|
||||
mutable uint32 _pollingStory : 1 = 0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,9 @@ StoryMention::StoryMention(
|
|||
, _unread(story->owner().stories().isUnread(story) ? 1 : 0) {
|
||||
}
|
||||
|
||||
StoryMention::~StoryMention() = default;
|
||||
StoryMention::~StoryMention() {
|
||||
changeSubscribedTo(0);
|
||||
}
|
||||
|
||||
int StoryMention::top() {
|
||||
return st::msgServiceGiftBoxButtonMargins.top();
|
||||
|
@ -105,13 +107,12 @@ void StoryMention::draw(
|
|||
? history->session().user()
|
||||
: history->peer);
|
||||
_thumbnailFromStory = showStory;
|
||||
_subscribed = 0;
|
||||
changeSubscribedTo(0);
|
||||
}
|
||||
if (!_subscribed) {
|
||||
if (changeSubscribedTo(1)) {
|
||||
_thumbnail->subscribeToUpdates([=] {
|
||||
_parent->data()->history()->owner().requestViewRepaint(_parent);
|
||||
});
|
||||
_subscribed = 1;
|
||||
}
|
||||
|
||||
const auto padding = (geometry.width() - st::storyMentionSize) / 2;
|
||||
|
@ -164,10 +165,26 @@ bool StoryMention::hasHeavyPart() {
|
|||
}
|
||||
|
||||
void StoryMention::unloadHeavyPart() {
|
||||
if (_subscribed) {
|
||||
_subscribed = 0;
|
||||
if (changeSubscribedTo(0)) {
|
||||
_thumbnail->subscribeToUpdates(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool StoryMention::changeSubscribedTo(uint32 value) {
|
||||
Expects(value == 0 || value == 1);
|
||||
|
||||
if (_subscribed == value) {
|
||||
return false;
|
||||
}
|
||||
_subscribed = value;
|
||||
const auto stories = &_parent->history()->owner().stories();
|
||||
if (value) {
|
||||
_parent->history()->owner().registerHeavyViewPart(_parent);
|
||||
stories->registerPolling(_story, Data::Stories::Polling::Chat);
|
||||
} else {
|
||||
stories->unregisterPolling(_story, Data::Stories::Polling::Chat);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -55,6 +55,8 @@ public:
|
|||
private:
|
||||
using Thumbnail = Dialogs::Stories::Thumbnail;
|
||||
|
||||
bool changeSubscribedTo(uint32 value);
|
||||
|
||||
const not_null<Element*> _parent;
|
||||
const not_null<Data::Story*> _story;
|
||||
std::shared_ptr<Thumbnail> _thumbnail;
|
||||
|
|
|
@ -56,6 +56,10 @@ Provider::Provider(not_null<AbstractController*> controller)
|
|||
}, _lifetime);
|
||||
}
|
||||
|
||||
Provider::~Provider() {
|
||||
clear();
|
||||
}
|
||||
|
||||
Type Provider::type() {
|
||||
return Type::PhotoVideo;
|
||||
}
|
||||
|
@ -90,11 +94,20 @@ std::optional<int> Provider::fullCount() {
|
|||
return _slice.fullCount();
|
||||
}
|
||||
|
||||
void Provider::restart() {
|
||||
void Provider::clear() {
|
||||
for (const auto &[storyId, _] : _layouts) {
|
||||
_peer->owner().stories().unregisterPolling(
|
||||
{ _peer->id, storyId },
|
||||
Data::Stories::Polling::Chat);
|
||||
}
|
||||
_layouts.clear();
|
||||
_aroundId = kDefaultAroundId;
|
||||
_idsLimit = kMinimalIdsLimit;
|
||||
_slice = Data::StoriesIdsSlice();
|
||||
}
|
||||
|
||||
void Provider::restart() {
|
||||
clear();
|
||||
refreshViewer();
|
||||
}
|
||||
|
||||
|
@ -210,6 +223,9 @@ void Provider::markLayoutsStale() {
|
|||
void Provider::clearStaleLayouts() {
|
||||
for (auto i = _layouts.begin(); i != _layouts.end();) {
|
||||
if (i->second.stale) {
|
||||
_peer->owner().stories().unregisterPolling(
|
||||
{ _peer->id, i->first },
|
||||
Data::Stories::Polling::Chat);
|
||||
_layoutRemoved.fire(i->second.item.get());
|
||||
const auto taken = _items.take(i->first);
|
||||
i = _layouts.erase(i);
|
||||
|
@ -240,6 +256,9 @@ bool Provider::isAfter(
|
|||
void Provider::itemRemoved(not_null<const HistoryItem*> item) {
|
||||
const auto id = StoryIdFromMsgId(item->id);
|
||||
if (const auto i = _layouts.find(id); i != end(_layouts)) {
|
||||
_peer->owner().stories().unregisterPolling(
|
||||
{ _peer->id, id },
|
||||
Data::Stories::Polling::Chat);
|
||||
_layoutRemoved.fire(i->second.item.get());
|
||||
_layouts.erase(i);
|
||||
}
|
||||
|
@ -253,6 +272,9 @@ BaseLayout *Provider::getLayout(
|
|||
if (auto layout = createLayout(id, delegate)) {
|
||||
layout->initDimensions();
|
||||
it = _layouts.emplace(id, std::move(layout)).first;
|
||||
_peer->owner().stories().registerPolling(
|
||||
{ _peer->id, id },
|
||||
Data::Stories::Polling::Chat);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class Provider final
|
|||
, public base::has_weak_ptr {
|
||||
public:
|
||||
explicit Provider(not_null<AbstractController*> controller);
|
||||
~Provider();
|
||||
|
||||
Media::Type type() override;
|
||||
bool hasSelectRestriction() override;
|
||||
|
@ -99,6 +100,7 @@ private:
|
|||
void itemRemoved(not_null<const HistoryItem*> item);
|
||||
void markLayoutsStale();
|
||||
void clearStaleLayouts();
|
||||
void clear();
|
||||
|
||||
[[nodiscard]] HistoryItem *ensureItem(StoryId id);
|
||||
[[nodiscard]] Media::BaseLayout *getLayout(
|
||||
|
|
|
@ -302,7 +302,9 @@ Controller::Controller(not_null<Delegate*> delegate)
|
|||
_contentFadeAnimation.stop();
|
||||
}
|
||||
|
||||
Controller::~Controller() = default;
|
||||
Controller::~Controller() {
|
||||
changeShown(nullptr);
|
||||
}
|
||||
|
||||
void Controller::updateContentFaded() {
|
||||
if (_contentFaded == _replyActive) {
|
||||
|
@ -480,6 +482,9 @@ void Controller::initLayout() {
|
|||
}
|
||||
|
||||
Data::Story *Controller::story() const {
|
||||
if (!_session) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto maybeStory = _session->data().stories().lookup(_shown);
|
||||
return maybeStory ? maybeStory->get() : nullptr;
|
||||
}
|
||||
|
@ -748,10 +753,9 @@ void Controller::show(
|
|||
.date = story->date(),
|
||||
.edited = story->edited(),
|
||||
});
|
||||
if (_shown == storyId && _session == &story->session()) {
|
||||
if (!changeShown(story)) {
|
||||
return;
|
||||
}
|
||||
_shown = storyId;
|
||||
_viewed = false;
|
||||
invalidate_weak_ptrs(&_viewsLoadGuard);
|
||||
_reactions->hide();
|
||||
|
@ -769,41 +773,72 @@ void Controller::show(
|
|||
.valid = user->isSelf(),
|
||||
});
|
||||
|
||||
const auto session = &story->session();
|
||||
if (_session != session) {
|
||||
_session = session;
|
||||
_sessionLifetime = session->changes().storyUpdates(
|
||||
Data::StoryUpdate::Flag::Destroyed
|
||||
) | rpl::start_with_next([=](Data::StoryUpdate update) {
|
||||
if (update.story->fullId() == _shown) {
|
||||
_delegate->storiesClose();
|
||||
}
|
||||
});
|
||||
session->data().stories().itemsChanged(
|
||||
) | rpl::start_with_next([=](PeerId peerId) {
|
||||
if (_waitingForId.peer == peerId) {
|
||||
checkWaitingFor();
|
||||
}
|
||||
}, _sessionLifetime);
|
||||
session->changes().storyUpdates(
|
||||
Data::StoryUpdate::Flag::Edited
|
||||
) | rpl::filter([=](const Data::StoryUpdate &update) {
|
||||
return (update.story == this->story());
|
||||
}) | rpl::start_with_next([=](const Data::StoryUpdate &update) {
|
||||
show(update.story, _context);
|
||||
_delegate->storiesRedisplay(update.story);
|
||||
}, _sessionLifetime);
|
||||
_sessionLifetime.add([=] {
|
||||
session->data().stories().setPreloadingInViewer({});
|
||||
});
|
||||
}
|
||||
|
||||
stories.loadAround(storyId, context);
|
||||
|
||||
updatePlayingAllowed();
|
||||
user->updateFull();
|
||||
}
|
||||
|
||||
bool Controller::changeShown(Data::Story *story) {
|
||||
const auto id = story ? story->fullId() : FullStoryId();
|
||||
const auto session = story ? &story->session() : nullptr;
|
||||
const auto sessionChanged = (_session != session);
|
||||
if (_shown == id && !sessionChanged) {
|
||||
return false;
|
||||
}
|
||||
if (const auto now = this->story()) {
|
||||
now->owner().stories().unregisterPolling(
|
||||
now,
|
||||
Data::Stories::Polling::Viewer);
|
||||
}
|
||||
if (sessionChanged) {
|
||||
_sessionLifetime.destroy();
|
||||
}
|
||||
_shown = id;
|
||||
_session = session;
|
||||
if (sessionChanged) {
|
||||
subscribeToSession();
|
||||
}
|
||||
if (story) {
|
||||
story->owner().stories().registerPolling(
|
||||
story,
|
||||
Data::Stories::Polling::Viewer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Controller::subscribeToSession() {
|
||||
Expects(!_sessionLifetime);
|
||||
|
||||
if (!_session) {
|
||||
return;
|
||||
}
|
||||
_session->changes().storyUpdates(
|
||||
Data::StoryUpdate::Flag::Destroyed
|
||||
) | rpl::start_with_next([=](Data::StoryUpdate update) {
|
||||
if (update.story->fullId() == _shown) {
|
||||
_delegate->storiesClose();
|
||||
}
|
||||
}, _sessionLifetime);
|
||||
_session->data().stories().itemsChanged(
|
||||
) | rpl::start_with_next([=](PeerId peerId) {
|
||||
if (_waitingForId.peer == peerId) {
|
||||
checkWaitingFor();
|
||||
}
|
||||
}, _sessionLifetime);
|
||||
_session->changes().storyUpdates(
|
||||
Data::StoryUpdate::Flag::Edited
|
||||
) | rpl::filter([=](const Data::StoryUpdate &update) {
|
||||
return (update.story == this->story());
|
||||
}) | rpl::start_with_next([=](const Data::StoryUpdate &update) {
|
||||
show(update.story, _context);
|
||||
_delegate->storiesRedisplay(update.story);
|
||||
}, _sessionLifetime);
|
||||
_sessionLifetime.add([=] {
|
||||
_session->data().stories().setPreloadingInViewer({});
|
||||
});
|
||||
}
|
||||
|
||||
void Controller::updatePlayingAllowed() {
|
||||
if (!_shown) {
|
||||
return;
|
||||
|
|
|
@ -164,6 +164,8 @@ private:
|
|||
class Unsupported;
|
||||
|
||||
void initLayout();
|
||||
bool changeShown(Data::Story *story);
|
||||
void subscribeToSession();
|
||||
void updatePhotoPlayback(const Player::TrackState &state);
|
||||
void updatePlayback(const Player::TrackState &state);
|
||||
void updatePowerSaveBlocker(const Player::TrackState &state);
|
||||
|
|
Loading…
Add table
Reference in a new issue