mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +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.h
|
||||||
data/data_photo_media.cpp
|
data/data_photo_media.cpp
|
||||||
data/data_photo_media.h
|
data/data_photo_media.h
|
||||||
data/data_pinned_messages.cpp
|
|
||||||
data/data_pinned_messages.h
|
|
||||||
data/data_poll.cpp
|
data/data_poll.cpp
|
||||||
data/data_poll.h
|
data/data_poll.h
|
||||||
data/data_pts_waiter.cpp
|
data/data_pts_waiter.cpp
|
||||||
|
|
|
@ -3570,6 +3570,9 @@ void ApiWrap::sharedMediaDone(
|
||||||
parsed.noSkipRange,
|
parsed.noSkipRange,
|
||||||
parsed.fullCount
|
parsed.fullCount
|
||||||
));
|
));
|
||||||
|
if (type == SharedMediaType::Pinned && !parsed.messageIds.empty()) {
|
||||||
|
peer->setHasPinnedMessages(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::requestUserPhotos(
|
void ApiWrap::requestUserPhotos(
|
||||||
|
|
|
@ -444,7 +444,7 @@ PinMessageBox::PinMessageBox(
|
||||||
: _peer(peer)
|
: _peer(peer)
|
||||||
, _api(&peer->session().mtp())
|
, _api(&peer->session().mtp())
|
||||||
, _msgId(msgId)
|
, _msgId(msgId)
|
||||||
, _pinningOld(msgId < peer->topPinnedMessageId())
|
, _pinningOld(msgId < Data::ResolveTopPinnedId(peer))
|
||||||
, _text(
|
, _text(
|
||||||
this,
|
this,
|
||||||
(_pinningOld
|
(_pinningOld
|
||||||
|
|
|
@ -57,7 +57,7 @@ struct PeerUpdate {
|
||||||
Notifications = (1 << 4),
|
Notifications = (1 << 4),
|
||||||
Migration = (1 << 5),
|
Migration = (1 << 5),
|
||||||
UnavailableReason = (1 << 6),
|
UnavailableReason = (1 << 6),
|
||||||
PinnedMessage = (1 << 7),
|
PinnedMessages = (1 << 7),
|
||||||
IsBlocked = (1 << 8),
|
IsBlocked = (1 << 8),
|
||||||
|
|
||||||
// For users
|
// For users
|
||||||
|
|
|
@ -769,9 +769,7 @@ void ApplyChannelUpdate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (const auto pinned = update.vpinned_msg_id()) {
|
if (const auto pinned = update.vpinned_msg_id()) {
|
||||||
channel->setTopPinnedMessageId(pinned->v);
|
SetTopPinnedMessageId(channel, pinned->v);
|
||||||
} else {
|
|
||||||
channel->clearPinnedMessages();
|
|
||||||
}
|
}
|
||||||
if (channel->isMegagroup()) {
|
if (channel->isMegagroup()) {
|
||||||
const auto stickerSet = update.vstickerset();
|
const auto stickerSet = update.vstickerset();
|
||||||
|
|
|
@ -333,9 +333,7 @@ void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
|
||||||
return QString();
|
return QString();
|
||||||
}));
|
}));
|
||||||
if (const auto pinned = update.vpinned_msg_id()) {
|
if (const auto pinned = update.vpinned_msg_id()) {
|
||||||
chat->setTopPinnedMessageId(pinned->v);
|
SetTopPinnedMessageId(chat, pinned->v);
|
||||||
} else {
|
|
||||||
chat->clearPinnedMessages();
|
|
||||||
}
|
}
|
||||||
chat->checkFolder(update.vfolder_id().value_or_empty());
|
chat->checkFolder(update.vfolder_id().value_or_empty());
|
||||||
chat->fullUpdated();
|
chat->fullUpdated();
|
||||||
|
|
|
@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_pinned_messages.h"
|
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "base/crc32hash.h"
|
#include "base/crc32hash.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -464,54 +463,13 @@ bool PeerData::canEditMessagesIndefinitely() const {
|
||||||
Unexpected("Peer type in PeerData::canEditMessagesIndefinitely.");
|
Unexpected("Peer type in PeerData::canEditMessagesIndefinitely.");
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgId PeerData::topPinnedMessageId() const {
|
bool PeerData::hasPinnedMessages() const {
|
||||||
return _pinnedMessages ? _pinnedMessages->topId() : 0;
|
return _hasPinnedMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerData::ensurePinnedMessagesCreated() {
|
void PeerData::setHasPinnedMessages(bool has) {
|
||||||
if (!_pinnedMessages) {
|
_hasPinnedMessages = has;
|
||||||
_pinnedMessages = std::make_unique<Data::PinnedMessages>(this);
|
session().changes().peerUpdated(this, UpdateFlag::PinnedMessages);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerData::canExportChatHistory() const {
|
bool PeerData::canExportChatHistory() const {
|
||||||
|
@ -1038,4 +996,36 @@ std::optional<QString> RestrictionError(
|
||||||
return std::nullopt;
|
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
|
} // namespace Data
|
||||||
|
|
|
@ -29,8 +29,6 @@ class Session;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
class PinnedMessages;
|
|
||||||
struct PinnedAroundId;
|
|
||||||
|
|
||||||
int PeerColorIndex(PeerId peerId);
|
int PeerColorIndex(PeerId peerId);
|
||||||
int PeerColorIndex(int32 bareId);
|
int PeerColorIndex(int32 bareId);
|
||||||
|
@ -328,12 +326,9 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] bool canPinMessages() const;
|
[[nodiscard]] bool canPinMessages() const;
|
||||||
[[nodiscard]] bool canEditMessagesIndefinitely() const;
|
[[nodiscard]] bool canEditMessagesIndefinitely() const;
|
||||||
[[nodiscard]] MsgId topPinnedMessageId() const;
|
|
||||||
void setTopPinnedMessageId(MsgId messageId);
|
[[nodiscard]] bool hasPinnedMessages() const;
|
||||||
void clearPinnedMessages();
|
void setHasPinnedMessages(bool has);
|
||||||
Data::PinnedMessages *currentPinnedMessages() const {
|
|
||||||
return _pinnedMessages.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool canExportChatHistory() const;
|
[[nodiscard]] bool canExportChatHistory() const;
|
||||||
|
|
||||||
|
@ -412,10 +407,6 @@ private:
|
||||||
-> const std::vector<Data::UnavailableReason> &;
|
-> const std::vector<Data::UnavailableReason> &;
|
||||||
|
|
||||||
void setUserpicChecked(PhotoId photoId, const ImageLocation &location);
|
void setUserpicChecked(PhotoId photoId, const ImageLocation &location);
|
||||||
void ensurePinnedMessagesCreated();
|
|
||||||
void removeEmptyPinnedMessages();
|
|
||||||
|
|
||||||
[[nodiscard]] bool messageIdTooSmall(MsgId messageId) const;
|
|
||||||
|
|
||||||
static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL);
|
static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL);
|
||||||
|
|
||||||
|
@ -433,7 +424,7 @@ private:
|
||||||
base::flat_set<QChar> _nameFirstLetters;
|
base::flat_set<QChar> _nameFirstLetters;
|
||||||
|
|
||||||
crl::time _lastFullUpdate = 0;
|
crl::time _lastFullUpdate = 0;
|
||||||
std::unique_ptr<Data::PinnedMessages> _pinnedMessages;
|
bool _hasPinnedMessages = false;
|
||||||
|
|
||||||
Settings _settings = { kSettingsUnknown };
|
Settings _settings = { kSettingsUnknown };
|
||||||
BlockStatus _blockStatus = BlockStatus::Unknown;
|
BlockStatus _blockStatus = BlockStatus::Unknown;
|
||||||
|
@ -451,4 +442,7 @@ std::optional<QString> RestrictionError(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
ChatRestriction restriction);
|
ChatRestriction restriction);
|
||||||
|
|
||||||
|
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId);
|
||||||
|
[[nodiscard]] MsgId ResolveTopPinnedId(not_null<PeerData*> peer);
|
||||||
|
|
||||||
} // namespace Data
|
} // 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);
|
user->setBotInfoVersion(-1);
|
||||||
}
|
}
|
||||||
if (const auto pinned = update.vpinned_msg_id()) {
|
if (const auto pinned = update.vpinned_msg_id()) {
|
||||||
user->setTopPinnedMessageId(pinned->v);
|
SetTopPinnedMessageId(user, pinned->v);
|
||||||
} else {
|
|
||||||
user->clearPinnedMessages();
|
|
||||||
}
|
}
|
||||||
user->setFullFlags(update.vflags().v);
|
user->setFullFlags(update.vflags().v);
|
||||||
user->setIsBlocked(update.is_blocked());
|
user->setIsBlocked(update.is_blocked());
|
||||||
|
|
|
@ -705,6 +705,9 @@ not_null<HistoryItem*> History::addNewToBack(
|
||||||
sharedMediaTypes,
|
sharedMediaTypes,
|
||||||
item->id,
|
item->id,
|
||||||
{ from, till }));
|
{ from, till }));
|
||||||
|
if (sharedMediaTypes.test(Storage::SharedMediaType::Pinned)) {
|
||||||
|
peer->setHasPinnedMessages(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item->from()->id) {
|
if (item->from()->id) {
|
||||||
|
@ -1008,6 +1011,7 @@ void History::applyServiceChanges(
|
||||||
Storage::SharedMediaType::Pinned,
|
Storage::SharedMediaType::Pinned,
|
||||||
{ id },
|
{ id },
|
||||||
{ id, ServerMaxMsgId }));
|
{ id, ServerMaxMsgId }));
|
||||||
|
peer->setHasPinnedMessages(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1348,6 +1352,9 @@ void History::addToSharedMedia(
|
||||||
type,
|
type,
|
||||||
std::move(medias[i]),
|
std::move(medias[i]),
|
||||||
{ from, till }));
|
{ from, till }));
|
||||||
|
if (type == Storage::SharedMediaType::Pinned) {
|
||||||
|
peer->setHasPinnedMessages(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,6 +355,7 @@ void HistoryItem::setIsPinned(bool pinned) {
|
||||||
Storage::SharedMediaType::Pinned,
|
Storage::SharedMediaType::Pinned,
|
||||||
id,
|
id,
|
||||||
{ id, id }));
|
{ id, id }));
|
||||||
|
history()->peer->setHasPinnedMessages(true);
|
||||||
} else {
|
} else {
|
||||||
_flags &= ~MTPDmessage::Flag::f_pinned;
|
_flags &= ~MTPDmessage::Flag::f_pinned;
|
||||||
history()->session().storage().remove(Storage::SharedMediaRemoveOne(
|
history()->session().storage().remove(Storage::SharedMediaRemoveOne(
|
||||||
|
@ -489,12 +490,12 @@ void HistoryItem::indexAsNewItem() {
|
||||||
addToUnreadMentions(UnreadMentionType::New);
|
addToUnreadMentions(UnreadMentionType::New);
|
||||||
if (const auto types = sharedMediaTypes()) {
|
if (const auto types = sharedMediaTypes()) {
|
||||||
_history->session().storage().add(Storage::SharedMediaAddNew(
|
_history->session().storage().add(Storage::SharedMediaAddNew(
|
||||||
history()->peer->id,
|
_history->peer->id,
|
||||||
types,
|
types,
|
||||||
id));
|
id));
|
||||||
}
|
if (types.test(Storage::SharedMediaType::Pinned)) {
|
||||||
if (isPinned()) {
|
_history->peer->setHasPinnedMessages(true);
|
||||||
_history->peer->setTopPinnedMessageId(id);
|
}
|
||||||
}
|
}
|
||||||
//if (const auto channel = history()->peer->asChannel()) { // #feed
|
//if (const auto channel = history()->peer->asChannel()) { // #feed
|
||||||
// if (const auto feed = channel->feed()) {
|
// if (const auto feed = channel->feed()) {
|
||||||
|
|
|
@ -567,7 +567,7 @@ HistoryWidget::HistoryWidget(
|
||||||
| UpdateFlag::ChannelLinkedChat
|
| UpdateFlag::ChannelLinkedChat
|
||||||
| UpdateFlag::Slowmode
|
| UpdateFlag::Slowmode
|
||||||
| UpdateFlag::BotStartToken
|
| UpdateFlag::BotStartToken
|
||||||
| UpdateFlag::PinnedMessage
|
| UpdateFlag::PinnedMessages
|
||||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||||
return (update.peer.get() == _peer);
|
return (update.peer.get() == _peer);
|
||||||
}) | rpl::map([](const Data::PeerUpdate &update) {
|
}) | rpl::map([](const Data::PeerUpdate &update) {
|
||||||
|
@ -608,7 +608,7 @@ HistoryWidget::HistoryWidget(
|
||||||
| UpdateFlag::ChannelLinkedChat)) {
|
| UpdateFlag::ChannelLinkedChat)) {
|
||||||
handlePeerUpdate();
|
handlePeerUpdate();
|
||||||
}
|
}
|
||||||
if (_pinnedTracker && (flags & UpdateFlag::PinnedMessage)) {
|
if (_pinnedTracker && (flags & UpdateFlag::PinnedMessages)) {
|
||||||
checkPinnedBarState();
|
checkPinnedBarState();
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
@ -5184,7 +5184,7 @@ void HistoryWidget::updatePinnedViewer() {
|
||||||
}();
|
}();
|
||||||
const auto lessThanId = item
|
const auto lessThanId = item
|
||||||
? (item->data()->id + (offset > 0 ? 1 : 0))
|
? (item->data()->id + (offset > 0 ? 1 : 0))
|
||||||
: (_history->peer->topPinnedMessageId() + 1);
|
: (ServerMaxMsgId - 1);
|
||||||
_pinnedTracker->trackAround(lessThanId);
|
_pinnedTracker->trackAround(lessThanId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5193,13 +5193,7 @@ void HistoryWidget::setupPinnedTracker() {
|
||||||
|
|
||||||
_pinnedTracker = std::make_unique<HistoryView::PinnedTracker>(_history);
|
_pinnedTracker = std::make_unique<HistoryView::PinnedTracker>(_history);
|
||||||
_pinnedBar = nullptr;
|
_pinnedBar = nullptr;
|
||||||
Info::Profile::SharedMediaCountValue(
|
checkPinnedBarState();
|
||||||
_history->peer,
|
|
||||||
_migrated ? _migrated->peer.get() : nullptr,
|
|
||||||
Storage::SharedMediaType::Pinned
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
checkPinnedBarState();
|
|
||||||
}, _pinnedTracker->lifetime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::checkPinnedBarState() {
|
void HistoryWidget::checkPinnedBarState() {
|
||||||
|
@ -5208,7 +5202,7 @@ void HistoryWidget::checkPinnedBarState() {
|
||||||
const auto hiddenId = _peer->canPinMessages()
|
const auto hiddenId = _peer->canPinMessages()
|
||||||
? MsgId(0)
|
? MsgId(0)
|
||||||
: session().settings().hiddenPinnedMessageId(_peer->id);
|
: session().settings().hiddenPinnedMessageId(_peer->id);
|
||||||
const auto currentPinnedId = _peer->topPinnedMessageId();
|
const auto currentPinnedId = Data::ResolveTopPinnedId(_peer);
|
||||||
if (currentPinnedId == hiddenId) {
|
if (currentPinnedId == hiddenId) {
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
_pinnedTracker->reset();
|
_pinnedTracker->reset();
|
||||||
|
@ -5601,7 +5595,7 @@ void HistoryWidget::hidePinnedMessage() {
|
||||||
if (_peer->canPinMessages()) {
|
if (_peer->canPinMessages()) {
|
||||||
unpinMessage({ peerToChannel(_peer->id), id.message });
|
unpinMessage({ peerToChannel(_peer->id), id.message });
|
||||||
} else {
|
} else {
|
||||||
const auto top = _peer->topPinnedMessageId();
|
const auto top = Data::ResolveTopPinnedId(_peer);
|
||||||
if (top) {
|
if (top) {
|
||||||
session().settings().setHiddenPinnedMessageId(_peer->id, top);
|
session().settings().setHiddenPinnedMessageId(_peer->id, top);
|
||||||
session().saveSettingsDelayed();
|
session().saveSettingsDelayed();
|
||||||
|
|
|
@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_pinned_messages.h"
|
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_sparse_ids.h"
|
#include "data/data_sparse_ids.h"
|
||||||
#include "data/data_shared_media.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 "history/view/history_view_pinned_tracker.h"
|
||||||
|
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_pinned_messages.h"
|
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_shared_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "storage/storage_facade.h"
|
#include "storage/storage_facade.h"
|
||||||
|
@ -21,16 +21,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
namespace{
|
namespace{
|
||||||
|
|
||||||
constexpr auto kLoadedLimit = 4;
|
constexpr auto kLoadedLimit = 5;
|
||||||
|
constexpr auto kChangeViewerLimit = 2;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PinnedTracker::PinnedTracker(not_null<History*> history) : _history(history) {
|
PinnedTracker::PinnedTracker(not_null<History*> history) : _history(history) {
|
||||||
_history->session().changes().peerFlagsValue(
|
_history->session().changes().peerFlagsValue(
|
||||||
_history->peer,
|
_history->peer,
|
||||||
Data::PeerUpdate::Flag::PinnedMessage
|
Data::PeerUpdate::Flag::PinnedMessages
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::map([=] {
|
||||||
refreshData();
|
return _history->peer->hasPinnedMessages();
|
||||||
|
}) | rpl::distinct_until_changed(
|
||||||
|
) | rpl::start_with_next([=](bool has) {
|
||||||
|
if (has) {
|
||||||
|
refreshViewer();
|
||||||
|
} else {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,60 +56,85 @@ PinnedId PinnedTracker::currentMessageId() const {
|
||||||
return _current.current();
|
return _current.current();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PinnedTracker::refreshData() {
|
void PinnedTracker::refreshViewer() {
|
||||||
const auto now = _history->peer->currentPinnedMessages();
|
if (_viewerAroundId == _aroundId) {
|
||||||
if (!now) {
|
return;
|
||||||
_dataLifetime.destroy();
|
}
|
||||||
_current = PinnedId();
|
_dataLifetime.destroy();
|
||||||
} else if (_data.get() != now) {
|
_viewerAroundId = _aroundId;
|
||||||
_dataLifetime.destroy();
|
SharedMediaViewer(
|
||||||
_data = now;
|
&_history->peer->session(),
|
||||||
if (_aroundId) {
|
Storage::SharedMediaKey(
|
||||||
setupViewer(now);
|
_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) {
|
void PinnedTracker::trackAround(MsgId messageId) {
|
||||||
if (_aroundId == messageId) {
|
if (_aroundId == messageId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_dataLifetime.destroy();
|
|
||||||
_aroundId = messageId;
|
_aroundId = messageId;
|
||||||
if (!_aroundId) {
|
if (!_aroundId) {
|
||||||
_current = PinnedId();
|
clear();
|
||||||
} else if (const auto now = _data.get()) {
|
} else {
|
||||||
setupViewer(now);
|
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
|
} // namespace HistoryView
|
||||||
|
|
|
@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
class History;
|
class History;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class PinnedMessages;
|
|
||||||
enum class LoadDirection : char;
|
enum class LoadDirection : char;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
@ -46,16 +45,24 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refreshData();
|
struct Slice {
|
||||||
void setupViewer(not_null<Data::PinnedMessages*> data);
|
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;
|
const not_null<History*> _history;
|
||||||
|
|
||||||
base::weak_ptr<Data::PinnedMessages> _data;
|
|
||||||
rpl::variable<PinnedId> _current;
|
rpl::variable<PinnedId> _current;
|
||||||
rpl::lifetime _dataLifetime;
|
rpl::lifetime _dataLifetime;
|
||||||
|
|
||||||
MsgId _aroundId = 0;
|
MsgId _aroundId = 0;
|
||||||
|
MsgId _viewerAroundId = 0;
|
||||||
|
Slice _slice;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue