mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Use only shared media code for pinned tracking.
This commit is contained in:
parent
59b4c5dad9
commit
cd5cad72bd
17 changed files with 162 additions and 273 deletions
|
@ -400,8 +400,6 @@ PRIVATE
|
|||
data/data_photo.h
|
||||
data/data_photo_media.cpp
|
||||
data/data_photo_media.h
|
||||
data/data_pinned_messages.cpp
|
||||
data/data_pinned_messages.h
|
||||
data/data_poll.cpp
|
||||
data/data_poll.h
|
||||
data/data_pts_waiter.cpp
|
||||
|
|
|
@ -3570,6 +3570,9 @@ void ApiWrap::sharedMediaDone(
|
|||
parsed.noSkipRange,
|
||||
parsed.fullCount
|
||||
));
|
||||
if (type == SharedMediaType::Pinned && !parsed.messageIds.empty()) {
|
||||
peer->setHasPinnedMessages(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::requestUserPhotos(
|
||||
|
|
|
@ -444,7 +444,7 @@ PinMessageBox::PinMessageBox(
|
|||
: _peer(peer)
|
||||
, _api(&peer->session().mtp())
|
||||
, _msgId(msgId)
|
||||
, _pinningOld(msgId < peer->topPinnedMessageId())
|
||||
, _pinningOld(msgId < Data::ResolveTopPinnedId(peer))
|
||||
, _text(
|
||||
this,
|
||||
(_pinningOld
|
||||
|
|
|
@ -57,7 +57,7 @@ struct PeerUpdate {
|
|||
Notifications = (1 << 4),
|
||||
Migration = (1 << 5),
|
||||
UnavailableReason = (1 << 6),
|
||||
PinnedMessage = (1 << 7),
|
||||
PinnedMessages = (1 << 7),
|
||||
IsBlocked = (1 << 8),
|
||||
|
||||
// For users
|
||||
|
|
|
@ -769,9 +769,7 @@ void ApplyChannelUpdate(
|
|||
}
|
||||
}
|
||||
if (const auto pinned = update.vpinned_msg_id()) {
|
||||
channel->setTopPinnedMessageId(pinned->v);
|
||||
} else {
|
||||
channel->clearPinnedMessages();
|
||||
SetTopPinnedMessageId(channel, pinned->v);
|
||||
}
|
||||
if (channel->isMegagroup()) {
|
||||
const auto stickerSet = update.vstickerset();
|
||||
|
|
|
@ -333,9 +333,7 @@ void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
|
|||
return QString();
|
||||
}));
|
||||
if (const auto pinned = update.vpinned_msg_id()) {
|
||||
chat->setTopPinnedMessageId(pinned->v);
|
||||
} else {
|
||||
chat->clearPinnedMessages();
|
||||
SetTopPinnedMessageId(chat, pinned->v);
|
||||
}
|
||||
chat->checkFolder(update.vfolder_id().value_or_empty());
|
||||
chat->fullUpdated();
|
||||
|
|
|
@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_session.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_pinned_messages.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/crc32hash.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -464,54 +463,13 @@ bool PeerData::canEditMessagesIndefinitely() const {
|
|||
Unexpected("Peer type in PeerData::canEditMessagesIndefinitely.");
|
||||
}
|
||||
|
||||
MsgId PeerData::topPinnedMessageId() const {
|
||||
return _pinnedMessages ? _pinnedMessages->topId() : 0;
|
||||
bool PeerData::hasPinnedMessages() const {
|
||||
return _hasPinnedMessages;
|
||||
}
|
||||
|
||||
void PeerData::ensurePinnedMessagesCreated() {
|
||||
if (!_pinnedMessages) {
|
||||
_pinnedMessages = std::make_unique<Data::PinnedMessages>(this);
|
||||
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerData::removeEmptyPinnedMessages() {
|
||||
if (_pinnedMessages && _pinnedMessages->empty()) {
|
||||
_pinnedMessages = nullptr;
|
||||
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
bool PeerData::messageIdTooSmall(MsgId messageId) const {
|
||||
if (const auto channel = asChannel()) {
|
||||
return (messageId <= channel->availableMinId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PeerData::setTopPinnedMessageId(MsgId messageId) {
|
||||
if (messageIdTooSmall(messageId)) {
|
||||
clearPinnedMessages();
|
||||
return;
|
||||
}
|
||||
const auto hiddenId = session().settings().hiddenPinnedMessageId(id);
|
||||
if (hiddenId != 0 && hiddenId != messageId) {
|
||||
session().settings().setHiddenPinnedMessageId(id, 0);
|
||||
session().saveSettingsDelayed();
|
||||
}
|
||||
ensurePinnedMessagesCreated();
|
||||
_pinnedMessages->setTopId(messageId);
|
||||
}
|
||||
|
||||
void PeerData::clearPinnedMessages() {
|
||||
if (session().settings().hiddenPinnedMessageId(id) != 0) {
|
||||
session().settings().setHiddenPinnedMessageId(id, 0);
|
||||
session().saveSettingsDelayed();
|
||||
}
|
||||
session().storage().remove(Storage::SharedMediaRemoveAll(
|
||||
id,
|
||||
Storage::SharedMediaType::Pinned));
|
||||
removeEmptyPinnedMessages();
|
||||
void PeerData::setHasPinnedMessages(bool has) {
|
||||
_hasPinnedMessages = has;
|
||||
session().changes().peerUpdated(this, UpdateFlag::PinnedMessages);
|
||||
}
|
||||
|
||||
bool PeerData::canExportChatHistory() const {
|
||||
|
@ -1038,4 +996,36 @@ std::optional<QString> RestrictionError(
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) {
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
if (messageId <= channel->availableMinId()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto &session = peer->session();
|
||||
const auto hiddenId = session.settings().hiddenPinnedMessageId(peer->id);
|
||||
if (hiddenId != 0 && hiddenId != messageId) {
|
||||
session.settings().setHiddenPinnedMessageId(peer->id, 0);
|
||||
session.saveSettingsDelayed();
|
||||
}
|
||||
session.storage().add(Storage::SharedMediaAddExisting(
|
||||
peer->id,
|
||||
Storage::SharedMediaType::Pinned,
|
||||
messageId,
|
||||
{ messageId, ServerMaxMsgId }));
|
||||
peer->setHasPinnedMessages(true);
|
||||
}
|
||||
|
||||
MsgId ResolveTopPinnedId(not_null<PeerData*> peer) {
|
||||
const auto slice = peer->session().storage().snapshot(
|
||||
Storage::SharedMediaQuery(
|
||||
Storage::SharedMediaKey(
|
||||
peer->id,
|
||||
Storage::SharedMediaType::Pinned,
|
||||
ServerMaxMsgId - 1),
|
||||
1,
|
||||
1));
|
||||
return slice.messageIds.empty() ? 0 : slice.messageIds.back();
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -29,8 +29,6 @@ class Session;
|
|||
namespace Data {
|
||||
|
||||
class Session;
|
||||
class PinnedMessages;
|
||||
struct PinnedAroundId;
|
||||
|
||||
int PeerColorIndex(PeerId peerId);
|
||||
int PeerColorIndex(int32 bareId);
|
||||
|
@ -328,12 +326,9 @@ public:
|
|||
|
||||
[[nodiscard]] bool canPinMessages() const;
|
||||
[[nodiscard]] bool canEditMessagesIndefinitely() const;
|
||||
[[nodiscard]] MsgId topPinnedMessageId() const;
|
||||
void setTopPinnedMessageId(MsgId messageId);
|
||||
void clearPinnedMessages();
|
||||
Data::PinnedMessages *currentPinnedMessages() const {
|
||||
return _pinnedMessages.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasPinnedMessages() const;
|
||||
void setHasPinnedMessages(bool has);
|
||||
|
||||
[[nodiscard]] bool canExportChatHistory() const;
|
||||
|
||||
|
@ -412,10 +407,6 @@ private:
|
|||
-> const std::vector<Data::UnavailableReason> &;
|
||||
|
||||
void setUserpicChecked(PhotoId photoId, const ImageLocation &location);
|
||||
void ensurePinnedMessagesCreated();
|
||||
void removeEmptyPinnedMessages();
|
||||
|
||||
[[nodiscard]] bool messageIdTooSmall(MsgId messageId) const;
|
||||
|
||||
static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL);
|
||||
|
||||
|
@ -433,7 +424,7 @@ private:
|
|||
base::flat_set<QChar> _nameFirstLetters;
|
||||
|
||||
crl::time _lastFullUpdate = 0;
|
||||
std::unique_ptr<Data::PinnedMessages> _pinnedMessages;
|
||||
bool _hasPinnedMessages = false;
|
||||
|
||||
Settings _settings = { kSettingsUnknown };
|
||||
BlockStatus _blockStatus = BlockStatus::Unknown;
|
||||
|
@ -451,4 +442,7 @@ std::optional<QString> RestrictionError(
|
|||
not_null<PeerData*> peer,
|
||||
ChatRestriction restriction);
|
||||
|
||||
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId);
|
||||
[[nodiscard]] MsgId ResolveTopPinnedId(not_null<PeerData*> peer);
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/data_pinned_messages.h"
|
||||
|
||||
#include "data/data_peer.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "data/data_shared_media.h"
|
||||
#include "data/data_sparse_ids.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto PinnedType = Storage::SharedMediaType::Pinned;
|
||||
|
||||
using Storage::SharedMediaQuery;
|
||||
using Storage::SharedMediaKey;
|
||||
using Storage::SharedMediaResult;
|
||||
|
||||
} // namespace
|
||||
|
||||
PinnedMessages::PinnedMessages(not_null<PeerData*> peer)
|
||||
: _peer(peer)
|
||||
, _storage(_peer->session().storage()) {
|
||||
}
|
||||
|
||||
bool PinnedMessages::empty() const {
|
||||
return _storage.empty(SharedMediaKey(_peer->id, PinnedType, 0));
|
||||
}
|
||||
|
||||
MsgId PinnedMessages::topId() const {
|
||||
const auto slice = _storage.snapshot(
|
||||
SharedMediaQuery(
|
||||
SharedMediaKey(_peer->id, PinnedType, ServerMaxMsgId),
|
||||
1,
|
||||
1));
|
||||
return slice.messageIds.empty() ? 0 : slice.messageIds.back();
|
||||
}
|
||||
|
||||
rpl::producer<PinnedAroundId> PinnedMessages::viewer(
|
||||
MsgId aroundId,
|
||||
int limit) const {
|
||||
return SharedMediaViewer(
|
||||
&_peer->session(),
|
||||
SharedMediaKey(_peer->id, PinnedType, aroundId),
|
||||
limit,
|
||||
limit
|
||||
) | rpl::map([](const SparseIdsSlice &result) {
|
||||
auto data = PinnedAroundId();
|
||||
data.fullCount = result.fullCount();
|
||||
data.skippedBefore = result.skippedBefore();
|
||||
data.skippedAfter = result.skippedAfter();
|
||||
const auto count = result.size();
|
||||
data.ids.reserve(count);
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
data.ids.push_back(result[i]);
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
void PinnedMessages::setTopId(MsgId messageId) {
|
||||
while (true) {
|
||||
auto top = topId();
|
||||
if (top > messageId) {
|
||||
_storage.remove(Storage::SharedMediaRemoveOne(
|
||||
_peer->id,
|
||||
PinnedType,
|
||||
top));
|
||||
} else if (top == messageId) {
|
||||
return;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_storage.add(Storage::SharedMediaAddNew(
|
||||
_peer->id,
|
||||
PinnedType,
|
||||
messageId));
|
||||
}
|
||||
|
||||
} // namespace Data
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_messages.h"
|
||||
#include "base/weak_ptr.h"
|
||||
|
||||
namespace Storage {
|
||||
class Facade;
|
||||
} // namespace Storage
|
||||
|
||||
namespace Data {
|
||||
|
||||
struct PinnedAroundId {
|
||||
std::vector<MsgId> ids;
|
||||
std::optional<int> skippedBefore;
|
||||
std::optional<int> skippedAfter;
|
||||
std::optional<int> fullCount;
|
||||
};
|
||||
|
||||
class PinnedMessages final : public base::has_weak_ptr {
|
||||
public:
|
||||
explicit PinnedMessages(not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] bool empty() const;
|
||||
[[nodiscard]] MsgId topId() const;
|
||||
[[nodiscard]] rpl::producer<PinnedAroundId> viewer(
|
||||
MsgId aroundId,
|
||||
int limit) const;
|
||||
void setTopId(MsgId messageId);
|
||||
|
||||
private:
|
||||
const not_null<PeerData*> _peer;
|
||||
Storage::Facade &_storage;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
|
@ -262,9 +262,7 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
|||
user->setBotInfoVersion(-1);
|
||||
}
|
||||
if (const auto pinned = update.vpinned_msg_id()) {
|
||||
user->setTopPinnedMessageId(pinned->v);
|
||||
} else {
|
||||
user->clearPinnedMessages();
|
||||
SetTopPinnedMessageId(user, pinned->v);
|
||||
}
|
||||
user->setFullFlags(update.vflags().v);
|
||||
user->setIsBlocked(update.is_blocked());
|
||||
|
|
|
@ -705,6 +705,9 @@ not_null<HistoryItem*> History::addNewToBack(
|
|||
sharedMediaTypes,
|
||||
item->id,
|
||||
{ from, till }));
|
||||
if (sharedMediaTypes.test(Storage::SharedMediaType::Pinned)) {
|
||||
peer->setHasPinnedMessages(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item->from()->id) {
|
||||
|
@ -1008,6 +1011,7 @@ void History::applyServiceChanges(
|
|||
Storage::SharedMediaType::Pinned,
|
||||
{ id },
|
||||
{ id, ServerMaxMsgId }));
|
||||
peer->setHasPinnedMessages(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1348,6 +1352,9 @@ void History::addToSharedMedia(
|
|||
type,
|
||||
std::move(medias[i]),
|
||||
{ from, till }));
|
||||
if (type == Storage::SharedMediaType::Pinned) {
|
||||
peer->setHasPinnedMessages(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -355,6 +355,7 @@ void HistoryItem::setIsPinned(bool pinned) {
|
|||
Storage::SharedMediaType::Pinned,
|
||||
id,
|
||||
{ id, id }));
|
||||
history()->peer->setHasPinnedMessages(true);
|
||||
} else {
|
||||
_flags &= ~MTPDmessage::Flag::f_pinned;
|
||||
history()->session().storage().remove(Storage::SharedMediaRemoveOne(
|
||||
|
@ -489,12 +490,12 @@ void HistoryItem::indexAsNewItem() {
|
|||
addToUnreadMentions(UnreadMentionType::New);
|
||||
if (const auto types = sharedMediaTypes()) {
|
||||
_history->session().storage().add(Storage::SharedMediaAddNew(
|
||||
history()->peer->id,
|
||||
_history->peer->id,
|
||||
types,
|
||||
id));
|
||||
}
|
||||
if (isPinned()) {
|
||||
_history->peer->setTopPinnedMessageId(id);
|
||||
if (types.test(Storage::SharedMediaType::Pinned)) {
|
||||
_history->peer->setHasPinnedMessages(true);
|
||||
}
|
||||
}
|
||||
//if (const auto channel = history()->peer->asChannel()) { // #feed
|
||||
// if (const auto feed = channel->feed()) {
|
||||
|
|
|
@ -567,7 +567,7 @@ HistoryWidget::HistoryWidget(
|
|||
| UpdateFlag::ChannelLinkedChat
|
||||
| UpdateFlag::Slowmode
|
||||
| UpdateFlag::BotStartToken
|
||||
| UpdateFlag::PinnedMessage
|
||||
| UpdateFlag::PinnedMessages
|
||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||
return (update.peer.get() == _peer);
|
||||
}) | rpl::map([](const Data::PeerUpdate &update) {
|
||||
|
@ -608,7 +608,7 @@ HistoryWidget::HistoryWidget(
|
|||
| UpdateFlag::ChannelLinkedChat)) {
|
||||
handlePeerUpdate();
|
||||
}
|
||||
if (_pinnedTracker && (flags & UpdateFlag::PinnedMessage)) {
|
||||
if (_pinnedTracker && (flags & UpdateFlag::PinnedMessages)) {
|
||||
checkPinnedBarState();
|
||||
}
|
||||
}, lifetime());
|
||||
|
@ -5184,7 +5184,7 @@ void HistoryWidget::updatePinnedViewer() {
|
|||
}();
|
||||
const auto lessThanId = item
|
||||
? (item->data()->id + (offset > 0 ? 1 : 0))
|
||||
: (_history->peer->topPinnedMessageId() + 1);
|
||||
: (ServerMaxMsgId - 1);
|
||||
_pinnedTracker->trackAround(lessThanId);
|
||||
}
|
||||
|
||||
|
@ -5193,13 +5193,7 @@ void HistoryWidget::setupPinnedTracker() {
|
|||
|
||||
_pinnedTracker = std::make_unique<HistoryView::PinnedTracker>(_history);
|
||||
_pinnedBar = nullptr;
|
||||
Info::Profile::SharedMediaCountValue(
|
||||
_history->peer,
|
||||
_migrated ? _migrated->peer.get() : nullptr,
|
||||
Storage::SharedMediaType::Pinned
|
||||
) | rpl::start_with_next([=] {
|
||||
checkPinnedBarState();
|
||||
}, _pinnedTracker->lifetime());
|
||||
checkPinnedBarState();
|
||||
}
|
||||
|
||||
void HistoryWidget::checkPinnedBarState() {
|
||||
|
@ -5208,7 +5202,7 @@ void HistoryWidget::checkPinnedBarState() {
|
|||
const auto hiddenId = _peer->canPinMessages()
|
||||
? MsgId(0)
|
||||
: session().settings().hiddenPinnedMessageId(_peer->id);
|
||||
const auto currentPinnedId = _peer->topPinnedMessageId();
|
||||
const auto currentPinnedId = Data::ResolveTopPinnedId(_peer);
|
||||
if (currentPinnedId == hiddenId) {
|
||||
if (_pinnedBar) {
|
||||
_pinnedTracker->reset();
|
||||
|
@ -5601,7 +5595,7 @@ void HistoryWidget::hidePinnedMessage() {
|
|||
if (_peer->canPinMessages()) {
|
||||
unpinMessage({ peerToChannel(_peer->id), id.message });
|
||||
} else {
|
||||
const auto top = _peer->topPinnedMessageId();
|
||||
const auto top = Data::ResolveTopPinnedId(_peer);
|
||||
if (top) {
|
||||
session().settings().setHiddenPinnedMessageId(_peer->id, top);
|
||||
session().saveSettingsDelayed();
|
||||
|
|
|
@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_pinned_messages.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_sparse_ids.h"
|
||||
#include "data/data_shared_media.h"
|
||||
|
|
|
@ -8,9 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_pinned_tracker.h"
|
||||
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_pinned_messages.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_shared_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/storage_facade.h"
|
||||
|
@ -21,16 +21,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace HistoryView {
|
||||
namespace{
|
||||
|
||||
constexpr auto kLoadedLimit = 4;
|
||||
constexpr auto kLoadedLimit = 5;
|
||||
constexpr auto kChangeViewerLimit = 2;
|
||||
|
||||
} // namespace
|
||||
|
||||
PinnedTracker::PinnedTracker(not_null<History*> history) : _history(history) {
|
||||
_history->session().changes().peerFlagsValue(
|
||||
_history->peer,
|
||||
Data::PeerUpdate::Flag::PinnedMessage
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshData();
|
||||
Data::PeerUpdate::Flag::PinnedMessages
|
||||
) | rpl::map([=] {
|
||||
return _history->peer->hasPinnedMessages();
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool has) {
|
||||
if (has) {
|
||||
refreshViewer();
|
||||
} else {
|
||||
clear();
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
|
@ -48,60 +56,85 @@ PinnedId PinnedTracker::currentMessageId() const {
|
|||
return _current.current();
|
||||
}
|
||||
|
||||
void PinnedTracker::refreshData() {
|
||||
const auto now = _history->peer->currentPinnedMessages();
|
||||
if (!now) {
|
||||
_dataLifetime.destroy();
|
||||
_current = PinnedId();
|
||||
} else if (_data.get() != now) {
|
||||
_dataLifetime.destroy();
|
||||
_data = now;
|
||||
if (_aroundId) {
|
||||
setupViewer(now);
|
||||
void PinnedTracker::refreshViewer() {
|
||||
if (_viewerAroundId == _aroundId) {
|
||||
return;
|
||||
}
|
||||
_dataLifetime.destroy();
|
||||
_viewerAroundId = _aroundId;
|
||||
SharedMediaViewer(
|
||||
&_history->peer->session(),
|
||||
Storage::SharedMediaKey(
|
||||
_history->peer->id,
|
||||
Storage::SharedMediaType::Pinned,
|
||||
_viewerAroundId),
|
||||
kLoadedLimit,
|
||||
kLoadedLimit
|
||||
) | rpl::start_with_next([=](const SparseIdsSlice &result) {
|
||||
_slice.fullCount = result.fullCount();
|
||||
_slice.skippedBefore = result.skippedBefore();
|
||||
_slice.skippedAfter = result.skippedAfter();
|
||||
_slice.ids.clear();
|
||||
const auto count = result.size();
|
||||
_slice.ids.reserve(count);
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
_slice.ids.push_back(result[i]);
|
||||
}
|
||||
refreshCurrentFromSlice();
|
||||
if (_slice.fullCount == 0) {
|
||||
_history->peer->setHasPinnedMessages(false);
|
||||
}
|
||||
}, _dataLifetime);
|
||||
}
|
||||
|
||||
void PinnedTracker::refreshCurrentFromSlice() {
|
||||
const auto i = ranges::lower_bound(_slice.ids, _aroundId);
|
||||
const auto empty = _slice.ids.empty();
|
||||
const auto before = int(i - begin(_slice.ids));
|
||||
const auto after = int(end(_slice.ids) - i);
|
||||
const auto haveValidData = (before > 0 || _slice.skippedBefore == 0)
|
||||
&& (after > 0 || _slice.skippedAfter == 0);
|
||||
const auto nearEnd = !haveValidData
|
||||
|| (before <= kChangeViewerLimit && _slice.skippedBefore != 0)
|
||||
|| (after <= kChangeViewerLimit && _slice.skippedAfter != 0);
|
||||
if (haveValidData) {
|
||||
const auto count = std::max(
|
||||
_slice.fullCount.value_or(1),
|
||||
int(_slice.ids.size()));
|
||||
const auto index = _slice.skippedBefore.has_value()
|
||||
? (*_slice.skippedBefore + before)
|
||||
: _slice.skippedAfter.has_value()
|
||||
? (count - *_slice.skippedAfter - after)
|
||||
: 1;
|
||||
if (i != begin(_slice.ids)) {
|
||||
_current = PinnedId{ *(i - 1), index - 1, count };
|
||||
} else if (!_slice.ids.empty()) {
|
||||
_current = PinnedId{ _slice.ids.front(), 0, count };
|
||||
} else {
|
||||
_current = PinnedId();
|
||||
}
|
||||
}
|
||||
if (nearEnd) {
|
||||
refreshViewer();
|
||||
}
|
||||
}
|
||||
|
||||
void PinnedTracker::clear() {
|
||||
_dataLifetime.destroy();
|
||||
_viewerAroundId = 0;
|
||||
_current = PinnedId();
|
||||
}
|
||||
|
||||
void PinnedTracker::trackAround(MsgId messageId) {
|
||||
if (_aroundId == messageId) {
|
||||
return;
|
||||
}
|
||||
_dataLifetime.destroy();
|
||||
_aroundId = messageId;
|
||||
if (!_aroundId) {
|
||||
_current = PinnedId();
|
||||
} else if (const auto now = _data.get()) {
|
||||
setupViewer(now);
|
||||
clear();
|
||||
} else {
|
||||
refreshCurrentFromSlice();
|
||||
}
|
||||
}
|
||||
|
||||
void PinnedTracker::setupViewer(not_null<Data::PinnedMessages*> data) {
|
||||
data->viewer(
|
||||
_aroundId,
|
||||
kLoadedLimit + 2
|
||||
) | rpl::start_with_next([=](const Data::PinnedAroundId &snapshot) {
|
||||
const auto i = ranges::lower_bound(snapshot.ids, _aroundId);
|
||||
const auto empty = snapshot.ids.empty();
|
||||
const auto before = int(i - begin(snapshot.ids));
|
||||
const auto after = int(end(snapshot.ids) - i);
|
||||
if (snapshot.ids.empty()) {
|
||||
_current = PinnedId();
|
||||
return;
|
||||
}
|
||||
const auto count = std::max(
|
||||
snapshot.fullCount.value_or(1),
|
||||
int(snapshot.ids.size()));
|
||||
const auto index = snapshot.skippedBefore.has_value()
|
||||
? (*snapshot.skippedBefore + before)
|
||||
: snapshot.skippedAfter.has_value()
|
||||
? (count - *snapshot.skippedAfter - after)
|
||||
: 1;
|
||||
if (i != begin(snapshot.ids)) {
|
||||
_current = PinnedId{ *(i - 1), index - 1, count };
|
||||
} else if (snapshot.skippedBefore == 0) {
|
||||
_current = PinnedId{ snapshot.ids.front(), 0, count };
|
||||
}
|
||||
}, _dataLifetime);
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
class History;
|
||||
|
||||
namespace Data {
|
||||
class PinnedMessages;
|
||||
enum class LoadDirection : char;
|
||||
} // namespace Data
|
||||
|
||||
|
@ -46,16 +45,24 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void refreshData();
|
||||
void setupViewer(not_null<Data::PinnedMessages*> data);
|
||||
struct Slice {
|
||||
std::vector<MsgId> ids;
|
||||
std::optional<int> fullCount;
|
||||
std::optional<int> skippedBefore;
|
||||
std::optional<int> skippedAfter;
|
||||
};
|
||||
void clear();
|
||||
void refreshViewer();
|
||||
void refreshCurrentFromSlice();
|
||||
|
||||
const not_null<History*> _history;
|
||||
|
||||
base::weak_ptr<Data::PinnedMessages> _data;
|
||||
rpl::variable<PinnedId> _current;
|
||||
rpl::lifetime _dataLifetime;
|
||||
|
||||
MsgId _aroundId = 0;
|
||||
MsgId _viewerAroundId = 0;
|
||||
Slice _slice;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue