2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-30 05:58:38 +00:00

Support shared media / pins for sublists.

This commit is contained in:
John Preston 2025-06-02 15:00:36 +04:00
parent ffe6786ad1
commit dfc1ec3ccf
83 changed files with 1105 additions and 221 deletions

View File

@ -2978,17 +2978,27 @@ void ApiWrap::resolveJumpToDate(
Fn<void(not_null<PeerData*>, MsgId)> callback) { Fn<void(not_null<PeerData*>, MsgId)> callback) {
if (const auto peer = chat.peer()) { if (const auto peer = chat.peer()) {
const auto topic = chat.topic(); const auto topic = chat.topic();
const auto rootId = topic ? topic->rootId() : 0; const auto sublist = chat.sublist();
resolveJumpToHistoryDate(peer, rootId, date, std::move(callback)); const auto rootId = topic ? topic->rootId() : MsgId();
const auto monoforumPeerId = sublist
? sublist->sublistPeer()->id
: PeerId();
resolveJumpToHistoryDate(
peer,
rootId,
monoforumPeerId,
date,
std::move(callback));
} }
} }
template <typename Callback> template <typename Callback>
void ApiWrap::requestMessageAfterDate( void ApiWrap::requestMessageAfterDate(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
const QDate &date, PeerId monoforumPeerId,
Callback &&callback) { const QDate &date,
Callback &&callback) {
// API returns a message with date <= offset_date. // API returns a message with date <= offset_date.
// So we request a message with offset_date = desired_date - 1 and add_offset = -1. // So we request a message with offset_date = desired_date - 1 and add_offset = -1.
// This should give us the first message with date >= desired_date. // This should give us the first message with date >= desired_date.
@ -3011,7 +3021,7 @@ void ApiWrap::requestMessageAfterDate(
return &messages.vmessages().v; return &messages.vmessages().v;
}; };
const auto list = result.match([&]( const auto list = result.match([&](
const MTPDmessages_messages &data) { const MTPDmessages_messages &data) {
return handleMessages(data); return handleMessages(data);
}, [&](const MTPDmessages_messagesSlice &data) { }, [&](const MTPDmessages_messagesSlice &data) {
return handleMessages(data); return handleMessages(data);
@ -3054,6 +3064,18 @@ void ApiWrap::requestMessageAfterDate(
MTP_int(maxId), MTP_int(maxId),
MTP_int(minId), MTP_int(minId),
MTP_long(historyHash))); MTP_long(historyHash)));
} else if (monoforumPeerId) {
send(MTPmessages_GetSavedHistory(
MTP_flags(MTPmessages_GetSavedHistory::Flag::f_parent_peer),
peer->input,
session().data().peer(monoforumPeerId)->input,
MTP_int(offsetId),
MTP_int(offsetDate),
MTP_int(addOffset),
MTP_int(limit),
MTP_int(maxId),
MTP_int(minId),
MTP_long(historyHash)));
} else { } else {
send(MTPmessages_GetHistory( send(MTPmessages_GetHistory(
peer->input, peer->input,
@ -3070,28 +3092,41 @@ void ApiWrap::requestMessageAfterDate(
void ApiWrap::resolveJumpToHistoryDate( void ApiWrap::resolveJumpToHistoryDate(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
const QDate &date, const QDate &date,
Fn<void(not_null<PeerData*>, MsgId)> callback) { Fn<void(not_null<PeerData*>, MsgId)> callback) {
if (const auto channel = peer->migrateTo()) { if (const auto channel = peer->migrateTo()) {
return resolveJumpToHistoryDate( return resolveJumpToHistoryDate(
channel, channel,
topicRootId, topicRootId,
monoforumPeerId,
date, date,
std::move(callback)); std::move(callback));
} }
const auto jumpToDateInPeer = [=] { const auto jumpToDateInPeer = [=] {
requestMessageAfterDate(peer, topicRootId, date, [=](MsgId itemId) { requestMessageAfterDate(
callback(peer, itemId); peer,
}); topicRootId,
monoforumPeerId,
date,
[=](MsgId itemId) { callback(peer, itemId); });
}; };
if (const auto chat = topicRootId ? nullptr : peer->migrateFrom()) { const auto migrated = (topicRootId || monoforumPeerId)
requestMessageAfterDate(chat, 0, date, [=](MsgId itemId) { ? nullptr
if (itemId) { : peer->migrateFrom();
callback(chat, itemId); if (migrated) {
} else { requestMessageAfterDate(
jumpToDateInPeer(); migrated,
} MsgId(),
}); PeerId(),
date,
[=](MsgId itemId) {
if (itemId) {
callback(migrated, itemId);
} else {
jumpToDateInPeer();
}
});
} else { } else {
jumpToDateInPeer(); jumpToDateInPeer();
} }
@ -3140,12 +3175,14 @@ void ApiWrap::requestHistory(
void ApiWrap::requestSharedMedia( void ApiWrap::requestSharedMedia(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type, SharedMediaType type,
MsgId messageId, MsgId messageId,
SliceType slice) { SliceType slice) {
const auto key = SharedMediaRequest{ const auto key = SharedMediaRequest{
peer, peer,
topicRootId, topicRootId,
monoforumPeerId,
type, type,
messageId, messageId,
slice, slice,
@ -3157,6 +3194,7 @@ void ApiWrap::requestSharedMedia(
const auto prepared = Api::PrepareSearchRequest( const auto prepared = Api::PrepareSearchRequest(
peer, peer,
topicRootId, topicRootId,
monoforumPeerId,
type, type,
QString(), QString(),
messageId, messageId,
@ -3179,7 +3217,12 @@ void ApiWrap::requestSharedMedia(
messageId, messageId,
slice, slice,
result); result);
sharedMediaDone(peer, topicRootId, type, std::move(parsed)); sharedMediaDone(
peer,
topicRootId,
monoforumPeerId,
type,
std::move(parsed));
finish(); finish();
}).fail([=] { }).fail([=] {
_sharedMediaRequests.remove(key); _sharedMediaRequests.remove(key);
@ -3192,16 +3235,19 @@ void ApiWrap::requestSharedMedia(
void ApiWrap::sharedMediaDone( void ApiWrap::sharedMediaDone(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type, SharedMediaType type,
Api::SearchResult &&parsed) { Api::SearchResult &&parsed) {
const auto topic = peer->forumTopicFor(topicRootId); const auto topic = peer->forumTopicFor(topicRootId);
if (topicRootId && !topic) { const auto sublist = peer->monoforumSublistFor(monoforumPeerId);
if ((topicRootId && !topic) || (monoforumPeerId && !sublist)) {
return; return;
} }
const auto hasMessages = !parsed.messageIds.empty(); const auto hasMessages = !parsed.messageIds.empty();
_session->storage().add(Storage::SharedMediaAddSlice( _session->storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
topicRootId, topicRootId,
monoforumPeerId,
type, type,
std::move(parsed.messageIds), std::move(parsed.messageIds),
parsed.noSkipRange, parsed.noSkipRange,
@ -3212,6 +3258,9 @@ void ApiWrap::sharedMediaDone(
if (topic) { if (topic) {
topic->setHasPinnedMessages(true); topic->setHasPinnedMessages(true);
} }
if (sublist) {
sublist->setHasPinnedMessages(true);
}
} }
} }
@ -3245,16 +3294,12 @@ void ApiWrap::sendAction(const SendAction &action) {
&& !action.options.shortcutId && !action.options.shortcutId
&& !action.replaceMediaOf) { && !action.replaceMediaOf) {
const auto topicRootId = action.replyTo.topicRootId; const auto topicRootId = action.replyTo.topicRootId;
const auto monoforumPeerId = action.replyTo.monoforumPeerId;
const auto topic = topicRootId const auto topic = topicRootId
? action.history->peer->forumTopicFor(topicRootId) ? action.history->peer->forumTopicFor(topicRootId)
: nullptr; : nullptr;
const auto monoforum = monoforumPeerId const auto monoforumPeerId = action.replyTo.monoforumPeerId;
? action.history->peer->monoforum() const auto sublist = monoforumPeerId
: nullptr; ? action.history->peer->monoforumSublistFor(monoforumPeerId)
const auto sublist = monoforum
? monoforum->sublistLoaded(
action.history->owner().peer(monoforumPeerId))
: nullptr; : nullptr;
if (topic) { if (topic) {
topic->readTillEnd(); topic->readTillEnd();

View File

@ -289,6 +289,7 @@ public:
void requestSharedMedia( void requestSharedMedia(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
Storage::SharedMediaType type, Storage::SharedMediaType type,
MsgId messageId, MsgId messageId,
SliceType slice); SliceType slice);
@ -505,18 +506,21 @@ private:
void resolveJumpToHistoryDate( void resolveJumpToHistoryDate(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
const QDate &date, const QDate &date,
Fn<void(not_null<PeerData*>, MsgId)> callback); Fn<void(not_null<PeerData*>, MsgId)> callback);
template <typename Callback> template <typename Callback>
void requestMessageAfterDate( void requestMessageAfterDate(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
const QDate &date, const QDate &date,
Callback &&callback); Callback &&callback);
void sharedMediaDone( void sharedMediaDone(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type, SharedMediaType type,
Api::SearchResult &&parsed); Api::SearchResult &&parsed);
void globalMediaDone( void globalMediaDone(
@ -665,6 +669,7 @@ private:
struct SharedMediaRequest { struct SharedMediaRequest {
not_null<PeerData*> peer; not_null<PeerData*> peer;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
SharedMediaType mediaType = {}; SharedMediaType mediaType = {};
MsgId aroundId = 0; MsgId aroundId = 0;
SliceType sliceType = {}; SliceType sliceType = {};

View File

@ -24,10 +24,15 @@ namespace {
[[nodiscard]] bool IsOldForPin( [[nodiscard]] bool IsOldForPin(
MsgId id, MsgId id,
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId) { MsgId topicRootId,
PeerId monoforumPeerId) {
const auto normal = peer->migrateToOrMe(); const auto normal = peer->migrateToOrMe();
const auto migrated = normal->migrateFrom(); const auto migrated = normal->migrateFrom();
const auto top = Data::ResolveTopPinnedId(normal, topicRootId, migrated); const auto top = Data::ResolveTopPinnedId(
normal,
topicRootId,
monoforumPeerId,
migrated);
if (!top) { if (!top) {
return false; return false;
} else if (peer == migrated) { } else if (peer == migrated) {
@ -53,7 +58,14 @@ void PinMessageBox(
const auto peer = item->history()->peer; const auto peer = item->history()->peer;
const auto msgId = item->id; const auto msgId = item->id;
const auto topicRootId = item->topic() ? item->topicRootId() : MsgId(); const auto topicRootId = item->topic() ? item->topicRootId() : MsgId();
const auto pinningOld = IsOldForPin(msgId, peer, topicRootId); const auto monoforumPeerId = item->history()->peer->amMonoforumAdmin()
? item->sublistPeerId()
: PeerId();
const auto pinningOld = IsOldForPin(
msgId,
peer,
topicRootId,
monoforumPeerId);
const auto state = box->lifetime().make_state<State>(); const auto state = box->lifetime().make_state<State>();
const auto api = box->lifetime().make_state<MTP::Sender>( const auto api = box->lifetime().make_state<MTP::Sender>(
&peer->session().mtp()); &peer->session().mtp());

View File

@ -847,6 +847,7 @@ bool OpenMediaTimestamp(
document, document,
context, context,
context ? context->topicRootId() : MsgId(0), context ? context->topicRootId() : MsgId(0),
context ? context->sublistPeerId() : PeerId(0),
false, false,
time)); time));
} else if (document->isSong() || document->isVoiceMessage()) { } else if (document->isSong() || document->isVoiceMessage()) {

View File

@ -187,7 +187,8 @@ void ResolveDocument(
Window::SessionController *controller, Window::SessionController *controller,
not_null<DocumentData*> document, not_null<DocumentData*> document,
HistoryItem *item, HistoryItem *item,
MsgId topicRootId) { MsgId topicRootId,
PeerId monoforumPeerId) {
if (document->isNull()) { if (document->isNull()) {
return; return;
} }
@ -202,7 +203,7 @@ void ResolveDocument(
controller->openDocument( controller->openDocument(
document, document,
true, true,
{ msgId, topicRootId }); { msgId, topicRootId, monoforumPeerId });
} }
}; };

View File

@ -31,6 +31,7 @@ void ResolveDocument(
Window::SessionController *controller, Window::SessionController *controller,
not_null<DocumentData*> document, not_null<DocumentData*> document,
HistoryItem *item, HistoryItem *item,
MsgId topicRootId); MsgId topicRootId,
PeerId monoforumPeerId);
} // namespace Data } // namespace Data

View File

@ -72,7 +72,10 @@ Forum::~Forum() {
auto &changes = session().changes(); auto &changes = session().changes();
const auto peerId = _history->peer->id; const auto peerId = _history->peer->id;
for (const auto &[rootId, topic] : _topics) { for (const auto &[rootId, topic] : _topics) {
storage.unload(Storage::SharedMediaUnloadThread(peerId, rootId)); storage.unload(Storage::SharedMediaUnloadThread(
peerId,
rootId,
PeerId()));
_history->setForwardDraft(rootId, PeerId(), {}); _history->setForwardDraft(rootId, PeerId(), {});
const auto raw = topic.get(); const auto raw = topic.get();
@ -198,7 +201,8 @@ void Forum::applyTopicDeleted(MsgId rootId) {
_history->destroyMessagesByTopic(rootId); _history->destroyMessagesByTopic(rootId);
session().storage().unload(Storage::SharedMediaUnloadThread( session().storage().unload(Storage::SharedMediaUnloadThread(
_history->peer->id, _history->peer->id,
rootId)); rootId,
PeerId()));
_history->setForwardDraft(rootId, PeerId(), {}); _history->setForwardDraft(rootId, PeerId(), {});
} }

View File

@ -152,6 +152,7 @@ rpl::producer<SparseIdsMergedSlice> HistoryMergedViewer(
auto createSimpleViewer = [=]( auto createSimpleViewer = [=](
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SparseIdsSlice::Key simpleKey, SparseIdsSlice::Key simpleKey,
int limitBefore, int limitBefore,
int limitAfter) { int limitAfter) {
@ -161,11 +162,10 @@ rpl::producer<SparseIdsMergedSlice> HistoryMergedViewer(
return HistoryViewer(chosen, simpleKey, limitBefore, limitAfter); return HistoryViewer(chosen, simpleKey, limitBefore, limitAfter);
}; };
const auto peerId = history->peer->id; const auto peerId = history->peer->id;
const auto topicRootId = MsgId();
const auto migratedPeerId = migrateFrom ? migrateFrom->id : PeerId(0); const auto migratedPeerId = migrateFrom ? migrateFrom->id : PeerId(0);
using Key = SparseIdsMergedSlice::Key; using Key = SparseIdsMergedSlice::Key;
return SparseIdsMergedSlice::CreateViewer( return SparseIdsMergedSlice::CreateViewer(
Key(peerId, topicRootId, migratedPeerId, universalAroundId), Key(peerId, MsgId(), PeerId(), migratedPeerId, universalAroundId),
limitBefore, limitBefore,
limitAfter, limitAfter,
std::move(createSimpleViewer)); std::move(createSimpleViewer));

View File

@ -1474,6 +1474,16 @@ Data::SavedMessages *PeerData::monoforum() const {
return nullptr; return nullptr;
} }
Data::SavedSublist *PeerData::monoforumSublistFor(
PeerId sublistPeerId) const {
if (!sublistPeerId) {
return nullptr;
} else if (const auto monoforum = this->monoforum()) {
return monoforum->sublistLoaded(owner().peer(sublistPeerId));
}
return nullptr;
}
bool PeerData::allowsForwarding() const { bool PeerData::allowsForwarding() const {
if (isUser()) { if (isUser()) {
return true; return true;
@ -1807,12 +1817,14 @@ void SetTopPinnedMessageId(
session.settings().setHiddenPinnedMessageId( session.settings().setHiddenPinnedMessageId(
peer->id, peer->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
0); 0);
session.saveSettingsDelayed(); session.saveSettingsDelayed();
} }
session.storage().add(Storage::SharedMediaAddExisting( session.storage().add(Storage::SharedMediaAddExisting(
peer->id, peer->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
messageId, messageId,
{ messageId, ServerMaxMsgId })); { messageId, ServerMaxMsgId }));
@ -1822,22 +1834,25 @@ void SetTopPinnedMessageId(
FullMsgId ResolveTopPinnedId( FullMsgId ResolveTopPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated) { PeerData *migrated) {
const auto slice = peer->session().storage().snapshot( const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
peer->id, peer->id,
topicRootId, topicRootId,
monoforumPeerId,
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1), ServerMaxMsgId - 1),
1, 1,
1)); 1));
const auto old = (!topicRootId && migrated) const auto old = (!topicRootId && !monoforumPeerId && migrated)
? migrated->session().storage().snapshot( ? migrated->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
migrated->id, migrated->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1), ServerMaxMsgId - 1),
1, 1,
@ -1859,22 +1874,25 @@ FullMsgId ResolveTopPinnedId(
FullMsgId ResolveMinPinnedId( FullMsgId ResolveMinPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated) { PeerData *migrated) {
const auto slice = peer->session().storage().snapshot( const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
peer->id, peer->id,
topicRootId, topicRootId,
monoforumPeerId,
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
1), 1),
1, 1,
1)); 1));
const auto old = (!topicRootId && migrated) const auto old = (!topicRootId && !monoforumPeerId && migrated)
? migrated->session().storage().snapshot( ? migrated->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
migrated->id, migrated->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
1), 1),
1, 1,

View File

@ -38,6 +38,7 @@ class ForumTopic;
class Session; class Session;
class GroupCall; class GroupCall;
class SavedMessages; class SavedMessages;
class SavedSublist;
struct ReactionId; struct ReactionId;
class WallPaper; class WallPaper;
@ -260,6 +261,8 @@ public:
[[nodiscard]] Data::ForumTopic *forumTopicFor(MsgId rootId) const; [[nodiscard]] Data::ForumTopic *forumTopicFor(MsgId rootId) const;
[[nodiscard]] Data::SavedMessages *monoforum() const; [[nodiscard]] Data::SavedMessages *monoforum() const;
[[nodiscard]] Data::SavedSublist *monoforumSublistFor(
PeerId sublistPeerId) const;
[[nodiscard]] Data::PeerNotifySettings &notify() { [[nodiscard]] Data::PeerNotifySettings &notify() {
return _notify; return _notify;
@ -616,10 +619,12 @@ void SetTopPinnedMessageId(
[[nodiscard]] FullMsgId ResolveTopPinnedId( [[nodiscard]] FullMsgId ResolveTopPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated = nullptr); PeerData *migrated = nullptr);
[[nodiscard]] FullMsgId ResolveMinPinnedId( [[nodiscard]] FullMsgId ResolveMinPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated = nullptr); PeerData *migrated = nullptr);
} // namespace Data } // namespace Data

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h" #include "core/application.h"
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_histories.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_saved_sublist.h" #include "data/data_saved_sublist.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -18,6 +19,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history_unread_things.h" #include "history/history_unread_things.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "window/notifications_manager.h" #include "window/notifications_manager.h"
namespace Data { namespace Data {
@ -29,6 +32,7 @@ constexpr auto kListPerPage = 100;
constexpr auto kListFirstPerPage = 20; constexpr auto kListFirstPerPage = 20;
constexpr auto kLoadedSublistsMinCount = 20; constexpr auto kLoadedSublistsMinCount = 20;
constexpr auto kShowSublistNamesCount = 5; constexpr auto kShowSublistNamesCount = 5;
constexpr auto kStalePerRequest = 100;
} // namespace } // namespace
@ -50,16 +54,36 @@ SavedMessages::SavedMessages(
} }
} }
SavedMessages::~SavedMessages() { void SavedMessages::clear() {
for (const auto &request : base::take(_sublistRequests)) {
if (request.second.id != _staleRequestId) {
owner().histories().cancelRequest(request.second.id);
}
}
if (const auto requestId = base::take(_staleRequestId)) {
session().api().request(requestId).cancel();
}
auto &storage = session().storage();
auto &changes = session().changes(); auto &changes = session().changes();
if (_owningHistory) { if (_owningHistory) {
for (const auto &[peer, sublist] : _sublists) { for (const auto &[peer, sublist] : base::take(_sublists)) {
storage.unload(Storage::SharedMediaUnloadThread(
_owningHistory->peer->id,
MsgId(),
peer->id));
_owningHistory->setForwardDraft(MsgId(), peer->id, {}); _owningHistory->setForwardDraft(MsgId(), peer->id, {});
const auto raw = sublist.get(); const auto raw = sublist.get();
changes.sublistRemoved(raw);
changes.entryRemoved(raw); changes.entryRemoved(raw);
} }
} }
_owningHistory = nullptr;
}
SavedMessages::~SavedMessages() {
clear();
} }
bool SavedMessages::supported() const { bool SavedMessages::supported() const {
@ -108,6 +132,90 @@ SavedSublist *SavedMessages::sublistLoaded(not_null<PeerData*> peer) {
return (i != end(_sublists)) ? i->second.get() : nullptr; return (i != end(_sublists)) ? i->second.get() : nullptr;
} }
void SavedMessages::requestSomeStale() {
if (_staleRequestId
|| (!_offset.id && _loadMoreRequestId)
|| _stalePeers.empty()
|| !_parentChat) {
return;
}
const auto type = Histories::RequestType::History;
auto peers = std::vector<not_null<PeerData*>>();
auto peerIds = QVector<MTPInputPeer>();
peers.reserve(std::min(int(_stalePeers.size()), kStalePerRequest));
peerIds.reserve(std::min(int(_stalePeers.size()), kStalePerRequest));
for (auto i = begin(_stalePeers); i != end(_stalePeers);) {
const auto peer = *i;
i = _stalePeers.erase(i);
peers.push_back(peer);
peerIds.push_back(peer->input);
if (peerIds.size() == kStalePerRequest) {
break;
}
}
if (peerIds.empty()) {
return;
}
const auto call = [=] {
for (const auto &peer : peers) {
finishSublistRequest(peer);
}
};
auto &histories = owner().histories();
_staleRequestId = histories.sendRequest(_owningHistory, type, [=](
Fn<void()> finish) {
using Flag = MTPmessages_GetSavedDialogsByID::Flag;
return session().api().request(
MTPmessages_GetSavedDialogsByID(
MTP_flags(Flag::f_parent_peer),
_parentChat->input,
MTP_vector<MTPInputPeer>(peerIds))
).done([=](const MTPmessages_SavedDialogs &result) {
_staleRequestId = 0;
applyReceivedSublists(result);
call();
finish();
}).fail([=] {
_staleRequestId = 0;
call();
finish();
}).send();
});
for (const auto &peer : peers) {
_sublistRequests[peer].id = _staleRequestId;
}
}
void SavedMessages::finishSublistRequest(not_null<PeerData*> peer) {
if (const auto request = _sublistRequests.take(peer)) {
for (const auto &callback : request->callbacks) {
callback();
}
}
}
void SavedMessages::requestSublist(
not_null<PeerData*> peer,
Fn<void()> done) {
if (!_parentChat) {
return;
}
auto &request = _sublistRequests[peer];
if (done) {
request.callbacks.push_back(std::move(done));
}
if (!request.id
&& _stalePeers.emplace(peer).second
&& (_stalePeers.size() == 1)) {
crl::on_main(&session(), [peer = _parentChat] {
if (const auto monoforum = peer->monoforum()) {
monoforum->requestSomeStale();
}
});
}
}
rpl::producer<> SavedMessages::chatsListChanges() const { rpl::producer<> SavedMessages::chatsListChanges() const {
return _chatsListChanges.events(); return _chatsListChanges.events();
} }
@ -146,18 +254,28 @@ void SavedMessages::sendLoadMore() {
MTP_flags(Flag::f_exclude_pinned MTP_flags(Flag::f_exclude_pinned
| (_parentChat ? Flag::f_parent_peer : Flag(0))), | (_parentChat ? Flag::f_parent_peer : Flag(0))),
_parentChat ? _parentChat->input : MTPInputPeer(), _parentChat ? _parentChat->input : MTPInputPeer(),
MTP_int(_offsetDate), MTP_int(_offset.date),
MTP_int(_offsetId), MTP_int(_offset.id),
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(), _offset.peer ? _offset.peer->input : MTP_inputPeerEmpty(),
MTP_int(_offsetId ? kListPerPage : kListFirstPerPage), MTP_int(_offset.id ? kListPerPage : kListFirstPerPage),
MTP_long(0)) // hash MTP_long(0)) // hash
).done([=](const MTPmessages_SavedDialogs &result) { ).done([=](const MTPmessages_SavedDialogs &result) {
apply(result, false); const auto applied = applyReceivedSublists(result);
if (applied.allLoaded || _offset == applied.offset) {
_chatsList.setLoaded();
} else if (_offset.date > 0 && applied.offset.date > _offset.date) {
LOG(("API Error: Bad order in messages.savedDialogs."));
_chatsList.setLoaded();
} else {
_offset = applied.offset;
}
_loadMoreRequestId = 0;
_chatsListChanges.fire({}); _chatsListChanges.fire({});
if (_chatsList.loaded()) { if (_chatsList.loaded()) {
_chatsListLoadedEvents.fire({}); _chatsListLoadedEvents.fire({});
} }
reorderLastSublists(); reorderLastSublists();
requestSomeStale();
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) { if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
markUnsupported(); markUnsupported();
@ -174,7 +292,9 @@ void SavedMessages::loadPinned() {
_pinnedRequestId = _owner->session().api().request( _pinnedRequestId = _owner->session().api().request(
MTPmessages_GetPinnedSavedDialogs() MTPmessages_GetPinnedSavedDialogs()
).done([=](const MTPmessages_SavedDialogs &result) { ).done([=](const MTPmessages_SavedDialogs &result) {
apply(result, true); _pinnedRequestId = 0;
_pinnedLoaded = true;
applyReceivedSublists(result, true);
_chatsListChanges.fire({}); _chatsListChanges.fire({});
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) { if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
@ -186,11 +306,11 @@ void SavedMessages::loadPinned() {
}).send(); }).send();
} }
void SavedMessages::apply( SavedMessages::ApplyResult SavedMessages::applyReceivedSublists(
const MTPmessages_SavedDialogs &result, const MTPmessages_SavedDialogs &dialogs,
bool pinned) { bool pinned) {
auto list = (const QVector<MTPSavedDialog>*)nullptr; auto list = (const QVector<MTPSavedDialog>*)nullptr;
result.match([](const MTPDmessages_savedDialogsNotModified &) { dialogs.match([](const MTPDmessages_savedDialogsNotModified &) {
LOG(("API Error: messages.savedDialogsNotModified.")); LOG(("API Error: messages.savedDialogsNotModified."));
}, [&](const auto &data) { }, [&](const auto &data) {
_owner->processUsers(data.vusers()); _owner->processUsers(data.vusers());
@ -200,22 +320,11 @@ void SavedMessages::apply(
NewMessageType::Existing); NewMessageType::Existing);
list = &data.vdialogs().v; list = &data.vdialogs().v;
}); });
if (pinned) {
_pinnedRequestId = 0;
_pinnedLoaded = true;
} else {
_loadMoreRequestId = 0;
}
if (!list) { if (!list) {
if (!pinned) { return { .allLoaded = true };
_chatsList.setLoaded();
}
return;
} }
auto lastValid = false; auto lastValid = false;
auto offsetDate = TimeId(); auto result = ApplyResult();
auto offsetId = MsgId();
auto offsetPeer = (PeerData*)nullptr;
const auto parentPeerId = _parentChat const auto parentPeerId = _parentChat
? _parentChat->id ? _parentChat->id
: _owner->session().userPeerId(); : _owner->session().userPeerId();
@ -224,9 +333,9 @@ void SavedMessages::apply(
const auto peer = _owner->peer(peerFromMTP(data.vpeer())); const auto peer = _owner->peer(peerFromMTP(data.vpeer()));
const auto topId = MsgId(data.vtop_message().v); const auto topId = MsgId(data.vtop_message().v);
if (const auto item = _owner->message(parentPeerId, topId)) { if (const auto item = _owner->message(parentPeerId, topId)) {
offsetPeer = peer; result.offset.peer = peer;
offsetDate = item->date(); result.offset.date = item->date();
offsetId = topId; result.offset.id = topId;
lastValid = true; lastValid = true;
const auto entry = sublist(peer); const auto entry = sublist(peer);
const auto entryPinned = pinned || data.is_pinned(); const auto entryPinned = pinned || data.is_pinned();
@ -239,9 +348,9 @@ void SavedMessages::apply(
const auto peer = _owner->peer(peerFromMTP(data.vpeer())); const auto peer = _owner->peer(peerFromMTP(data.vpeer()));
const auto topId = MsgId(data.vtop_message().v); const auto topId = MsgId(data.vtop_message().v);
if (const auto item = _owner->message(parentPeerId, topId)) { if (const auto item = _owner->message(parentPeerId, topId)) {
offsetPeer = peer; result.offset.peer = peer;
offsetDate = item->date(); result.offset.date = item->date();
offsetId = topId; result.offset.id = topId;
lastValid = true; lastValid = true;
sublist(peer)->applyMonoforumDialog(data, item); sublist(peer)->applyMonoforumDialog(data, item);
} else { } else {
@ -252,20 +361,14 @@ void SavedMessages::apply(
if (pinned) { if (pinned) {
} else if (!lastValid) { } else if (!lastValid) {
LOG(("API Error: Unknown message in the end of a slice.")); LOG(("API Error: Unknown message in the end of a slice."));
_chatsList.setLoaded(); result.allLoaded = true;
} else if (result.type() == mtpc_messages_savedDialogs) { } else if (dialogs.type() == mtpc_messages_savedDialogs) {
_chatsList.setLoaded(); result.allLoaded = true;
} else if ((_offsetDate > 0 && offsetDate > _offsetDate)
|| (offsetDate == _offsetDate
&& offsetId == _offsetId
&& offsetPeer == _offsetPeer)) {
LOG(("API Error: Bad order in messages.savedDialogs."));
_chatsList.setLoaded();
} else {
_offsetDate = offsetDate;
_offsetId = offsetId;
_offsetPeer = offsetPeer;
} }
if (!_stalePeers.empty()) {
requestSomeStale();
}
return result;
} }
void SavedMessages::sendLoadMoreRequests() { void SavedMessages::sendLoadMoreRequests() {
@ -324,7 +427,7 @@ void SavedMessages::applySublistDeleted(not_null<PeerData*> sublistPeer) {
return; return;
} }
const auto raw = i->second.get(); const auto raw = i->second.get();
//Core::App().notifications().clearFromTopic(raw); // #TODO monoforum Core::App().notifications().clearFromSublist(raw);
owner().removeChatListEntry(raw); owner().removeChatListEntry(raw);
if (ranges::contains(_lastSublists, not_null(raw))) { if (ranges::contains(_lastSublists, not_null(raw))) {
@ -342,9 +445,10 @@ void SavedMessages::applySublistDeleted(not_null<PeerData*> sublistPeer) {
const auto history = owningHistory(); const auto history = owningHistory();
history->destroyMessagesBySublist(sublistPeer); history->destroyMessagesBySublist(sublistPeer);
//session().storage().unload(Storage::SharedMediaUnloadThread( session().storage().unload(Storage::SharedMediaUnloadThread(
// _history->peer->id, _owningHistory->peer->id,
// rootId)); MsgId(),
sublistPeer->id));
history->setForwardDraft(MsgId(), sublistPeer->id, {}); history->setForwardDraft(MsgId(), sublistPeer->id, {});
} }

View File

@ -18,6 +18,16 @@ namespace Data {
class Session; class Session;
class SavedSublist; class SavedSublist;
struct SavedMessagesOffsets {
TimeId date = 0;
MsgId id = 0;
PeerData *peer = nullptr;
friend inline constexpr auto operator<=>(
SavedMessagesOffsets,
SavedMessagesOffsets) = default;
};
class SavedMessages final { class SavedMessages final {
public: public:
explicit SavedMessages( explicit SavedMessages(
@ -37,6 +47,7 @@ public:
[[nodiscard]] not_null<Dialogs::MainList*> chatsList(); [[nodiscard]] not_null<Dialogs::MainList*> chatsList();
[[nodiscard]] not_null<SavedSublist*> sublist(not_null<PeerData*> peer); [[nodiscard]] not_null<SavedSublist*> sublist(not_null<PeerData*> peer);
[[nodiscard]] SavedSublist *sublistLoaded(not_null<PeerData*> peer); [[nodiscard]] SavedSublist *sublistLoaded(not_null<PeerData*> peer);
void requestSublist(not_null<PeerData*> peer, Fn<void()> done = nullptr);
[[nodiscard]] rpl::producer<> chatsListChanges() const; [[nodiscard]] rpl::producer<> chatsListChanges() const;
[[nodiscard]] rpl::producer<> chatsListLoadedEvents() const; [[nodiscard]] rpl::producer<> chatsListLoadedEvents() const;
@ -59,13 +70,31 @@ public:
[[nodiscard]] auto recentSublists() const [[nodiscard]] auto recentSublists() const
-> const std::vector<not_null<SavedSublist*>> &; -> const std::vector<not_null<SavedSublist*>> &;
void clear();
[[nodiscard]] rpl::lifetime &lifetime(); [[nodiscard]] rpl::lifetime &lifetime();
private: private:
struct SublistRequest {
mtpRequestId id = 0;
std::vector<Fn<void()>> callbacks;
};
struct ApplyResult {
SavedMessagesOffsets offset;
bool allLoaded = false;
};
void loadPinned(); void loadPinned();
void apply(const MTPmessages_SavedDialogs &result, bool pinned); ApplyResult applyReceivedSublists(
const MTPmessages_SavedDialogs &result,
SavedMessagesOffsets &updateOffsets);
ApplyResult applyReceivedSublists(
const MTPmessages_SavedDialogs &result,
bool pinned = false);
void reorderLastSublists(); void reorderLastSublists();
void requestSomeStale();
void finishSublistRequest(not_null<PeerData*> peer);
void sendLoadMore(); void sendLoadMore();
void sendLoadMoreRequests(); void sendLoadMoreRequests();
@ -80,13 +109,14 @@ private:
base::flat_map< base::flat_map<
not_null<PeerData*>, not_null<PeerData*>,
std::unique_ptr<SavedSublist>> _sublists; std::unique_ptr<SavedSublist>> _sublists;
base::flat_map<not_null<PeerData*>, SublistRequest> _sublistRequests;
base::flat_set<not_null<PeerData*>> _stalePeers;
mtpRequestId _staleRequestId = 0;
mtpRequestId _loadMoreRequestId = 0; mtpRequestId _loadMoreRequestId = 0;
mtpRequestId _pinnedRequestId = 0; mtpRequestId _pinnedRequestId = 0;
TimeId _offsetDate = 0; SavedMessagesOffsets _offset;
MsgId _offsetId = 0;
PeerData *_offsetPeer = nullptr;
SingleQueuedInvokation _loadMore; SingleQueuedInvokation _loadMore;
bool _loadMoreScheduled = false; bool _loadMoreScheduled = false;

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_saved_sublist.h" #include "data/data_saved_sublist.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "core/application.h"
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
@ -22,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history_unread_things.h" #include "history/history_unread_things.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "window/notifications_manager.h"
namespace Data { namespace Data {
namespace { namespace {
@ -221,7 +223,7 @@ void SavedSublist::applyItemRemoved(MsgId id) {
void SavedSublist::requestChatListMessage() { void SavedSublist::requestChatListMessage() {
if (!chatListMessageKnown()) { if (!chatListMessageKnown()) {
//forum()->requestTopic(_rootId); // #TODO monoforum parent()->requestSublist(sublistPeer());
} }
} }
@ -648,7 +650,7 @@ void SavedSublist::readTill(
_readRequestTimer.callOnce(0); _readRequestTimer.callOnce(0);
} }
} }
// Core::App().notifications().clearIncomingFromSublist(this); // #TODO monoforum Core::App().notifications().clearIncomingFromSublist(this);
} }
void SavedSublist::sendReadTillRequest() { void SavedSublist::sendReadTillRequest() {

View File

@ -132,6 +132,7 @@ GlobalMediaResult ParseGlobalMediaResult(
std::optional<SearchRequest> PrepareSearchRequest( std::optional<SearchRequest> PrepareSearchRequest(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
Storage::SharedMediaType type, Storage::SharedMediaType type,
const QString &query, const QString &query,
MsgId messageId, MsgId messageId,
@ -168,11 +169,14 @@ std::optional<SearchRequest> PrepareSearchRequest(
int64(0x3FFFFFFF))); int64(0x3FFFFFFF)));
using Flag = MTPmessages_Search::Flag; using Flag = MTPmessages_Search::Flag;
return MTPmessages_Search( return MTPmessages_Search(
MTP_flags(topicRootId ? Flag::f_top_msg_id : Flag(0)), MTP_flags((topicRootId ? Flag::f_top_msg_id : Flag(0))
| (monoforumPeerId ? Flag::f_saved_peer_id : Flag(0))),
peer->input, peer->input,
MTP_string(query), MTP_string(query),
MTP_inputPeerEmpty(), MTP_inputPeerEmpty(),
MTPInputPeer(), // saved_peer_id (monoforumPeerId
? peer->owner().peer(monoforumPeerId)->input
: MTPInputPeer()),
MTPVector<MTPReaction>(), // saved_reaction MTPVector<MTPReaction>(), // saved_reaction
MTP_int(topicRootId), MTP_int(topicRootId),
filter, filter,
@ -369,12 +373,14 @@ rpl::producer<SparseIdsMergedSlice> SearchController::idsSlice(
auto createSimpleViewer = [=]( auto createSimpleViewer = [=](
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SparseIdsSlice::Key simpleKey, SparseIdsSlice::Key simpleKey,
int limitBefore, int limitBefore,
int limitAfter) { int limitAfter) {
return simpleIdsSlice( return simpleIdsSlice(
peerId, peerId,
topicRootId, topicRootId,
monoforumPeerId,
simpleKey, simpleKey,
query, query,
limitBefore, limitBefore,
@ -384,6 +390,7 @@ rpl::producer<SparseIdsMergedSlice> SearchController::idsSlice(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
query.peerId, query.peerId,
query.topicRootId, query.topicRootId,
query.monoforumPeerId,
query.migratedPeerId, query.migratedPeerId,
aroundId), aroundId),
limitBefore, limitBefore,
@ -394,6 +401,7 @@ rpl::producer<SparseIdsMergedSlice> SearchController::idsSlice(
rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice( rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
MsgId aroundId, MsgId aroundId,
const Query &query, const Query &query,
int limitBefore, int limitBefore,
@ -402,8 +410,12 @@ rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice(
Expects(IsServerMsgId(aroundId) || (aroundId == 0)); Expects(IsServerMsgId(aroundId) || (aroundId == 0));
Expects((aroundId != 0) Expects((aroundId != 0)
|| (limitBefore == 0 && limitAfter == 0)); || (limitBefore == 0 && limitAfter == 0));
Expects((query.peerId == peerId && query.topicRootId == topicRootId) Expects((query.peerId == peerId
|| (query.migratedPeerId == peerId && MsgId(0) == topicRootId)); && query.topicRootId == topicRootId
&& query.monoforumPeerId == monoforumPeerId)
|| (query.migratedPeerId == peerId
&& MsgId(0) == topicRootId
&& PeerId(0) == monoforumPeerId));
auto it = _cache.find(query); auto it = _cache.find(query);
if (it == _cache.end()) { if (it == _cache.end()) {
@ -437,7 +449,9 @@ rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice(
_session->data().itemRemoved( _session->data().itemRemoved(
) | rpl::filter([=](not_null<const HistoryItem*> item) { ) | rpl::filter([=](not_null<const HistoryItem*> item) {
return (item->history()->peer->id == peerId) return (item->history()->peer->id == peerId)
&& (!topicRootId || item->topicRootId() == topicRootId); && (!topicRootId || item->topicRootId() == topicRootId)
&& (!monoforumPeerId
|| item->sublistPeerId() == monoforumPeerId);
}) | rpl::filter([=](not_null<const HistoryItem*> item) { }) | rpl::filter([=](not_null<const HistoryItem*> item) {
return builder->removeOne(item->id); return builder->removeOne(item->id);
}) | rpl::start_with_next(pushNextSnapshot, lifetime); }) | rpl::start_with_next(pushNextSnapshot, lifetime);
@ -510,6 +524,7 @@ void SearchController::requestMore(
auto prepared = PrepareSearchRequest( auto prepared = PrepareSearchRequest(
listData->peer, listData->peer,
query.topicRootId, query.topicRootId,
query.monoforumPeerId,
query.type, query.type,
query.query, query.query,
key.aroundId, key.aroundId,

View File

@ -61,6 +61,7 @@ struct GlobalMediaResult {
[[nodiscard]] std::optional<SearchRequest> PrepareSearchRequest( [[nodiscard]] std::optional<SearchRequest> PrepareSearchRequest(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
Storage::SharedMediaType type, Storage::SharedMediaType type,
const QString &query, const QString &query,
MsgId messageId, MsgId messageId,
@ -92,6 +93,7 @@ public:
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
PeerId migratedPeerId = 0; PeerId migratedPeerId = 0;
MediaType type = MediaType::kCount; MediaType type = MediaType::kCount;
QString query; QString query;
@ -151,6 +153,7 @@ private:
rpl::producer<SparseIdsSlice> simpleIdsSlice( rpl::producer<SparseIdsSlice> simpleIdsSlice(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
MsgId aroundId, MsgId aroundId,
const Query &query, const Query &query,
int limitBefore, int limitBefore,

View File

@ -404,6 +404,7 @@ void Session::clear() {
channel->setFlags(channel->flags() channel->setFlags(channel->flags()
& ~(ChannelDataFlag::Forum | ChannelDataFlag::MonoforumAdmin)); & ~(ChannelDataFlag::Forum | ChannelDataFlag::MonoforumAdmin));
} }
_savedMessages->clear();
_sendActionManager->clear(); _sendActionManager->clear();

View File

@ -110,11 +110,13 @@ rpl::producer<SparseIdsSlice> SharedMediaViewer(
auto requestMediaAround = [ auto requestMediaAround = [
peer = session->data().peer(key.peerId), peer = session->data().peer(key.peerId),
topicRootId = key.topicRootId, topicRootId = key.topicRootId,
monoforumPeerId = key.monoforumPeerId,
type = key.type type = key.type
](const SparseIdsSliceBuilder::AroundData &data) { ](const SparseIdsSliceBuilder::AroundData &data) {
peer->session().api().requestSharedMedia( peer->session().api().requestSharedMedia(
peer, peer,
topicRootId, topicRootId,
monoforumPeerId,
type, type,
data.aroundId, data.aroundId,
data.direction); data.direction);
@ -131,6 +133,7 @@ rpl::producer<SparseIdsSlice> SharedMediaViewer(
) | rpl::filter([=](const SliceUpdate &update) { ) | rpl::filter([=](const SliceUpdate &update) {
return (update.peerId == key.peerId) return (update.peerId == key.peerId)
&& (update.topicRootId == key.topicRootId) && (update.topicRootId == key.topicRootId)
&& (update.monoforumPeerId == key.monoforumPeerId)
&& (update.type == key.type); && (update.type == key.type);
}) | rpl::filter([=](const SliceUpdate &update) { }) | rpl::filter([=](const SliceUpdate &update) {
return builder->applyUpdate(update.data); return builder->applyUpdate(update.data);
@ -151,6 +154,8 @@ rpl::producer<SparseIdsSlice> SharedMediaViewer(
return (update.peerId == key.peerId) return (update.peerId == key.peerId)
&& (!update.topicRootId && (!update.topicRootId
|| update.topicRootId == key.topicRootId) || update.topicRootId == key.topicRootId)
&& (!update.monoforumPeerId
|| update.monoforumPeerId == key.monoforumPeerId)
&& update.types.test(key.type); && update.types.test(key.type);
}) | rpl::filter([=] { }) | rpl::filter([=] {
return builder->removeAll(); return builder->removeAll();
@ -236,6 +241,7 @@ rpl::producer<SparseIdsMergedSlice> SharedMediaMergedViewer(
auto createSimpleViewer = [=]( auto createSimpleViewer = [=](
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SparseIdsSlice::Key simpleKey, SparseIdsSlice::Key simpleKey,
int limitBefore, int limitBefore,
int limitAfter) { int limitAfter) {
@ -244,6 +250,7 @@ rpl::producer<SparseIdsMergedSlice> SharedMediaMergedViewer(
Storage::SharedMediaKey( Storage::SharedMediaKey(
peerId, peerId,
topicRootId, topicRootId,
monoforumPeerId,
key.type, key.type,
simpleKey), simpleKey),
limitBefore, limitBefore,

View File

@ -74,11 +74,13 @@ public:
Key( Key(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerId migratedPeerId, PeerId migratedPeerId,
Type type, Type type,
UniversalMsgId universalId) UniversalMsgId universalId)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) , topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, migratedPeerId(migratedPeerId) , migratedPeerId(migratedPeerId)
, type(type) , type(type)
, universalId(universalId) { , universalId(universalId) {
@ -91,6 +93,7 @@ public:
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
PeerId migratedPeerId = 0; PeerId migratedPeerId = 0;
Type type = Type::kCount; Type type = Type::kCount;
UniversalMsgId universalId; UniversalMsgId universalId;
@ -120,6 +123,7 @@ public:
return { return {
key.peerId, key.peerId,
key.topicRootId, key.topicRootId,
key.monoforumPeerId,
key.migratedPeerId, key.migratedPeerId,
v::is<MessageId>(key.universalId) v::is<MessageId>(key.universalId)
? v::get<MessageId>(key.universalId) ? v::get<MessageId>(key.universalId)
@ -130,6 +134,7 @@ public:
return { return {
key.peerId, key.peerId,
key.topicRootId, key.topicRootId,
key.monoforumPeerId,
key.migratedPeerId, key.migratedPeerId,
ServerMaxMsgId - 1 ServerMaxMsgId - 1
}; };

View File

@ -377,7 +377,10 @@ rpl::producer<SparseIdsMergedSlice> SparseIdsMergedSlice::CreateViewer(
int limitBefore, int limitBefore,
int limitAfter, int limitAfter,
Fn<SimpleViewerFunction> simpleViewer) { Fn<SimpleViewerFunction> simpleViewer) {
Expects(!key.topicRootId || !key.migratedPeerId); Expects(!key.topicRootId
|| (!key.monoforumPeerId && !key.migratedPeerId));
Expects(!key.monoforumPeerId
|| (!key.topicRootId && !key.migratedPeerId));
Expects(IsServerMsgId(key.universalId) Expects(IsServerMsgId(key.universalId)
|| (key.universalId == 0) || (key.universalId == 0)
|| (IsServerMsgId(ServerMaxMsgId + key.universalId) && key.migratedPeerId != 0)); || (IsServerMsgId(ServerMaxMsgId + key.universalId) && key.migratedPeerId != 0));
@ -388,6 +391,7 @@ rpl::producer<SparseIdsMergedSlice> SparseIdsMergedSlice::CreateViewer(
auto partViewer = simpleViewer( auto partViewer = simpleViewer(
key.peerId, key.peerId,
key.topicRootId, key.topicRootId,
key.monoforumPeerId,
SparseIdsMergedSlice::PartKey(key), SparseIdsMergedSlice::PartKey(key),
limitBefore, limitBefore,
limitAfter limitAfter
@ -405,6 +409,7 @@ rpl::producer<SparseIdsMergedSlice> SparseIdsMergedSlice::CreateViewer(
auto migratedViewer = simpleViewer( auto migratedViewer = simpleViewer(
key.migratedPeerId, key.migratedPeerId,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
SparseIdsMergedSlice::MigratedKey(key), SparseIdsMergedSlice::MigratedKey(key),
limitBefore, limitBefore,
limitAfter); limitAfter);

View File

@ -33,11 +33,13 @@ public:
Key( Key(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerId migratedPeerId, PeerId migratedPeerId,
UniversalMsgId universalId) UniversalMsgId universalId)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) , topicRootId(topicRootId)
, migratedPeerId(topicRootId ? 0 : migratedPeerId) , monoforumPeerId(monoforumPeerId)
, migratedPeerId((topicRootId || monoforumPeerId) ? 0 : migratedPeerId)
, universalId(universalId) { , universalId(universalId) {
} }
@ -47,6 +49,7 @@ public:
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
PeerId migratedPeerId = 0; PeerId migratedPeerId = 0;
UniversalMsgId universalId = 0; UniversalMsgId universalId = 0;
}; };
@ -72,6 +75,7 @@ public:
using SimpleViewerFunction = rpl::producer<SparseIdsSlice>( using SimpleViewerFunction = rpl::producer<SparseIdsSlice>(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SparseIdsSlice::Key simpleKey, SparseIdsSlice::Key simpleKey,
int limitBefore, int limitBefore,
int limitAfter); int limitAfter);

View File

@ -1909,7 +1909,7 @@ RowDescriptor InnerWidget::computeChatPreviewRow() const {
auto result = computeChosenRow(); auto result = computeChosenRow();
if (const auto peer = result.key.peer()) { if (const auto peer = result.key.peer()) {
const auto topicId = _pressedTopicJump const auto topicId = _pressedTopicJump
? _pressedTopicJumpRootId ? _pressedTopicJumpRootId // #TODO monoforums
: 0; : 0;
if (const auto topic = peer->forumTopicFor(topicId)) { if (const auto topic = peer->forumTopicFor(topicId)) {
return { topic, FullMsgId() }; return { topic, FullMsgId() };

View File

@ -651,8 +651,38 @@ void History::destroyMessagesBySublist(not_null<PeerData*> sublistPeer) {
} }
} }
void History::unpinMessagesFor(MsgId topicRootId) { void History::unpinMessagesFor(MsgId topicRootId, PeerId monoforumPeerId) {
if (!topicRootId) { if (topicRootId) {
session().storage().remove(
Storage::SharedMediaRemoveAll(
peer->id,
topicRootId,
Storage::SharedMediaType::Pinned));
if (const auto topic = peer->forumTopicFor(topicRootId)) {
topic->setHasPinnedMessages(false);
}
for (const auto &item : _items) {
if (item->isPinned() && item->topicRootId() == topicRootId) {
item->setIsPinned(false);
}
}
} else if (monoforumPeerId) {
session().storage().remove(
Storage::SharedMediaRemoveAll(
peer->id,
monoforumPeerId,
Storage::SharedMediaType::Pinned));
if (const auto sublist = peer->monoforumSublistFor(
monoforumPeerId)) {
sublist->setHasPinnedMessages(false);
}
for (const auto &item : _items) {
if (item->isPinned()
&& item->sublistPeerId() == monoforumPeerId) {
item->setIsPinned(false);
}
}
} else {
session().storage().remove( session().storage().remove(
Storage::SharedMediaRemoveAll( Storage::SharedMediaRemoveAll(
peer->id, peer->id,
@ -668,20 +698,6 @@ void History::unpinMessagesFor(MsgId topicRootId) {
item->setIsPinned(false); item->setIsPinned(false);
} }
} }
} else {
session().storage().remove(
Storage::SharedMediaRemoveAll(
peer->id,
topicRootId,
Storage::SharedMediaType::Pinned));
if (const auto topic = peer->forumTopicFor(topicRootId)) {
topic->setHasPinnedMessages(false);
}
for (const auto &item : _items) {
if (item->isPinned() && item->topicRootId() == topicRootId) {
item->setIsPinned(false);
}
}
} }
} }
@ -898,6 +914,7 @@ not_null<HistoryItem*> History::addNewToBack(
storage.add(Storage::SharedMediaAddExisting( storage.add(Storage::SharedMediaAddExisting(
peer->id, peer->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
types, types,
item->id, item->id,
{ from, till })); { from, till }));
@ -909,6 +926,7 @@ not_null<HistoryItem*> History::addNewToBack(
storage.add(Storage::SharedMediaAddExisting( storage.add(Storage::SharedMediaAddExisting(
peer->id, peer->id,
topic->rootId(), topic->rootId(),
PeerId(), // monoforumPeerId
types, types,
item->id, item->id,
{ item->id, item->id})); { item->id, item->id}));
@ -916,6 +934,18 @@ not_null<HistoryItem*> History::addNewToBack(
topic->setHasPinnedMessages(true); topic->setHasPinnedMessages(true);
} }
} }
if (const auto sublist = item->savedSublist()) {
storage.add(Storage::SharedMediaAddExisting(
peer->id,
MsgId(), // topicRootId
item->sublistPeerId(),
types,
item->id,
{ item->id, item->id }));
if (pinned) {
sublist->setHasPinnedMessages(true);
}
}
} }
} }
if (item->from()->id) { if (item->from()->id) {
@ -1182,7 +1212,8 @@ void History::applyServiceChanges(
if (id && item) { if (id && item) {
session().storage().add(Storage::SharedMediaAddSlice( session().storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
MsgId(0), MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
{ id }, { id },
{ id, ServerMaxMsgId })); { id, ServerMaxMsgId }));
@ -1191,11 +1222,22 @@ void History::applyServiceChanges(
session().storage().add(Storage::SharedMediaAddSlice( session().storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
topic->rootId(), topic->rootId(),
PeerId(), // monoforumPeerId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
{ id }, { id },
{ id, ServerMaxMsgId })); { id, ServerMaxMsgId }));
topic->setHasPinnedMessages(true); topic->setHasPinnedMessages(true);
} }
if (const auto sublist = item->savedSublist()) {
session().storage().add(Storage::SharedMediaAddSlice(
peer->id,
MsgId(), // topicRootId
item->sublistPeerId(),
Storage::SharedMediaType::Pinned,
{ id },
{ id, ServerMaxMsgId }));
sublist->setHasPinnedMessages(true);
}
} }
}, [&](const MTPDmessageReplyStoryHeader &data) { }, [&](const MTPDmessageReplyStoryHeader &data) {
LOG(("API Error: story reply in messageActionPinMessage.")); LOG(("API Error: story reply in messageActionPinMessage."));
@ -1470,6 +1512,7 @@ void History::addEdgesToSharedMedia() {
session().storage().add(Storage::SharedMediaAddSlice( session().storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
type, type,
{}, {},
{ from, till })); { from, till }));
@ -1683,6 +1726,7 @@ void History::addToSharedMedia(
session().storage().add(Storage::SharedMediaAddSlice( session().storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
type, type,
std::move(medias[i]), std::move(medias[i]),
{ from, till })); { from, till }));
@ -3162,11 +3206,9 @@ void History::forceFullResize() {
Data::Thread *History::threadFor(MsgId topicRootId, PeerId monoforumPeerId) { Data::Thread *History::threadFor(MsgId topicRootId, PeerId monoforumPeerId) {
return topicRootId return topicRootId
? peer->forumTopicFor(topicRootId) ? peer->forumTopicFor(topicRootId)
: !monoforumPeerId : monoforumPeerId
? static_cast<Data::Thread*>(this) ? peer->monoforumSublistFor(monoforumPeerId)
: peer->monoforum() : static_cast<Data::Thread*>(this);
? peer->monoforum()->sublistLoaded(owner().peer(monoforumPeerId))
: nullptr;
} }
const Data::Thread *History::threadFor( const Data::Thread *History::threadFor(

View File

@ -141,7 +141,7 @@ public:
void destroyMessagesByTopic(MsgId topicRootId); void destroyMessagesByTopic(MsgId topicRootId);
void destroyMessagesBySublist(not_null<PeerData*> sublistPeer); void destroyMessagesBySublist(not_null<PeerData*> sublistPeer);
void unpinMessagesFor(MsgId topicRootId); void unpinMessagesFor(MsgId topicRootId, PeerId monoforumPeerId);
not_null<HistoryItem*> addNewMessage( not_null<HistoryItem*> addNewMessage(
MsgId id, MsgId id,

View File

@ -1513,6 +1513,7 @@ void HistoryItem::setIsPinned(bool pinned) {
storage.add(Storage::SharedMediaAddExisting( storage.add(Storage::SharedMediaAddExisting(
_history->peer->id, _history->peer->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
id, id,
{ id, id })); { id, id }));
@ -1521,11 +1522,22 @@ void HistoryItem::setIsPinned(bool pinned) {
storage.add(Storage::SharedMediaAddExisting( storage.add(Storage::SharedMediaAddExisting(
_history->peer->id, _history->peer->id,
topic->rootId(), topic->rootId(),
PeerId(), // monoforumPeerId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
id, id,
{ id, id })); { id, id }));
topic->setHasPinnedMessages(true); topic->setHasPinnedMessages(true);
} }
if (const auto sublist = this->savedSublist()) {
storage.add(Storage::SharedMediaAddExisting(
_history->peer->id,
MsgId(0), // topicRootId
sublistPeerId(),
Storage::SharedMediaType::Pinned,
id,
{ id, id }));
sublist->setHasPinnedMessages(true);
}
} else { } else {
_flags &= ~MessageFlag::Pinned; _flags &= ~MessageFlag::Pinned;
if (_flags & MessageFlag::StoryItem) { if (_flags & MessageFlag::StoryItem) {
@ -2238,6 +2250,7 @@ void HistoryItem::addToSharedMediaIndex() {
_history->session().storage().add(Storage::SharedMediaAddNew( _history->session().storage().add(Storage::SharedMediaAddNew(
_history->peer->id, _history->peer->id,
topicRootId(), topicRootId(),
sublistPeerId(),
types, types,
id)); id));
if (types.test(Storage::SharedMediaType::Pinned)) { if (types.test(Storage::SharedMediaType::Pinned)) {
@ -2245,6 +2258,9 @@ void HistoryItem::addToSharedMediaIndex() {
if (const auto topic = this->topic()) { if (const auto topic = this->topic()) {
topic->setHasPinnedMessages(true); topic->setHasPinnedMessages(true);
} }
if (const auto sublist = this->savedSublist()) {
sublist->setHasPinnedMessages(true);
}
} }
} }
} }

View File

@ -6038,7 +6038,7 @@ bool HistoryWidget::showSendingFilesError(
return true; return true;
} }
MsgId HistoryWidget::resolveReplyToTopicRootId() { MsgId HistoryWidget::resolveReplyToTopicRootId() { // #TODO monoforums
Expects(_peer != nullptr); Expects(_peer != nullptr);
const auto replyToInfo = replyTo(); const auto replyToInfo = replyTo();
@ -7601,6 +7601,7 @@ void HistoryWidget::updatePinnedViewer() {
_minPinnedId = Data::ResolveMinPinnedId( _minPinnedId = Data::ResolveMinPinnedId(
_peer, _peer,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
_migrated ? _migrated->peer.get() : nullptr); _migrated ? _migrated->peer.get() : nullptr);
} }
if (_pinnedClickedId if (_pinnedClickedId
@ -7680,6 +7681,7 @@ void HistoryWidget::checkPinnedBarState() {
const auto currentPinnedId = Data::ResolveTopPinnedId( const auto currentPinnedId = Data::ResolveTopPinnedId(
_peer, _peer,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
_migrated ? _migrated->peer.get() : nullptr); _migrated ? _migrated->peer.get() : nullptr);
const auto universalPinnedId = !currentPinnedId const auto universalPinnedId = !currentPinnedId
? int32(0) ? int32(0)
@ -7713,6 +7715,7 @@ void HistoryWidget::checkPinnedBarState() {
auto pinnedRefreshed = Info::Profile::SharedMediaCountValue( auto pinnedRefreshed = Info::Profile::SharedMediaCountValue(
_peer, _peer,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
nullptr, nullptr,
Storage::SharedMediaType::Pinned Storage::SharedMediaType::Pinned
) | rpl::distinct_until_changed( ) | rpl::distinct_until_changed(
@ -8593,6 +8596,7 @@ void HistoryWidget::hidePinnedMessage() {
controller(), controller(),
_peer, _peer,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
crl::guard(this, callback)); crl::guard(this, callback));
} }
} }

View File

@ -151,7 +151,7 @@ void ChatMemento::setFromTopic(not_null<Data::ForumTopic*> topic) {
} }
Data::ForumTopic *ChatMemento::topicForRemoveRequests() const { Data::ForumTopic *ChatMemento::topicForRemoveRequests() const {// #TODO monoforums
return _id.repliesRootId return _id.repliesRootId
? _id.history->peer->forumTopicFor(_id.repliesRootId) ? _id.history->peer->forumTopicFor(_id.repliesRootId)
: nullptr; : nullptr;
@ -233,6 +233,9 @@ ChatWidget::ChatWidget(
, _topic(lookupTopic()) , _topic(lookupTopic())
, _areComments(computeAreComments()) , _areComments(computeAreComments())
, _sublist(_id.sublist) , _sublist(_id.sublist)
, _monoforumPeerId((_sublist && _sublist->parentChat())
? _sublist->sublistPeer()->id
: PeerId())
, _sendAction(_repliesRootId , _sendAction(_repliesRootId
? _history->owner().sendActionManager().repliesPainter( ? _history->owner().sendActionManager().repliesPainter(
_history, _history,
@ -772,7 +775,7 @@ void ChatWidget::setupComposeControls() {
_composeControls->setHistory({ _composeControls->setHistory({
.history = _history.get(), .history = _history.get(),
.topicRootId = _topic ? _topic->rootId() : MsgId(), .topicRootId = _topic ? _topic->rootId() : MsgId(),
.monoforumPeerId = _sublist ? _sublist->sublistPeer()->id : PeerId(), .monoforumPeerId = _monoforumPeerId,
.showSlowmodeError = [=] { return showSlowmodeError(); }, .showSlowmodeError = [=] { return showSlowmodeError(); },
.sendActionFactory = [=] { return prepareSendAction({}); }, .sendActionFactory = [=] { return prepareSendAction({}); },
.slowmodeSecondsLeft = SlowmodeSecondsLeft(_peer), .slowmodeSecondsLeft = SlowmodeSecondsLeft(_peer),
@ -1781,20 +1784,17 @@ SendMenu::Details ChatWidget::sendMenuDetails() const {
} }
FullReplyTo ChatWidget::replyTo() const { FullReplyTo ChatWidget::replyTo() const {
const auto monoforumPeerId = (_sublist && _sublist->parentChat())
? _sublist->sublistPeer()->id
: PeerId();
if (auto custom = _composeControls->replyingToMessage()) { if (auto custom = _composeControls->replyingToMessage()) {
const auto item = custom.messageId const auto item = custom.messageId
? session().data().message(custom.messageId) ? session().data().message(custom.messageId)
: nullptr; : nullptr;
const auto sublistPeerId = item ? item->sublistPeerId() : PeerId(); const auto sublistPeerId = item ? item->sublistPeerId() : PeerId();
if (!item if (!item
|| !monoforumPeerId || !_monoforumPeerId
|| (sublistPeerId == monoforumPeerId)) { || (sublistPeerId == _monoforumPeerId)) {
// Never answer to a message in a wrong monoforum peer id. // Never answer to a message in a wrong monoforum peer id.
custom.topicRootId = _repliesRootId; custom.topicRootId = _repliesRootId;
custom.monoforumPeerId = monoforumPeerId; custom.monoforumPeerId = _monoforumPeerId;
return custom; return custom;
} }
} }
@ -1803,7 +1803,7 @@ FullReplyTo ChatWidget::replyTo() const {
? FullMsgId(_peer->id, _repliesRootId) ? FullMsgId(_peer->id, _repliesRootId)
: FullMsgId()), : FullMsgId()),
.topicRootId = _repliesRootId, .topicRootId = _repliesRootId,
.monoforumPeerId = monoforumPeerId, .monoforumPeerId = _monoforumPeerId,
}; };
} }
@ -1850,7 +1850,10 @@ void ChatWidget::updatePinnedViewer() {
_pinnedClickedId = FullMsgId(); _pinnedClickedId = FullMsgId();
} }
if (_pinnedClickedId && !_minPinnedId) { if (_pinnedClickedId && !_minPinnedId) {
_minPinnedId = Data::ResolveMinPinnedId(_peer, _repliesRootId); _minPinnedId = Data::ResolveMinPinnedId(
_peer,
_repliesRootId,
_monoforumPeerId);
} }
if (_pinnedClickedId && _minPinnedId && _minPinnedId >= _pinnedClickedId) { if (_pinnedClickedId && _minPinnedId && _minPinnedId >= _pinnedClickedId) {
// After click on the last pinned message we should the top one. // After click on the last pinned message we should the top one.
@ -1955,6 +1958,7 @@ void ChatWidget::setupPinnedTracker() {
Storage::SharedMediaKey( Storage::SharedMediaKey(
_topic->channel()->id, _topic->channel()->id,
_repliesRootId, _repliesRootId,
_monoforumPeerId,
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1), ServerMaxMsgId - 1),
1, 1,
@ -1968,10 +1972,15 @@ void ChatWidget::setupPinnedTracker() {
const auto peerId = _peer->id; const auto peerId = _peer->id;
const auto hiddenId = settings.hiddenPinnedMessageId( const auto hiddenId = settings.hiddenPinnedMessageId(
peerId, peerId,
_repliesRootId); _repliesRootId,
_monoforumPeerId);
const auto last = result.size() ? result[result.size() - 1] : 0; const auto last = result.size() ? result[result.size() - 1] : 0;
if (hiddenId && hiddenId != last) { if (hiddenId && hiddenId != last) {
settings.setHiddenPinnedMessageId(peerId, _repliesRootId, 0); settings.setHiddenPinnedMessageId(
peerId,
_repliesRootId,
_monoforumPeerId,
0);
_history->session().saveSettingsDelayed(); _history->session().saveSettingsDelayed();
} }
} }
@ -1987,10 +1996,12 @@ void ChatWidget::checkPinnedBarState() {
? MsgId(0) ? MsgId(0)
: _peer->session().settings().hiddenPinnedMessageId( : _peer->session().settings().hiddenPinnedMessageId(
_peer->id, _peer->id,
_repliesRootId); _repliesRootId,
_monoforumPeerId);
const auto currentPinnedId = Data::ResolveTopPinnedId( const auto currentPinnedId = Data::ResolveTopPinnedId(
_peer, _peer,
_repliesRootId); _repliesRootId,
_monoforumPeerId);
const auto universalPinnedId = !currentPinnedId const auto universalPinnedId = !currentPinnedId
? MsgId(0) ? MsgId(0)
: currentPinnedId.msg; : currentPinnedId.msg;
@ -2021,6 +2032,7 @@ void ChatWidget::checkPinnedBarState() {
auto pinnedRefreshed = Info::Profile::SharedMediaCountValue( auto pinnedRefreshed = Info::Profile::SharedMediaCountValue(
_peer, _peer,
_repliesRootId, _repliesRootId,
_monoforumPeerId,
nullptr, nullptr,
Storage::SharedMediaType::Pinned Storage::SharedMediaType::Pinned
) | rpl::distinct_until_changed( ) | rpl::distinct_until_changed(
@ -2187,6 +2199,7 @@ void ChatWidget::hidePinnedMessage() {
controller(), controller(),
_peer, _peer,
_repliesRootId, _repliesRootId,
_monoforumPeerId,
crl::guard(this, callback)); crl::guard(this, callback));
} }
} }
@ -3193,7 +3206,9 @@ void ChatWidget::listShowPremiumToast(not_null<DocumentData*> document) {
void ChatWidget::listOpenPhoto( void ChatWidget::listOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
controller()->openPhoto(photo, { context, _repliesRootId }); controller()->openPhoto(
photo,
{ context, _repliesRootId, _monoforumPeerId });
} }
void ChatWidget::listOpenDocument( void ChatWidget::listOpenDocument(
@ -3203,7 +3218,7 @@ void ChatWidget::listOpenDocument(
controller()->openDocument( controller()->openDocument(
document, document,
showInMediaView, showInMediaView,
{ context, _repliesRootId }); { context, _repliesRootId, _monoforumPeerId });
} }
void ChatWidget::listPaintEmpty( void ChatWidget::listPaintEmpty(

View File

@ -394,6 +394,7 @@ private:
rpl::variable<bool> _areComments = false; rpl::variable<bool> _areComments = false;
Data::SavedSublist *_sublist = nullptr; Data::SavedSublist *_sublist = nullptr;
PeerId _monoforumPeerId;
std::shared_ptr<SendActionPainter> _sendAction; std::shared_ptr<SendActionPainter> _sendAction;
std::shared_ptr<Ui::ChatTheme> _theme; std::shared_ptr<Ui::ChatTheme> _theme;

View File

@ -195,6 +195,7 @@ void PinnedWidget::setupClearButton() {
controller(), controller(),
_history->peer, _history->peer,
_thread->topicRootId(), _thread->topicRootId(),
_thread->monoforumPeerId(),
crl::guard(this, callback)); crl::guard(this, callback));
} else { } else {
Window::UnpinAllMessages(controller(), _thread); Window::UnpinAllMessages(controller(), _thread);
@ -517,6 +518,7 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
_history->peer->id, _history->peer->id,
_thread->topicRootId(), _thread->topicRootId(),
_thread->monoforumPeerId(),
_migratedPeer ? _migratedPeer->id : 0, _migratedPeer ? _migratedPeer->id : 0,
messageId), messageId),
Storage::SharedMediaType::Pinned), Storage::SharedMediaType::Pinned),

View File

@ -86,6 +86,7 @@ void PinnedTracker::refreshViewer() {
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
peer->id, peer->id,
_thread->topicRootId(), _thread->topicRootId(),
_thread->monoforumPeerId(),
_migratedPeer ? _migratedPeer->id : 0, _migratedPeer ? _migratedPeer->id : 0,
_viewerAroundId), _viewerAroundId),
Storage::SharedMediaType::Pinned), Storage::SharedMediaType::Pinned),

View File

@ -751,7 +751,7 @@ void TopBarWidget::infoClicked() {
_controller->showSection(std::make_shared<Info::Memento>(topic)); _controller->showSection(std::make_shared<Info::Memento>(topic));
} else if (const auto sublist = key.sublist()) { } else if (const auto sublist = key.sublist()) {
_controller->showSection(std::make_shared<Info::Memento>( _controller->showSection(std::make_shared<Info::Memento>(
sublist->owningHistory()->peer, sublist,
Info::Section(Storage::SharedMediaType::Photo))); Info::Section(Storage::SharedMediaType::Photo)));
} else if (key.peer()->savedSublistsInfo()) { } else if (key.peer()->savedSublistsInfo()) {
_controller->showSection(std::make_shared<Info::Memento>( _controller->showSection(std::make_shared<Info::Memento>(

View File

@ -21,7 +21,7 @@ namespace Info {
namespace CommonGroups { namespace CommonGroups {
Memento::Memento(not_null<UserData*> user) Memento::Memento(not_null<UserData*> user)
: ContentMemento(user, nullptr, PeerId()) { : ContentMemento(user, nullptr, nullptr, PeerId()) {
} }
Section Memento::section() const { Section Memento::section() const {

View File

@ -307,6 +307,7 @@ QRect ContentWidget::floatPlayerAvailableRect() const {
void ContentWidget::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) { void ContentWidget::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
const auto peer = _controller->key().peer(); const auto peer = _controller->key().peer();
const auto topic = _controller->key().topic(); const auto topic = _controller->key().topic();
const auto sublist = _controller->key().sublist();
if (!peer && !topic) { if (!peer && !topic) {
return; return;
} }
@ -316,6 +317,8 @@ void ContentWidget::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
Dialogs::EntryState{ Dialogs::EntryState{
.key = (topic .key = (topic
? Dialogs::Key{ topic } ? Dialogs::Key{ topic }
: sublist
? Dialogs::Key{ sublist }
: Dialogs::Key{ peer->owner().history(peer) }), : Dialogs::Key{ peer->owner().history(peer) }),
.section = Dialogs::EntryState::Section::Profile, .section = Dialogs::EntryState::Section::Profile,
}, },
@ -465,6 +468,8 @@ void ContentWidget::setupSwipeHandler(not_null<Ui::RpWidget*> widget) {
Key ContentMemento::key() const { Key ContentMemento::key() const {
if (const auto topic = this->topic()) { if (const auto topic = this->topic()) {
return Key(topic); return Key(topic);
} else if (const auto sublist = this->sublist()) {
return Key(sublist);
} else if (const auto peer = this->peer()) { } else if (const auto peer = this->peer()) {
return Key(peer); return Key(peer);
} else if (const auto poll = this->poll()) { } else if (const auto poll = this->poll()) {
@ -489,12 +494,14 @@ Key ContentMemento::key() const {
ContentMemento::ContentMemento( ContentMemento::ContentMemento(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Data::ForumTopic *topic, Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId) PeerId migratedPeerId)
: _peer(peer) : _peer(peer)
, _migratedPeerId((!topic && peer->migrateFrom()) , _migratedPeerId((!topic && !sublist && peer->migrateFrom())
? peer->migrateFrom()->id ? peer->migrateFrom()->id
: 0) : 0)
, _topic(topic) { , _topic(topic)
, _sublist(sublist) {
if (_topic) { if (_topic) {
_peer->owner().itemIdChanged( _peer->owner().itemIdChanged(
) | rpl::start_with_next([=](const Data::Session::IdChange &change) { ) | rpl::start_with_next([=](const Data::Session::IdChange &change) {

View File

@ -210,6 +210,7 @@ public:
ContentMemento( ContentMemento(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Data::ForumTopic *topic, Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId); PeerId migratedPeerId);
explicit ContentMemento(Settings::Tag settings); explicit ContentMemento(Settings::Tag settings);
explicit ContentMemento(Downloads::Tag downloads); explicit ContentMemento(Downloads::Tag downloads);
@ -240,6 +241,9 @@ public:
Data::ForumTopic *topic() const { Data::ForumTopic *topic() const {
return _topic; return _topic;
} }
Data::SavedSublist *sublist() const {
return _sublist;
}
UserData *settingsSelf() const { UserData *settingsSelf() const {
return _settingsSelf; return _settingsSelf;
} }
@ -311,6 +315,7 @@ private:
PeerData * const _peer = nullptr; PeerData * const _peer = nullptr;
const PeerId _migratedPeerId = 0; const PeerId _migratedPeerId = 0;
Data::ForumTopic *_topic = nullptr; Data::ForumTopic *_topic = nullptr;
Data::SavedSublist *_sublist = nullptr;
UserData * const _settingsSelf = nullptr; UserData * const _settingsSelf = nullptr;
PeerData * const _storiesPeer = nullptr; PeerData * const _storiesPeer = nullptr;
Stories::Tab _storiesTab = {}; Stories::Tab _storiesTab = {};

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/search_field_controller.h" #include "ui/search_field_controller.h"
#include "data/data_shared_media.h" #include "data/data_shared_media.h"
#include "history/history.h"
#include "info/info_content_widget.h" #include "info/info_content_widget.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/global_media/info_global_media_widget.h" #include "info/global_media/info_global_media_widget.h"
@ -20,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
#include "data/data_download_manager.h" #include "data/data_download_manager.h"
@ -35,6 +37,9 @@ Key::Key(not_null<PeerData*> peer) : _value(peer) {
Key::Key(not_null<Data::ForumTopic*> topic) : _value(topic) { Key::Key(not_null<Data::ForumTopic*> topic) : _value(topic) {
} }
Key::Key(not_null<Data::SavedSublist*> sublist) : _value(sublist) {
}
Key::Key(Settings::Tag settings) : _value(settings) { Key::Key(Settings::Tag settings) : _value(settings) {
} }
@ -69,6 +74,8 @@ PeerData *Key::peer() const {
return *peer; return *peer;
} else if (const auto topic = this->topic()) { } else if (const auto topic = this->topic()) {
return topic->channel(); return topic->channel();
} else if (const auto sublist = this->sublist()) {
return sublist->owningHistory()->peer;
} }
return nullptr; return nullptr;
} }
@ -81,6 +88,14 @@ Data::ForumTopic *Key::topic() const {
return nullptr; return nullptr;
} }
Data::SavedSublist *Key::sublist() const {
if (const auto sublist = std::get_if<not_null<Data::SavedSublist*>>(
&_value)) {
return *sublist;
}
return nullptr;
}
UserData *Key::settingsSelf() const { UserData *Key::settingsSelf() const {
if (const auto tag = std::get_if<Settings::Tag>(&_value)) { if (const auto tag = std::get_if<Settings::Tag>(&_value)) {
return tag->self; return tag->self;
@ -195,6 +210,7 @@ rpl::producer<SparseIdsMergedSlice> AbstractController::mediaSource(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
peer()->id, peer()->id,
topicId, topicId,
sublist() ? sublist()->sublistPeer()->id : PeerId(),
migratedPeerId(), migratedPeerId(),
aroundId), aroundId),
section().mediaType()), section().mediaType()),
@ -487,6 +503,7 @@ rpl::producer<SparseIdsMergedSlice> Controller::mediaSource(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
query.peerId, query.peerId,
query.topicRootId, query.topicRootId,
query.monoforumPeerId,
query.migratedPeerId, query.migratedPeerId,
aroundId), aroundId),
query.type), query.type),

View File

@ -18,6 +18,7 @@ struct WhoReadList;
namespace Data { namespace Data {
class ForumTopic; class ForumTopic;
class SavedSublist;
} // namespace Data } // namespace Data
namespace Ui { namespace Ui {
@ -94,6 +95,7 @@ class Key {
public: public:
explicit Key(not_null<PeerData*> peer); explicit Key(not_null<PeerData*> peer);
explicit Key(not_null<Data::ForumTopic*> topic); explicit Key(not_null<Data::ForumTopic*> topic);
explicit Key(not_null<Data::SavedSublist*> sublist);
Key(Settings::Tag settings); Key(Settings::Tag settings);
Key(Downloads::Tag downloads); Key(Downloads::Tag downloads);
Key(Stories::Tag stories); Key(Stories::Tag stories);
@ -108,6 +110,7 @@ public:
PeerData *peer() const; PeerData *peer() const;
Data::ForumTopic *topic() const; Data::ForumTopic *topic() const;
Data::SavedSublist *sublist() const;
UserData *settingsSelf() const; UserData *settingsSelf() const;
bool isDownloads() const; bool isDownloads() const;
bool isGlobalMedia() const; bool isGlobalMedia() const;
@ -135,6 +138,7 @@ private:
std::variant< std::variant<
not_null<PeerData*>, not_null<PeerData*>,
not_null<Data::ForumTopic*>, not_null<Data::ForumTopic*>,
not_null<Data::SavedSublist*>,
Settings::Tag, Settings::Tag,
Downloads::Tag, Downloads::Tag,
Stories::Tag, Stories::Tag,
@ -225,6 +229,9 @@ public:
[[nodiscard]] Data::ForumTopic *topic() const { [[nodiscard]] Data::ForumTopic *topic() const {
return key().topic(); return key().topic();
} }
[[nodiscard]] Data::SavedSublist *sublist() const {
return key().sublist();
}
[[nodiscard]] UserData *settingsSelf() const { [[nodiscard]] UserData *settingsSelf() const {
return key().settingsSelf(); return key().settingsSelf();
} }

View File

@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -48,6 +49,14 @@ Memento::Memento(not_null<Data::ForumTopic*> topic, Section section)
: Memento(DefaultStack(topic, section)) { : Memento(DefaultStack(topic, section)) {
} }
Memento::Memento(not_null<Data::SavedSublist*> sublist)
: Memento(sublist, Section::Type::Profile) {
}
Memento::Memento(not_null<Data::SavedSublist*> sublist, Section section)
: Memento(DefaultStack(sublist, section)) {
}
Memento::Memento(Settings::Tag settings, Section section) Memento::Memento(Settings::Tag settings, Section section)
: Memento(DefaultStack(settings, section)) { : Memento(DefaultStack(settings, section)) {
} }
@ -66,9 +75,12 @@ Memento::Memento(
Memento::Memento(std::vector<std::shared_ptr<ContentMemento>> stack) Memento::Memento(std::vector<std::shared_ptr<ContentMemento>> stack)
: _stack(std::move(stack)) { : _stack(std::move(stack)) {
auto topics = base::flat_set<not_null<Data::ForumTopic*>>(); auto topics = base::flat_set<not_null<Data::ForumTopic*>>();
auto sublists = base::flat_set<not_null<Data::SavedSublist*>>();
for (auto &entry : _stack) { for (auto &entry : _stack) {
if (const auto topic = entry->topic()) { if (const auto topic = entry->topic()) {
topics.emplace(topic); topics.emplace(topic);
} else if (const auto sublist = entry->sublist()) {
sublists.emplace(sublist);
} }
} }
for (const auto &topic : topics) { for (const auto &topic : topics) {
@ -86,6 +98,21 @@ Memento::Memento(std::vector<std::shared_ptr<ContentMemento>> stack)
} }
}, _lifetime); }, _lifetime);
} }
for (const auto &sublist : sublists) {
sublist->destroyed(
) | rpl::start_with_next([=] {
for (auto i = begin(_stack); i != end(_stack);) {
if (i->get()->sublist() == sublist) {
i = _stack.erase(i);
} else {
++i;
}
}
if (_stack.empty()) {
_removeRequests.fire({});
}
}, _lifetime);
}
} }
std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack( std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
@ -104,6 +131,14 @@ std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
return result; return result;
} }
std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
not_null<Data::SavedSublist*> sublist,
Section section) {
auto result = std::vector<std::shared_ptr<ContentMemento>>();
result.push_back(DefaultContent(sublist, section));
return result;
}
std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack( std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
Settings::Tag settings, Settings::Tag settings,
Section section) { Section section) {
@ -205,6 +240,20 @@ std::shared_ptr<ContentMemento> Memento::DefaultContent(
Unexpected("Wrong section type in Info::Memento::DefaultContent()"); Unexpected("Wrong section type in Info::Memento::DefaultContent()");
} }
std::shared_ptr<ContentMemento> Memento::DefaultContent(
not_null<Data::SavedSublist*> sublist,
Section section) {
switch (section.type()) {
case Section::Type::Profile:
return std::make_shared<Profile::Memento>(sublist);
case Section::Type::Media:
return std::make_shared<Media::Memento>(
sublist,
section.mediaType());
}
Unexpected("Wrong section type in Info::Memento::DefaultContent()");
}
object_ptr<Window::SectionWidget> Memento::createWidget( object_ptr<Window::SectionWidget> Memento::createWidget(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,

View File

@ -23,6 +23,7 @@ enum class SharedMediaType : signed char;
namespace Data { namespace Data {
class ForumTopic; class ForumTopic;
class SavedSublist;
struct ReactionId; struct ReactionId;
} // namespace Data } // namespace Data
@ -49,6 +50,8 @@ public:
Memento(not_null<PeerData*> peer, Section section); Memento(not_null<PeerData*> peer, Section section);
explicit Memento(not_null<Data::ForumTopic*> topic); explicit Memento(not_null<Data::ForumTopic*> topic);
Memento(not_null<Data::ForumTopic*> topic, Section section); Memento(not_null<Data::ForumTopic*> topic, Section section);
explicit Memento(not_null<Data::SavedSublist*> sublist);
Memento(not_null<Data::SavedSublist*> sublist, Section section);
Memento(Settings::Tag settings, Section section); Memento(Settings::Tag settings, Section section);
Memento(not_null<PollData*> poll, FullMsgId contextId); Memento(not_null<PollData*> poll, FullMsgId contextId);
Memento( Memento(
@ -94,6 +97,9 @@ private:
static std::vector<std::shared_ptr<ContentMemento>> DefaultStack( static std::vector<std::shared_ptr<ContentMemento>> DefaultStack(
not_null<Data::ForumTopic*> topic, not_null<Data::ForumTopic*> topic,
Section section); Section section);
static std::vector<std::shared_ptr<ContentMemento>> DefaultStack(
not_null<Data::SavedSublist*> sublist,
Section section);
static std::vector<std::shared_ptr<ContentMemento>> DefaultStack( static std::vector<std::shared_ptr<ContentMemento>> DefaultStack(
Settings::Tag settings, Settings::Tag settings,
Section section); Section section);
@ -111,6 +117,9 @@ private:
static std::shared_ptr<ContentMemento> DefaultContent( static std::shared_ptr<ContentMemento> DefaultContent(
not_null<Data::ForumTopic*> topic, not_null<Data::ForumTopic*> topic,
Section section); Section section);
static std::shared_ptr<ContentMemento> DefaultContent(
not_null<Data::SavedSublist*> sublist,
Section section);
std::vector<std::shared_ptr<ContentMemento>> _stack; std::vector<std::shared_ptr<ContentMemento>> _stack;
rpl::event_stream<> _removeRequests; rpl::event_stream<> _removeRequests;

View File

@ -147,12 +147,18 @@ not_null<Ui::SettingsButton*> AddButton(
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated, PeerData *migrated,
Type type, Type type,
Ui::MultiSlideTracker &tracker) { Ui::MultiSlideTracker &tracker) {
auto result = AddCountedButton( auto result = AddCountedButton(
parent, parent,
Profile::SharedMediaCountValue(peer, topicRootId, migrated, type), Profile::SharedMediaCountValue(
peer,
topicRootId,
monoforumPeerId,
migrated,
type),
MediaText(type), MediaText(type),
tracker)->entity(); tracker)->entity();
const auto separateId = SeparateId(peer, topicRootId, type); const auto separateId = SeparateId(peer, topicRootId, type);

View File

@ -42,6 +42,7 @@ using Type = Storage::SharedMediaType;
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated, PeerData *migrated,
Type type, Type type,
Ui::MultiSlideTracker &tracker); Ui::MultiSlideTracker &tracker);

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/info_controller.h" #include "info/info_controller.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_peer.h" #include "data/data_peer.h"
#include "data/data_saved_sublist.h"
#include "ui/widgets/discrete_sliders.h" #include "ui/widgets/discrete_sliders.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -79,7 +80,11 @@ void InnerWidget::createTypeButtons() {
auto tracker = Ui::MultiSlideTracker(); auto tracker = Ui::MultiSlideTracker();
const auto peer = _controller->key().peer(); const auto peer = _controller->key().peer();
const auto topic = _controller->key().topic(); const auto topic = _controller->key().topic();
const auto sublist = _controller->key().sublist();
const auto topicRootId = topic ? topic->rootId() : MsgId(); const auto topicRootId = topic ? topic->rootId() : MsgId();
const auto monoforumPeerId = sublist
? sublist->sublistPeer()->id
: PeerId();
const auto migrated = _controller->migrated(); const auto migrated = _controller->migrated();
const auto addMediaButton = [&]( const auto addMediaButton = [&](
Type buttonType, Type buttonType,
@ -92,6 +97,7 @@ void InnerWidget::createTypeButtons() {
_controller, _controller,
peer, peer,
topicRootId, topicRootId,
monoforumPeerId,
migrated, migrated,
buttonType, buttonType,
tracker); tracker);

View File

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_download_manager.h" #include "data/data_download_manager.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history_item_helpers.h" #include "history/history_item_helpers.h"
#include "history/history.h" #include "history/history.h"
@ -512,7 +513,7 @@ void ListWidget::openPhoto(not_null<PhotoData*> photo, FullMsgId id) {
: Data::StoriesContext{ Data::StoriesContextSaved() }; : Data::StoriesContext{ Data::StoriesContextSaved() };
_controller->parentController()->openPhoto( _controller->parentController()->openPhoto(
photo, photo,
{ id, topicRootId() }, { id, topicRootId(), monoforumPeerId() },
_controller->storiesPeer() ? &context : nullptr); _controller->storiesPeer() ? &context : nullptr);
} }
@ -527,7 +528,7 @@ void ListWidget::openDocument(
_controller->parentController()->openDocument( _controller->parentController()->openDocument(
document, document,
showInMediaView, showInMediaView,
{ id, topicRootId() }, { id, topicRootId(), monoforumPeerId() },
_controller->storiesPeer() ? &context : nullptr); _controller->storiesPeer() ? &context : nullptr);
} }
@ -796,6 +797,11 @@ MsgId ListWidget::topicRootId() const {
return topic ? topic->rootId() : MsgId(0); return topic ? topic->rootId() : MsgId(0);
} }
PeerId ListWidget::monoforumPeerId() const {
const auto sublist = _controller->key().sublist();
return sublist ? sublist->sublistPeer()->id : PeerId(0);
}
QMargins ListWidget::padding() const { QMargins ListWidget::padding() const {
return st::infoMediaMargin; return st::infoMediaMargin;
} }

View File

@ -158,6 +158,7 @@ private:
void setupSelectRestriction(); void setupSelectRestriction();
[[nodiscard]] MsgId topicRootId() const; [[nodiscard]] MsgId topicRootId() const;
[[nodiscard]] PeerId monoforumPeerId() const;
QMargins padding() const; QMargins padding() const;
bool isItemLayout( bool isItemLayout(

View File

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#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_saved_sublist.h"
#include "styles/style_info.h" #include "styles/style_info.h"
#include "styles/style_overview.h" #include "styles/style_overview.h"
@ -40,7 +41,10 @@ Provider::Provider(not_null<AbstractController*> controller)
, _peer(_controller->key().peer()) , _peer(_controller->key().peer())
, _topicRootId(_controller->key().topic() , _topicRootId(_controller->key().topic()
? _controller->key().topic()->rootId() ? _controller->key().topic()->rootId()
: 0) : MsgId())
, _monoforumPeerId(_controller->key().sublist()
? _controller->key().sublist()->sublistPeer()->id
: PeerId())
, _migrated(_controller->migrated()) , _migrated(_controller->migrated())
, _type(_controller->section().mediaType()) , _type(_controller->section().mediaType())
, _slice(sliceKey(_universalAroundId)) { , _slice(sliceKey(_universalAroundId)) {
@ -331,13 +335,23 @@ SparseIdsMergedSlice::Key Provider::sliceKey(
UniversalMsgId universalId) const { UniversalMsgId universalId) const {
using Key = SparseIdsMergedSlice::Key; using Key = SparseIdsMergedSlice::Key;
if (!_topicRootId && _migrated) { if (!_topicRootId && _migrated) {
return Key(_peer->id, _topicRootId, _migrated->id, universalId); return Key(
_peer->id,
_topicRootId,
_monoforumPeerId,
_migrated->id,
universalId);
} }
if (universalId < 0) { if (universalId < 0) {
// Convert back to plain id for non-migrated histories. // Convert back to plain id for non-migrated histories.
universalId = universalId + ServerMaxMsgId; universalId = universalId + ServerMaxMsgId;
} }
return Key(_peer->id, _topicRootId, 0, universalId); return Key(
_peer->id,
_topicRootId,
_monoforumPeerId,
PeerId(),
universalId);
} }
void Provider::itemRemoved(not_null<const HistoryItem*> item) { void Provider::itemRemoved(not_null<const HistoryItem*> item) {

View File

@ -105,6 +105,7 @@ private:
const not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
const MsgId _topicRootId = 0; const MsgId _topicRootId = 0;
const PeerId _monoforumPeerId = 0;
PeerData * const _migrated = nullptr; PeerData * const _migrated = nullptr;
const Type _type = Type::Photo; const Type _type = Type::Photo;

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "info/media/info_media_widget.h" #include "info/media/info_media_widget.h"
#include "history/history.h"
#include "info/media/info_media_inner_widget.h" #include "info/media/info_media_inner_widget.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -17,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "styles/style_info.h" #include "styles/style_info.h"
@ -70,6 +72,7 @@ Memento::Memento(not_null<Controller*> controller)
? controller->storiesPeer() ? controller->storiesPeer()
: controller->parentController()->session().user()), : controller->parentController()->session().user()),
controller->topic(), controller->topic(),
controller->sublist(),
controller->migratedPeerId(), controller->migratedPeerId(),
(controller->section().type() == Section::Type::Downloads (controller->section().type() == Section::Type::Downloads
? Type::File ? Type::File
@ -79,23 +82,31 @@ Memento::Memento(not_null<Controller*> controller)
} }
Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type) Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type)
: Memento(peer, nullptr, migratedPeerId, type) { : Memento(peer, nullptr, nullptr, migratedPeerId, type) {
} }
Memento::Memento(not_null<Data::ForumTopic*> topic, Type type) Memento::Memento(not_null<Data::ForumTopic*> topic, Type type)
: Memento(topic->channel(), topic, PeerId(), type) { : Memento(topic->channel(), topic, nullptr, PeerId(), type) {
}
Memento::Memento(not_null<Data::SavedSublist*> sublist, Type type)
: Memento(sublist->owningHistory()->peer, nullptr, sublist, PeerId(), type) {
} }
Memento::Memento( Memento::Memento(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Data::ForumTopic *topic, Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId, PeerId migratedPeerId,
Type type) Type type)
: ContentMemento(peer, topic, migratedPeerId) : ContentMemento(peer, topic, sublist, migratedPeerId)
, _type(type) { , _type(type) {
_searchState.query.type = type; _searchState.query.type = type;
_searchState.query.peerId = peer->id; _searchState.query.peerId = peer->id;
_searchState.query.topicRootId = topic ? topic->rootId() : 0; _searchState.query.topicRootId = topic ? topic->rootId() : MsgId();
_searchState.query.monoforumPeerId = sublist
? sublist->sublistPeer()->id
: PeerId();
_searchState.query.migratedPeerId = migratedPeerId; _searchState.query.migratedPeerId = migratedPeerId;
if (migratedPeerId) { if (migratedPeerId) {
_searchState.migratedList = Storage::SparseIdsList(); _searchState.migratedList = Storage::SparseIdsList();

View File

@ -35,6 +35,7 @@ public:
explicit Memento(not_null<Controller*> controller); explicit Memento(not_null<Controller*> controller);
Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type); Memento(not_null<PeerData*> peer, PeerId migratedPeerId, Type type);
Memento(not_null<Data::ForumTopic*> topic, Type type); Memento(not_null<Data::ForumTopic*> topic, Type type);
Memento(not_null<Data::SavedSublist*> sublist, Type type);
using SearchState = Api::DelayedSearchController::SavedState; using SearchState = Api::DelayedSearchController::SavedState;
@ -92,6 +93,7 @@ private:
Memento( Memento(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Data::ForumTopic *topic, Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId, PeerId migratedPeerId,
Type type); Type type);

View File

@ -26,7 +26,7 @@ Memento::Memento(not_null<Controller*> controller)
} }
Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId) Memento::Memento(not_null<PeerData*> peer, PeerId migratedPeerId)
: ContentMemento(peer, nullptr, migratedPeerId) { : ContentMemento(peer, nullptr, nullptr, migratedPeerId) {
} }
Section Memento::section() const { Section Memento::section() const {

View File

@ -678,7 +678,7 @@ void InnerWidget::restoreState(not_null<Memento*> memento) {
} }
Memento::Memento(not_null<PeerData*> peer) Memento::Memento(not_null<PeerData*> peer)
: ContentMemento(peer, nullptr, PeerId()) { : ContentMemento(peer, nullptr, nullptr, PeerId()) {
} }
Section Memento::section() const { Section Memento::section() const {

View File

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_saved_sublist.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "api/api_peer_photo.h" #include "api/api_peer_photo.h"
@ -46,6 +47,7 @@ InnerWidget::InnerWidget(
, _peer(_controller->key().peer()) , _peer(_controller->key().peer())
, _migrated(_controller->migrated()) , _migrated(_controller->migrated())
, _topic(_controller->key().topic()) , _topic(_controller->key().topic())
, _sublist(_controller->key().sublist())
, _content(setupContent(this, origin)) { , _content(setupContent(this, origin)) {
_content->heightValue( _content->heightValue(
) | rpl::start_with_next([this](int height) { ) | rpl::start_with_next([this](int height) {
@ -82,7 +84,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
AddDetails(result, _controller, _peer, _topic, origin); AddDetails(result, _controller, _peer, _topic, origin);
result->add(setupSharedMedia(result.data())); result->add(setupSharedMedia(result.data()));
if (_topic) { if (_topic || _sublist) {
return result; return result;
} }
{ {
@ -147,7 +149,8 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
content, content,
_controller, _controller,
_peer, _peer,
_topic ? _topic->rootId() : 0, _topic ? _topic->rootId() : MsgId(),
_sublist ? _sublist->sublistPeer()->id : PeerId(),
_migrated, _migrated,
type, type,
tracker); tracker);

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Data { namespace Data {
class ForumTopic; class ForumTopic;
class SavedSublist;
class PhotoMedia; class PhotoMedia;
} // namespace Data } // namespace Data
@ -74,6 +75,7 @@ private:
const not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
PeerData * const _migrated = nullptr; PeerData * const _migrated = nullptr;
Data::ForumTopic * const _topic = nullptr; Data::ForumTopic * const _topic = nullptr;
Data::SavedSublist * const _sublist = nullptr;
PeerData *_reactionGroup = nullptr; PeerData *_reactionGroup = nullptr;

View File

@ -543,6 +543,7 @@ rpl::producer<int> KickedCountValue(not_null<ChannelData*> channel) {
rpl::producer<int> SharedMediaCountValue( rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated, PeerData *migrated,
Storage::SharedMediaType type) { Storage::SharedMediaType type) {
auto aroundId = 0; auto aroundId = 0;
@ -553,6 +554,7 @@ rpl::producer<int> SharedMediaCountValue(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
peer->id, peer->id,
topicRootId, topicRootId,
monoforumPeerId,
migrated ? migrated->id : 0, migrated ? migrated->id : 0,
aroundId), aroundId),
type), type),

View File

@ -113,6 +113,7 @@ struct LinkWithUrl {
[[nodiscard]] rpl::producer<int> SharedMediaCountValue( [[nodiscard]] rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated, PeerData *migrated,
Storage::SharedMediaType type); Storage::SharedMediaType type);
[[nodiscard]] rpl::producer<int> CommonGroupsCountValue( [[nodiscard]] rpl::producer<int> CommonGroupsCountValue(

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/profile/info_profile_widget.h" #include "info/profile/info_profile_widget.h"
#include "dialogs/ui/dialogs_stories_content.h" #include "dialogs/ui/dialogs_stories_content.h"
#include "history/history.h"
#include "info/profile/info_profile_inner_widget.h" #include "info/profile/info_profile_inner_widget.h"
#include "info/profile/info_profile_members.h" #include "info/profile/info_profile_members.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
@ -15,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_peer.h" #include "data/data_peer.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "info/info_controller.h" #include "info/info_controller.h"
@ -25,6 +27,7 @@ Memento::Memento(not_null<Controller*> controller)
: Memento( : Memento(
controller->peer(), controller->peer(),
controller->topic(), controller->topic(),
controller->sublist(),
controller->migratedPeerId(), controller->migratedPeerId(),
{ v::null }) { { v::null }) {
} }
@ -33,20 +36,25 @@ Memento::Memento(
not_null<PeerData*> peer, not_null<PeerData*> peer,
PeerId migratedPeerId, PeerId migratedPeerId,
Origin origin) Origin origin)
: Memento(peer, nullptr, migratedPeerId, origin) { : Memento(peer, nullptr, nullptr, migratedPeerId, origin) {
} }
Memento::Memento( Memento::Memento(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Data::ForumTopic *topic, Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId, PeerId migratedPeerId,
Origin origin) Origin origin)
: ContentMemento(peer, topic, migratedPeerId) : ContentMemento(peer, topic, sublist, migratedPeerId)
, _origin(origin) { , _origin(origin) {
} }
Memento::Memento(not_null<Data::ForumTopic*> topic) Memento::Memento(not_null<Data::ForumTopic*> topic)
: ContentMemento(topic->channel(), topic, 0) { : ContentMemento(topic->channel(), topic, nullptr, 0) {
}
Memento::Memento(not_null<Data::SavedSublist*> sublist)
: ContentMemento(sublist->owningHistory()->peer, nullptr, sublist, 0) {
} }
Section Memento::section() const { Section Memento::section() const {

View File

@ -35,6 +35,7 @@ public:
PeerId migratedPeerId, PeerId migratedPeerId,
Origin origin = { v::null }); Origin origin = { v::null });
explicit Memento(not_null<Data::ForumTopic*> topic); explicit Memento(not_null<Data::ForumTopic*> topic);
explicit Memento(not_null<Data::SavedSublist*> sublist);
object_ptr<ContentWidget> createWidget( object_ptr<ContentWidget> createWidget(
QWidget *parent, QWidget *parent,
@ -56,6 +57,7 @@ private:
Memento( Memento(
not_null<PeerData*> peer, not_null<PeerData*> peer,
Data::ForumTopic *topic, Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId, PeerId migratedPeerId,
Origin origin); Origin origin);

View File

@ -188,7 +188,7 @@ std::shared_ptr<Main::SessionShow> InnerWidget::peerListUiShow() {
} }
Memento::Memento(not_null<PeerData*> peer) Memento::Memento(not_null<PeerData*> peer)
: ContentMemento(peer, nullptr, PeerId()) { : ContentMemento(peer, nullptr, nullptr, PeerId()) {
} }
Section Memento::section() const { Section Memento::section() const {

View File

@ -29,7 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Info::Saved { namespace Info::Saved {
SublistsMemento::SublistsMemento(not_null<Main::Session*> session) SublistsMemento::SublistsMemento(not_null<Main::Session*> session)
: ContentMemento(session->user(), nullptr, PeerId()) { : ContentMemento(session->user(), nullptr, nullptr, PeerId()) {
} }
Section SublistsMemento::section() const { Section SublistsMemento::section() const {
@ -113,6 +113,7 @@ void SublistsWidget::setupOtherTypes() {
controller(), controller(),
peer, peer,
MsgId(), // topicRootId MsgId(), // topicRootId
PeerId(), // monoforumPeerId
nullptr, // migrated nullptr, // migrated
buttonType, buttonType,
tracker); tracker);

View File

@ -438,7 +438,7 @@ std::shared_ptr<Main::SessionShow> InnerWidget::peerListUiShow() {
} }
Memento::Memento(not_null<PeerData*> peer) Memento::Memento(not_null<PeerData*> peer)
: ContentMemento(peer, nullptr, PeerId()) { : ContentMemento(peer, nullptr, nullptr, PeerId()) {
} }
Section Memento::section() const { Section Memento::section() const {

View File

@ -347,9 +347,9 @@ bool Result::onChoose(Layout::ItemBase *layout) {
Media::View::OpenRequest Result::openRequest() { Media::View::OpenRequest Result::openRequest() {
using namespace Media::View; using namespace Media::View;
if (_document) { if (_document) {
return OpenRequest(nullptr, _document, nullptr, MsgId()); return OpenRequest(nullptr, _document, nullptr, MsgId(), PeerId());
} else if (_photo) { } else if (_photo) {
return OpenRequest(nullptr, _photo, nullptr, MsgId()); return OpenRequest(nullptr, _photo, nullptr, MsgId(), PeerId());
} }
return {}; return {};
} }

View File

@ -894,6 +894,7 @@ void Instance::show(
: nullptr; : nullptr;
const auto item = (HistoryItem*)nullptr; const auto item = (HistoryItem*)nullptr;
const auto topicRootId = MsgId(0); const auto topicRootId = MsgId(0);
const auto monoforumPeerId = PeerId(0);
if (event.context.startsWith("-photo")) { if (event.context.startsWith("-photo")) {
const auto id = event.context.mid(6).toULongLong(); const auto id = event.context.mid(6).toULongLong();
const auto photo = _shownSession->data().photo(id); const auto photo = _shownSession->data().photo(id);
@ -902,7 +903,8 @@ void Instance::show(
controller, controller,
photo, photo,
item, item,
topicRootId topicRootId,
monoforumPeerId
}); });
} }
} else if (event.context.startsWith("-video")) { } else if (event.context.startsWith("-video")) {
@ -913,7 +915,8 @@ void Instance::show(
controller, controller,
video, video,
item, item,
topicRootId topicRootId,
monoforumPeerId
}); });
} }
} }

View File

@ -40,7 +40,7 @@ QByteArray SessionSettings::serialize() const {
+ sizeof(qint32) * 11 + sizeof(qint32) * 11
+ (_mutePeriods.size() * sizeof(quint64)) + (_mutePeriods.size() * sizeof(quint64))
+ sizeof(qint32) * 2 + sizeof(qint32) * 2
+ _hiddenPinnedMessages.size() * (sizeof(quint64) * 3) + _hiddenPinnedMessages.size() * (sizeof(quint64) * 4)
+ sizeof(qint32) + sizeof(qint32)
+ _groupEmojiSectionHidden.size() * sizeof(quint64) + _groupEmojiSectionHidden.size() * sizeof(quint64)
+ sizeof(qint32) * 2; + sizeof(qint32) * 2;
@ -68,32 +68,33 @@ QByteArray SessionSettings::serialize() const {
<< qint32(_archiveInMainMenu.current() ? 1 : 0) << qint32(_archiveInMainMenu.current() ? 1 : 0)
<< qint32(_skipArchiveInSearch.current() ? 1 : 0) << qint32(_skipArchiveInSearch.current() ? 1 : 0)
<< qint32(0) // old _mediaLastPlaybackPosition.size()); << qint32(0) // old _mediaLastPlaybackPosition.size());
<< qint32(0) // very old _hiddenPinnedMessages.size()); << qint32(0) // very very old _hiddenPinnedMessages.size());
<< qint32(_dialogsFiltersEnabled ? 1 : 0) << qint32(_dialogsFiltersEnabled ? 1 : 0)
<< qint32(_supportAllSilent ? 1 : 0) << qint32(_supportAllSilent ? 1 : 0)
<< qint32(_photoEditorHintShowsCount) << qint32(_photoEditorHintShowsCount)
<< qint32(0) // old _hiddenPinnedMessages.size()); << qint32(0) // very old _hiddenPinnedMessages.size());
<< qint32(_mutePeriods.size()); << qint32(_mutePeriods.size());
for (const auto &period : _mutePeriods) { for (const auto &period : _mutePeriods) {
stream << quint64(period); stream << quint64(period);
} }
stream stream
<< qint32(0) // old _skipPremiumStickersSet << qint32(0) // old _skipPremiumStickersSet
<< qint32(_hiddenPinnedMessages.size()); << qint32(0) // old _hiddenPinnedMessages.size());
for (const auto &[key, value] : _hiddenPinnedMessages) {
stream
<< SerializePeerId(key.peerId)
<< qint64(key.topicRootId.bare)
<< qint64(value.bare);
}
stream
<< qint32(_groupEmojiSectionHidden.size()); << qint32(_groupEmojiSectionHidden.size());
for (const auto &peerId : _groupEmojiSectionHidden) { for (const auto &peerId : _groupEmojiSectionHidden) {
stream << SerializePeerId(peerId); stream << SerializePeerId(peerId);
} }
stream stream
<< qint32(_lastNonPremiumLimitDownload) << qint32(_lastNonPremiumLimitDownload)
<< qint32(_lastNonPremiumLimitUpload); << qint32(_lastNonPremiumLimitUpload)
<< qint32(_hiddenPinnedMessages.size());
for (const auto &[key, value] : _hiddenPinnedMessages) {
stream
<< SerializePeerId(key.peerId)
<< qint64(key.topicRootId.bare)
<< SerializePeerId(key.monoforumPeerId)
<< qint64(value.bare);
}
} }
Ensures(result.size() == size); Ensures(result.size() == size);
@ -401,6 +402,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
auto count = qint32(0); auto count = qint32(0);
stream >> count; stream >> count;
if (stream.status() == QDataStream::Ok) { if (stream.status() == QDataStream::Ok) {
// Legacy.
for (auto i = 0; i != count; ++i) { for (auto i = 0; i != count; ++i) {
auto keyPeerId = quint64(); auto keyPeerId = quint64();
auto keyTopicRootId = qint64(); auto keyTopicRootId = qint64();
@ -438,6 +440,33 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
>> lastNonPremiumLimitDownload >> lastNonPremiumLimitDownload
>> lastNonPremiumLimitUpload; >> lastNonPremiumLimitUpload;
} }
if (!stream.atEnd()) {
auto count = qint32(0);
stream >> count;
if (stream.status() == QDataStream::Ok) {
for (auto i = 0; i != count; ++i) {
auto keyPeerId = quint64();
auto keyTopicRootId = qint64();
auto keyMonoforumPeerId = quint64();
auto value = qint64();
stream
>> keyPeerId
>> keyTopicRootId
>> keyMonoforumPeerId
>> value;
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for SessionSettings::addFromSerialized()"));
return;
}
hiddenPinnedMessages.emplace(ThreadId{
DeserializePeerId(keyPeerId),
keyTopicRootId,
DeserializePeerId(keyMonoforumPeerId),
}, value);
}
}
}
if (stream.status() != QDataStream::Ok) { if (stream.status() != QDataStream::Ok) {
LOG(("App Error: " LOG(("App Error: "
"Bad data for SessionSettings::addFromSerialized()")); "Bad data for SessionSettings::addFromSerialized()"));
@ -595,16 +624,22 @@ rpl::producer<bool> SessionSettings::skipArchiveInSearchChanges() const {
MsgId SessionSettings::hiddenPinnedMessageId( MsgId SessionSettings::hiddenPinnedMessageId(
PeerId peerId, PeerId peerId,
MsgId topicRootId) const { MsgId topicRootId,
const auto i = _hiddenPinnedMessages.find({ peerId, topicRootId }); PeerId monoforumPeerId) const {
const auto i = _hiddenPinnedMessages.find({
peerId,
topicRootId,
monoforumPeerId,
});
return (i != end(_hiddenPinnedMessages)) ? i->second : 0; return (i != end(_hiddenPinnedMessages)) ? i->second : 0;
} }
void SessionSettings::setHiddenPinnedMessageId( void SessionSettings::setHiddenPinnedMessageId(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
MsgId msgId) { MsgId msgId) {
const auto id = ThreadId{ peerId, topicRootId }; const auto id = ThreadId{ peerId, topicRootId, monoforumPeerId };
if (msgId) { if (msgId) {
_hiddenPinnedMessages[id] = msgId; _hiddenPinnedMessages[id] = msgId;
} else { } else {

View File

@ -110,10 +110,12 @@ public:
[[nodiscard]] MsgId hiddenPinnedMessageId( [[nodiscard]] MsgId hiddenPinnedMessageId(
PeerId peerId, PeerId peerId,
MsgId topicRootId = 0) const; MsgId topicRootId = 0,
PeerId monoforumPeerId = 0) const;
void setHiddenPinnedMessageId( void setHiddenPinnedMessageId(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
MsgId msgId); MsgId msgId);
[[nodiscard]] bool dialogsFiltersEnabled() const { [[nodiscard]] bool dialogsFiltersEnabled() const {
@ -149,6 +151,7 @@ private:
struct ThreadId { struct ThreadId {
PeerId peerId; PeerId peerId;
MsgId topicRootId; MsgId topicRootId;
PeerId monoforumPeerId;
friend inline constexpr auto operator<=>( friend inline constexpr auto operator<=>(
ThreadId, ThreadId,

View File

@ -85,6 +85,7 @@ struct Instance::ShuffleData {
std::vector<UniversalMsgId> playedIds; std::vector<UniversalMsgId> playedIds;
History *history = nullptr; History *history = nullptr;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
History *migrated = nullptr; History *migrated = nullptr;
bool scheduled = false; bool scheduled = false;
int indexInPlayedIds = 0; int indexInPlayedIds = 0;
@ -247,6 +248,7 @@ void Instance::setHistory(
if (history) { if (history) {
data->history = history->migrateToOrMe(); data->history = history->migrateToOrMe();
data->topicRootId = 0; data->topicRootId = 0;
data->monoforumPeerId = 0;
data->migrated = data->history->migrateFrom(); data->migrated = data->history->migrateFrom();
setSession(data, &history->session()); setSession(data, &history->session());
} else { } else {
@ -349,6 +351,7 @@ bool Instance::validPlaylist(not_null<const Data*> data) const {
const auto inSameDomain = [](const Key &a, const Key &b) { const auto inSameDomain = [](const Key &a, const Key &b) {
return (a.peerId == b.peerId) return (a.peerId == b.peerId)
&& (a.topicRootId == b.topicRootId) && (a.topicRootId == b.topicRootId)
&& (a.monoforumPeerId == b.monoforumPeerId)
&& (a.migratedPeerId == b.migratedPeerId); && (a.migratedPeerId == b.migratedPeerId);
}; };
const auto countDistanceInData = [&](const Key &a, const Key &b) { const auto countDistanceInData = [&](const Key &a, const Key &b) {
@ -422,6 +425,7 @@ auto Instance::playlistKey(not_null<const Data*> data) const
(item->isScheduled() (item->isScheduled()
? SparseIdsMergedSlice::kScheduledTopicId ? SparseIdsMergedSlice::kScheduledTopicId
: data->topicRootId), : data->topicRootId),
data->monoforumPeerId,
data->migrated ? data->migrated->peer->id : 0, data->migrated ? data->migrated->peer->id : 0,
universalId); universalId);
} }
@ -479,6 +483,7 @@ auto Instance::playlistOtherKey(not_null<const Data*> data) const
return SliceKey( return SliceKey(
data->history->peer->id, data->history->peer->id,
data->topicRootId, data->topicRootId,
data->monoforumPeerId,
data->migrated ? data->migrated->peer->id : 0, data->migrated ? data->migrated->peer->id : 0,
(data->playlistSlice->skippedBefore() == 0 (data->playlistSlice->skippedBefore() == 0
? ServerMaxMsgId - 1 ? ServerMaxMsgId - 1
@ -905,6 +910,7 @@ void Instance::validateShuffleData(not_null<Data*> data) {
&& (key->topicRootId == SparseIdsMergedSlice::kScheduledTopicId); && (key->topicRootId == SparseIdsMergedSlice::kScheduledTopicId);
if (raw->history != data->history if (raw->history != data->history
|| raw->topicRootId != data->topicRootId || raw->topicRootId != data->topicRootId
|| raw->monoforumPeerId != data->monoforumPeerId
|| raw->migrated != data->migrated || raw->migrated != data->migrated
|| raw->scheduled != scheduled) { || raw->scheduled != scheduled) {
raw->history = data->history; raw->history = data->history;
@ -962,6 +968,7 @@ void Instance::validateShuffleData(not_null<Data*> data) {
SliceKey( SliceKey(
raw->history->peer->id, raw->history->peer->id,
raw->topicRootId, raw->topicRootId,
raw->monoforumPeerId,
raw->migrated ? raw->migrated->peer->id : 0, raw->migrated ? raw->migrated->peer->id : 0,
last), last),
data->overview), data->overview),

View File

@ -194,6 +194,7 @@ private:
rpl::event_stream<> playlistChanges; rpl::event_stream<> playlistChanges;
History *history = nullptr; History *history = nullptr;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
History *migrated = nullptr; History *migrated = nullptr;
Main::Session *session = nullptr; Main::Session *session = nullptr;
bool isPlaying = false; bool isPlaying = false;

View File

@ -30,11 +30,13 @@ public:
Window::SessionController *controller, Window::SessionController *controller,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
HistoryItem *item, HistoryItem *item,
MsgId topicRootId) MsgId topicRootId,
PeerId monoforumPeerId)
: _controller(controller) : _controller(controller)
, _photo(photo) , _photo(photo)
, _item(item) , _item(item)
, _topicRootId(topicRootId) { , _topicRootId(topicRootId)
, _monoforumPeerId(monoforumPeerId) {
} }
OpenRequest( OpenRequest(
Window::SessionController *controller, Window::SessionController *controller,
@ -50,12 +52,14 @@ public:
not_null<DocumentData*> document, not_null<DocumentData*> document,
HistoryItem *item, HistoryItem *item,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
bool continueStreaming = false, bool continueStreaming = false,
crl::time startTime = 0) crl::time startTime = 0)
: _controller(controller) : _controller(controller)
, _document(document) , _document(document)
, _item(item) , _item(item)
, _topicRootId(topicRootId) , _topicRootId(topicRootId)
, _monoforumPeerId(monoforumPeerId)
, _continueStreaming(continueStreaming) , _continueStreaming(continueStreaming)
, _startTime(startTime) { , _startTime(startTime) {
} }
@ -92,6 +96,9 @@ public:
[[nodiscard]] MsgId topicRootId() const { [[nodiscard]] MsgId topicRootId() const {
return _topicRootId; return _topicRootId;
} }
[[nodiscard]] PeerId monoforumPeerId() const {
return _monoforumPeerId;
}
[[nodiscard]] DocumentData *document() const { [[nodiscard]] DocumentData *document() const {
return _document; return _document;
@ -129,6 +136,7 @@ private:
PeerData *_peer = nullptr; PeerData *_peer = nullptr;
HistoryItem *_item = nullptr; HistoryItem *_item = nullptr;
MsgId _topicRootId = 0; MsgId _topicRootId = 0;
PeerId _monoforumPeerId = 0;
std::optional<Data::CloudTheme> _cloudTheme = std::nullopt; std::optional<Data::CloudTheme> _cloudTheme = std::nullopt;
bool _continueStreaming = false; bool _continueStreaming = false;
crl::time _startTime = 0; crl::time _startTime = 0;

View File

@ -366,6 +366,7 @@ struct OverlayWidget::PipWrap {
struct OverlayWidget::ItemContext { struct OverlayWidget::ItemContext {
not_null<HistoryItem*> item; not_null<HistoryItem*> item;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
}; };
struct OverlayWidget::StoriesContext { struct OverlayWidget::StoriesContext {
@ -2675,7 +2676,8 @@ void OverlayWidget::handleDocumentClick() {
findWindow(), findWindow(),
_document, _document,
_message, _message,
_topicRootId); _topicRootId,
_monoforumPeerId);
if (_document && _document->loading() && !_radial.animating()) { if (_document && _document->loading() && !_radial.animating()) {
_radial.start(_documentMedia->progress()); _radial.start(_documentMedia->progress());
} }
@ -2921,13 +2923,22 @@ void OverlayWidget::showMediaOverview() {
const auto topic = _topicRootId const auto topic = _topicRootId
? _history->peer->forumTopicFor(_topicRootId) ? _history->peer->forumTopicFor(_topicRootId)
: nullptr; : nullptr;
const auto sublist = _monoforumPeerId
? _history->peer->monoforumSublistFor(_monoforumPeerId)
: nullptr;
if (_topicRootId && !topic) { if (_topicRootId && !topic) {
return; return;
} else if (_monoforumPeerId && !sublist) {
return;
} }
window->showSection(_topicRootId window->showSection(_topicRootId
? std::make_shared<Info::Memento>( ? std::make_shared<Info::Memento>(
topic, topic,
Info::Section(*overviewType)) Info::Section(*overviewType))
: _monoforumPeerId
? std::make_shared<Info::Memento>(
sublist,
Info::Section(*overviewType))
: std::make_shared<Info::Memento>( : std::make_shared<Info::Memento>(
_history->peer, _history->peer,
Info::Section(*overviewType))); Info::Section(*overviewType)));
@ -3017,6 +3028,7 @@ auto OverlayWidget::sharedMediaKey() const -> std::optional<SharedMediaKey> {
return SharedMediaKey{ return SharedMediaKey{
_history->peer->id, _history->peer->id,
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
_migrated ? _migrated->peer->id : 0, _migrated ? _migrated->peer->id : 0,
SharedMediaType::ChatPhoto, SharedMediaType::ChatPhoto,
_photo _photo
@ -3032,6 +3044,7 @@ auto OverlayWidget::sharedMediaKey() const -> std::optional<SharedMediaKey> {
(isScheduled (isScheduled
? SparseIdsMergedSlice::kScheduledTopicId ? SparseIdsMergedSlice::kScheduledTopicId
: _topicRootId), : _topicRootId),
(isScheduled ? PeerId() : _monoforumPeerId),
_migrated ? _migrated->peer->id : 0, _migrated ? _migrated->peer->id : 0,
type, type,
(_message->history() == _history (_message->history() == _history
@ -4609,6 +4622,7 @@ void OverlayWidget::switchToPip() {
const auto document = _document; const auto document = _document;
const auto messageId = _message ? _message->fullId() : FullMsgId(); const auto messageId = _message ? _message->fullId() : FullMsgId();
const auto topicRootId = _topicRootId; const auto topicRootId = _topicRootId;
const auto monoforumPeerId = _monoforumPeerId;
const auto closeAndContinue = [=] { const auto closeAndContinue = [=] {
_showAsPip = false; _showAsPip = false;
show(OpenRequest( show(OpenRequest(
@ -4616,6 +4630,7 @@ void OverlayWidget::switchToPip() {
document, document,
document->owner().message(messageId), document->owner().message(messageId),
topicRootId, topicRootId,
monoforumPeerId,
true)); true));
}; };
_showAsPip = true; _showAsPip = true;
@ -5699,9 +5714,9 @@ OverlayWidget::Entity OverlayWidget::entityForCollage(int index) const {
return { v::null, nullptr }; return { v::null, nullptr };
} }
if (const auto document = std::get_if<DocumentData*>(&items[index])) { if (const auto document = std::get_if<DocumentData*>(&items[index])) {
return { *document, _message, _topicRootId }; return { *document, _message, _topicRootId, _monoforumPeerId };
} else if (const auto photo = std::get_if<PhotoData*>(&items[index])) { } else if (const auto photo = std::get_if<PhotoData*>(&items[index])) {
return { *photo, _message, _topicRootId }; return { *photo, _message, _topicRootId, _monoforumPeerId };
} }
return { v::null, nullptr }; return { v::null, nullptr };
} }
@ -5712,12 +5727,12 @@ OverlayWidget::Entity OverlayWidget::entityForItemId(const FullMsgId &itemId) co
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 photo = media->photo()) { if (const auto photo = media->photo()) {
return { photo, item, _topicRootId }; return { photo, item, _topicRootId, _monoforumPeerId };
} else if (const auto document = media->document()) { } else if (const auto document = media->document()) {
return { document, item, _topicRootId }; return { document, item, _topicRootId, _monoforumPeerId };
} }
} }
return { v::null, item, _topicRootId }; return { v::null, item, _topicRootId, _monoforumPeerId };
} }
return { v::null, nullptr }; return { v::null, nullptr };
} }
@ -5744,6 +5759,9 @@ void OverlayWidget::setContext(
_history = _message->history(); _history = _message->history();
_peer = _history->peer; _peer = _history->peer;
_topicRootId = _peer->isForum() ? item->topicRootId : MsgId(); _topicRootId = _peer->isForum() ? item->topicRootId : MsgId();
_monoforumPeerId = _peer->amMonoforumAdmin()
? item->monoforumPeerId
: PeerId();
setStoriesPeer(nullptr); setStoriesPeer(nullptr);
} else if (const auto peer = std::get_if<not_null<PeerData*>>(&context)) { } else if (const auto peer = std::get_if<not_null<PeerData*>>(&context)) {
_peer = *peer; _peer = *peer;

View File

@ -170,6 +170,7 @@ private:
not_null<DocumentData*>> data; not_null<DocumentData*>> data;
HistoryItem *item = nullptr; HistoryItem *item = nullptr;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
}; };
enum class SavePhotoVideo { enum class SavePhotoVideo {
None, None,
@ -674,6 +675,7 @@ private:
History *_migrated = nullptr; History *_migrated = nullptr;
History *_history = nullptr; // if conversation photos or files overview History *_history = nullptr; // if conversation photos or files overview
MsgId _topicRootId = 0; MsgId _topicRootId = 0;
PeerId _monoforumPeerId = 0;
PeerData *_peer = nullptr; PeerData *_peer = nullptr;
UserData *_user = nullptr; // if user profile photos overview UserData *_user = nullptr; // if user profile photos overview

View File

@ -16,6 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/sandbox.h" #include "core/sandbox.h"
#include "core/core_settings.h" #include "core/core_settings.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "data/data_peer.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -156,6 +158,7 @@ public:
void clearAll(); void clearAll();
void clearFromItem(not_null<HistoryItem*> item); void clearFromItem(not_null<HistoryItem*> item);
void clearFromTopic(not_null<Data::ForumTopic*> topic); void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history); void clearFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session); void clearFromSession(not_null<Main::Session*> session);
void clearNotification(NotificationId id); void clearNotification(NotificationId id);
@ -367,6 +370,8 @@ Manager::Private::Private(not_null<Manager*> manager)
.sessionId = dict.lookup_value("session").get_uint64(), .sessionId = dict.lookup_value("session").get_uint64(),
.peerId = PeerId(dict.lookup_value("peer").get_uint64()), .peerId = PeerId(dict.lookup_value("peer").get_uint64()),
.topicRootId = dict.lookup_value("topic").get_int64(), .topicRootId = dict.lookup_value("topic").get_int64(),
.monoforumPeerId = dict.lookup_value(
"monoforumpeer").get_uint64(),
}, },
.msgId = dict.lookup_value("msgid").get_int64(), .msgId = dict.lookup_value("msgid").get_int64(),
}; };
@ -531,6 +536,7 @@ void Manager::Private::showNotification(
.sessionId = peer->session().uniqueId(), .sessionId = peer->session().uniqueId(),
.peerId = peer->id, .peerId = peer->id,
.topicRootId = info.topicRootId, .topicRootId = info.topicRootId,
.monoforumPeerId = info.monoforumPeerId,
}; };
const auto notificationId = NotificationId{ const auto notificationId = NotificationId{
.contextId = key, .contextId = key,
@ -591,6 +597,10 @@ void Manager::Private::showNotification(
GLib::Variant::new_string("topic"), GLib::Variant::new_string("topic"),
GLib::Variant::new_variant( GLib::Variant::new_variant(
GLib::Variant::new_int64(info.topicRootId.bare))), GLib::Variant::new_int64(info.topicRootId.bare))),
GLib::Variant::new_dict_entry(
GLib::Variant::new_string("monoforumpeer"),
GLib::Variant::new_variant(
GLib::Variant::new_uint64(info.monoforumPeerId.value))),
GLib::Variant::new_dict_entry( GLib::Variant::new_dict_entry(
GLib::Variant::new_string("msgid"), GLib::Variant::new_string("msgid"),
GLib::Variant::new_variant( GLib::Variant::new_variant(
@ -809,6 +819,7 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
.sessionId = item->history()->session().uniqueId(), .sessionId = item->history()->session().uniqueId(),
.peerId = item->history()->peer->id, .peerId = item->history()->peer->id,
.topicRootId = item->topicRootId(), .topicRootId = item->topicRootId(),
.monoforumPeerId = item->sublistPeerId(),
}); });
if (i != _notifications.cend() if (i != _notifications.cend()
&& i->second.remove(item->id) && i->second.remove(item->id)
@ -825,6 +836,15 @@ void Manager::Private::clearFromTopic(not_null<Data::ForumTopic*> topic) {
}); });
} }
void Manager::Private::clearFromSublist(
not_null<Data::SavedSublist*> sublist) {
_notifications.remove(ContextId{
.sessionId = sublist->session().uniqueId(),
.peerId = sublist->owningHistory()->peer->id,
.monoforumPeerId = sublist->sublistPeer()->id,
});
}
void Manager::Private::clearFromHistory(not_null<History*> history) { void Manager::Private::clearFromHistory(not_null<History*> history) {
const auto sessionId = history->session().uniqueId(); const auto sessionId = history->session().uniqueId();
const auto peerId = history->peer->id; const auto peerId = history->peer->id;
@ -889,6 +909,10 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
_private->clearFromTopic(topic); _private->clearFromTopic(topic);
} }
void Manager::doClearFromSublist(not_null<Data::SavedSublist*> sublist) {
_private->clearFromSublist(sublist);
}
void Manager::doClearFromHistory(not_null<History*> history) { void Manager::doClearFromHistory(not_null<History*> history) {
_private->clearFromHistory(history); _private->clearFromHistory(history);
} }

View File

@ -24,6 +24,7 @@ protected:
void doClearAllFast() override; void doClearAllFast() override;
void doClearFromItem(not_null<HistoryItem*> item) override; void doClearFromItem(not_null<HistoryItem*> item) override;
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override; void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
void doClearFromSublist(not_null<Data::SavedSublist*> sublist) override;
void doClearFromHistory(not_null<History*> history) override; void doClearFromHistory(not_null<History*> history) override;
void doClearFromSession(not_null<Main::Session*> session) override; void doClearFromSession(not_null<Main::Session*> session) override;
bool doSkipToast() const override; bool doSkipToast() const override;

View File

@ -25,6 +25,7 @@ protected:
void doClearAllFast() override; void doClearAllFast() override;
void doClearFromItem(not_null<HistoryItem*> item) override; void doClearFromItem(not_null<HistoryItem*> item) override;
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override; void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
void doClearFromSublist(not_null<Data::SavedSublist*> sublist) override;
void doClearFromHistory(not_null<History*> history) override; void doClearFromHistory(not_null<History*> history) override;
void doClearFromSession(not_null<Main::Session*> session) override; void doClearFromSession(not_null<Main::Session*> session) override;
QString accountNameSeparator() override; QString accountNameSeparator() override;

View File

@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/platform/mac/base_utilities_mac.h" #include "base/platform/mac/base_utilities_mac.h"
#include "base/random.h" #include "base/random.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "data/data_peer.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "ui/empty_userpic.h" #include "ui/empty_userpic.h"
@ -131,6 +133,12 @@ using Manager = Platform::Notifications::Manager;
return; return;
} }
const auto notificationTopicRootId = [topicObject longLongValue]; const auto notificationTopicRootId = [topicObject longLongValue];
NSNumber *monoforumPeerObject = [notificationUserInfo objectForKey:@"monoforumpeer"];
if (!monoforumPeerObject) {
LOG(("App Error: A notification with unknown monoforum peer was received"));
return;
}
const auto notificationMonoforumPeerId = [monoforumPeerObject unsignedLongLongValue];
NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"]; NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"];
const auto notificationMsgId = msgObject ? [msgObject longLongValue] : 0LL; const auto notificationMsgId = msgObject ? [msgObject longLongValue] : 0LL;
@ -140,6 +148,7 @@ using Manager = Platform::Notifications::Manager;
.sessionId = notificationSessionId, .sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId), .peerId = PeerId(notificationPeerId),
.topicRootId = MsgId(notificationTopicRootId), .topicRootId = MsgId(notificationTopicRootId),
.monoforumPeerId = PeerId(notificationMonoforumPeerId),
}, },
.msgId = notificationMsgId, .msgId = notificationMsgId,
}; };
@ -210,6 +219,7 @@ public:
void clearAll(); void clearAll();
void clearFromItem(not_null<HistoryItem*> item); void clearFromItem(not_null<HistoryItem*> item);
void clearFromTopic(not_null<Data::ForumTopic*> topic); void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history); void clearFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session); void clearFromSession(not_null<Main::Session*> session);
void updateDelegate(); void updateDelegate();
@ -237,6 +247,9 @@ private:
struct ClearFromTopic { struct ClearFromTopic {
ContextId contextId; ContextId contextId;
}; };
struct ClearFromSublist {
ContextId contextId;
}
struct ClearFromHistory { struct ClearFromHistory {
ContextId partialContextId; ContextId partialContextId;
}; };
@ -250,6 +263,7 @@ private:
using ClearTask = std::variant< using ClearTask = std::variant<
ClearFromItem, ClearFromItem,
ClearFromTopic, ClearFromTopic,
ClearFromSublist,
ClearFromHistory, ClearFromHistory,
ClearFromSession, ClearFromSession,
ClearAll, ClearAll,
@ -311,6 +325,8 @@ void Manager::Private::showNotification(
@"peer", @"peer",
[NSNumber numberWithLongLong:info.topicRootId.bare], [NSNumber numberWithLongLong:info.topicRootId.bare],
@"topic", @"topic",
[NSNumber numberWithUnsignedLongLong:info.monoforumPeerId.value],
@"monoforumpeer",
[NSNumber numberWithLongLong:info.itemId.bare], [NSNumber numberWithLongLong:info.itemId.bare],
@"msgid", @"msgid",
[NSNumber numberWithUnsignedLongLong:_managerId], [NSNumber numberWithUnsignedLongLong:_managerId],
@ -351,6 +367,7 @@ void Manager::Private::clearingThreadLoop() {
auto clearAll = false; auto clearAll = false;
auto clearFromItems = base::flat_set<NotificationId>(); auto clearFromItems = base::flat_set<NotificationId>();
auto clearFromTopics = base::flat_set<ContextId>(); auto clearFromTopics = base::flat_set<ContextId>();
auto clearFromSublists = base::flat_set<ContextId>();
auto clearFromHistories = base::flat_set<ContextId>(); auto clearFromHistories = base::flat_set<ContextId>();
auto clearFromSessions = base::flat_set<uint64>(); auto clearFromSessions = base::flat_set<uint64>();
{ {
@ -368,6 +385,8 @@ void Manager::Private::clearingThreadLoop() {
clearFromItems.emplace(value.id); clearFromItems.emplace(value.id);
}, [&](const ClearFromTopic &value) { }, [&](const ClearFromTopic &value) {
clearFromTopics.emplace(value.contextId); clearFromTopics.emplace(value.contextId);
}, [&](const ClearFromSublist &value) {
clearFromSublists.emplace(value.contextId);
}, [&](const ClearFromHistory &value) { }, [&](const ClearFromHistory &value) {
clearFromHistories.emplace(value.partialContextId); clearFromHistories.emplace(value.partialContextId);
}, [&](const ClearFromSession &value) { }, [&](const ClearFromSession &value) {
@ -395,21 +414,35 @@ void Manager::Private::clearingThreadLoop() {
return true; return true;
} }
const auto notificationTopicRootId = [topicObject longLongValue]; const auto notificationTopicRootId = [topicObject longLongValue];
NSNumber *monoforumPeerObject = [notificationUserInfo objectForKey:@"monoforumpeer"];
if (!monoforumPeerObject) {
return true;
}
const auto notificationMonoforumPeerId = [monoforumPeerObject unsignedLongLongValue];
NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"]; NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"];
const auto msgId = msgObject ? [msgObject longLongValue] : 0LL; const auto msgId = msgObject ? [msgObject longLongValue] : 0LL;
const auto partialContextId = ContextId{ const auto partialContextId = ContextId{
.sessionId = notificationSessionId, .sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId), .peerId = PeerId(notificationPeerId),
}; };
const auto contextId = ContextId{ const auto contextId = notificationTopicRootId
? ContextId{
.sessionId = notificationSessionId, .sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId), .peerId = PeerId(notificationPeerId),
.topicRootId = MsgId(notificationTopicRootId), .topicRootId = MsgId(notificationTopicRootId),
}; }
: notificationMonoforumPeerId
? ContextId{
.sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId),
.monoforumPeerId = PeerId(notificationMonoforumPeerId),
}
: partialContextId;
const auto id = NotificationId{ contextId, MsgId(msgId) }; const auto id = NotificationId{ contextId, MsgId(msgId) };
return clearFromSessions.contains(notificationSessionId) return clearFromSessions.contains(notificationSessionId)
|| clearFromHistories.contains(partialContextId) || clearFromHistories.contains(partialContextId)
|| clearFromTopics.contains(contextId) || clearFromTopics.contains(contextId)
|| clearFromSublists.contains(contextId)
|| (msgId && clearFromItems.contains(id)); || (msgId && clearFromItems.contains(id));
}; };
@ -450,6 +483,7 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
.sessionId = item->history()->session().uniqueId(), .sessionId = item->history()->session().uniqueId(),
.peerId = item->history()->peer->id, .peerId = item->history()->peer->id,
.topicRootId = item->topicRootId(), .topicRootId = item->topicRootId(),
.monoforumPeerId = item->sublistPeerId(),
}, item->id }); }, item->id });
} }
@ -461,6 +495,15 @@ void Manager::Private::clearFromTopic(not_null<Data::ForumTopic*> topic) {
} }); } });
} }
void Manager::Private::clearFromSublist(
not_null<Data::SavedSublist*> sublist) {
putClearTask(ClearFromSublist{ ContextId{
.sessionId = sublist->session().uniqueId(),
.peerId = sublist->owningHistory()->peer->id,
.monoforumPeerId = sublist->sublistPeer()->id,
} });
}
void Manager::Private::clearFromHistory(not_null<History*> history) { void Manager::Private::clearFromHistory(not_null<History*> history) {
putClearTask(ClearFromHistory{ ContextId{ putClearTask(ClearFromHistory{ ContextId{
.sessionId = history->session().uniqueId(), .sessionId = history->session().uniqueId(),
@ -511,6 +554,10 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
_private->clearFromTopic(topic); _private->clearFromTopic(topic);
} }
void Manager::doClearFromSublist(not_null<Data::SavedSublist*> sublist) {
_private->clearFromSublist(sublist);
}
void Manager::doClearFromHistory(not_null<History*> history) { void Manager::doClearFromHistory(not_null<History*> history) {
_private->clearFromHistory(history); _private->clearFromHistory(history);
} }

View File

@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/win/windows_dlls.h" #include "platform/win/windows_dlls.h"
#include "platform/win/specific_win.h" #include "platform/win/specific_win.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "data/data_peer.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "core/application.h" #include "core/application.h"
@ -433,6 +435,7 @@ public:
void clearAll(); void clearAll();
void clearFromItem(not_null<HistoryItem*> item); void clearFromItem(not_null<HistoryItem*> item);
void clearFromTopic(not_null<Data::ForumTopic*> topic); void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history); void clearFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session); void clearFromSession(not_null<Main::Session*> session);
void beforeNotificationActivated(NotificationId id); void beforeNotificationActivated(NotificationId id);
@ -508,6 +511,7 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
.sessionId = item->history()->session().uniqueId(), .sessionId = item->history()->session().uniqueId(),
.peerId = item->history()->peer->id, .peerId = item->history()->peer->id,
.topicRootId = item->topicRootId(), .topicRootId = item->topicRootId(),
.monoforumPeerId = item->sublistPeerId(),
}); });
if (i == _notifications.cend()) { if (i == _notifications.cend()) {
return; return;
@ -544,6 +548,27 @@ void Manager::Private::clearFromTopic(not_null<Data::ForumTopic*> topic) {
} }
} }
void Manager::Private::clearFromSublist(
not_null<Data::SavedSublist*> sublist) {
if (!_notifier) {
return;
}
const auto i = _notifications.find(ContextId{
.sessionId = sublist->session().uniqueId(),
.peerId = sublist->owningHistory()->peer->id,
.monoforumPeerId = sublist->sublistPeer()->id,
});
if (i != _notifications.cend()) {
const auto temp = base::take(i->second);
_notifications.erase(i);
for (const auto &[msgId, notification] : temp) {
tryHide(notification);
}
}
}
void Manager::Private::clearFromHistory(not_null<History*> history) { void Manager::Private::clearFromHistory(not_null<History*> history) {
if (!_notifier) { if (!_notifier) {
return; return;
@ -626,7 +651,9 @@ void Manager::Private::handleActivation(const ToastActivation &activation) {
.contextId = ContextId{ .contextId = ContextId{
.sessionId = parsed.value("session").toULongLong(), .sessionId = parsed.value("session").toULongLong(),
.peerId = PeerId(parsed.value("peer").toULongLong()), .peerId = PeerId(parsed.value("peer").toULongLong()),
.topicRootId = MsgId(parsed.value("topic").toLongLong()) .topicRootId = MsgId(parsed.value("topic").toLongLong()),
.monoforumPeerId = PeerId(
parsed.value("monoforumpeer").toULongLong()),
}, },
.msgId = MsgId(parsed.value("msg").toLongLong()), .msgId = MsgId(parsed.value("msg").toLongLong()),
}; };
@ -694,16 +721,18 @@ bool Manager::Private::showNotificationInTryCatch(
.sessionId = peer->session().uniqueId(), .sessionId = peer->session().uniqueId(),
.peerId = peer->id, .peerId = peer->id,
.topicRootId = info.topicRootId, .topicRootId = info.topicRootId,
.monoforumPeerId = info.monoforumPeerId,
}; };
const auto notificationId = NotificationId{ const auto notificationId = NotificationId{
.contextId = key, .contextId = key,
.msgId = info.itemId, .msgId = info.itemId,
}; };
const auto idString = u"pid=%1&session=%2&peer=%3&topic=%4&msg=%5"_q const auto idString = u"pid=%1&session=%2&peer=%3&topic=%4&monoforumpeer=%5&msg=%6"_q
.arg(GetCurrentProcessId()) .arg(GetCurrentProcessId())
.arg(key.sessionId) .arg(key.sessionId)
.arg(key.peerId.value) .arg(key.peerId.value)
.arg(info.topicRootId.bare) .arg(info.topicRootId.bare)
.arg(info.monoforumPeerId.value)
.arg(info.itemId.bare); .arg(info.itemId.bare);
const auto modern = Platform::IsWindows10OrGreater(); const auto modern = Platform::IsWindows10OrGreater();
@ -897,6 +926,10 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
_private->clearFromTopic(topic); _private->clearFromTopic(topic);
} }
void Manager::doClearFromSublist(not_null<Data::SavedSublist*> sublist) {
_private->clearFromSublist(sublist);
}
void Manager::doClearFromHistory(not_null<History*> history) { void Manager::doClearFromHistory(not_null<History*> history) {
_private->clearFromHistory(history); _private->clearFromHistory(history);
} }

View File

@ -31,6 +31,7 @@ protected:
void doClearAllFast() override; void doClearAllFast() override;
void doClearFromItem(not_null<HistoryItem*> item) override; void doClearFromItem(not_null<HistoryItem*> item) override;
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override; void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
void doClearFromSublist(not_null<Data::SavedSublist*> sublist) override;
void doClearFromHistory(not_null<History*> history) override; void doClearFromHistory(not_null<History*> history) override;
void doClearFromSession(not_null<Main::Session*> session) override; void doClearFromSession(not_null<Main::Session*> session) override;
void onBeforeNotificationActivated(NotificationId id) override; void onBeforeNotificationActivated(NotificationId id) override;

View File

@ -1084,6 +1084,7 @@ bool ReadSetting(
context.sessionSettings().setHiddenPinnedMessageId( context.sessionSettings().setHiddenPinnedMessageId(
DeserializePeerId(i.key()), DeserializePeerId(i.key()),
MsgId(0), // topicRootId MsgId(0), // topicRootId
PeerId(0), // monoforumPeerId
MsgId(i.value())); MsgId(i.value()));
} }
context.legacyRead = true; context.legacyRead = true;

View File

@ -27,6 +27,7 @@ auto SharedMedia::enforceLists(Key key)
return SharedMediaSliceUpdate( return SharedMediaSliceUpdate(
key.peerId, key.peerId,
key.topicRootId, key.topicRootId,
key.monoforumPeerId,
type, type,
update); update);
}) | rpl::start_to_stream(_sliceUpdated, _lifetime); }) | rpl::start_to_stream(_sliceUpdated, _lifetime);
@ -50,10 +51,20 @@ void SharedMedia::add(SharedMediaAddNew &&query) {
if (topicIt != end(_lists)) { if (topicIt != end(_lists)) {
addByIt(topicIt); addByIt(topicIt);
} }
const auto monoforumPeerIt = query.monoforumPeerId
? _lists.find({ query.peerId, MsgId(), query.monoforumPeerId })
: end(_lists);
if (monoforumPeerIt != end(_lists)) {
addByIt(monoforumPeerIt);
}
} }
void SharedMedia::add(SharedMediaAddExisting &&query) { void SharedMedia::add(SharedMediaAddExisting &&query) {
auto peerIt = enforceLists({ query.peerId, query.topicRootId }); auto peerIt = enforceLists({
query.peerId,
query.topicRootId,
query.monoforumPeerId,
});
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
auto type = static_cast<SharedMediaType>(index); auto type = static_cast<SharedMediaType>(index);
if (query.types.test(type)) { if (query.types.test(type)) {
@ -67,7 +78,11 @@ void SharedMedia::add(SharedMediaAddExisting &&query) {
void SharedMedia::add(SharedMediaAddSlice &&query) { void SharedMedia::add(SharedMediaAddSlice &&query) {
Expects(IsValidSharedMediaType(query.type)); Expects(IsValidSharedMediaType(query.type));
auto peerIt = enforceLists({ query.peerId, query.topicRootId }); auto peerIt = enforceLists({
query.peerId,
query.topicRootId,
query.monoforumPeerId,
});
auto index = static_cast<int>(query.type); auto index = static_cast<int>(query.type);
peerIt->second[index].addSlice( peerIt->second[index].addSlice(
std::move(query.messageIds), std::move(query.messageIds),
@ -90,11 +105,17 @@ void SharedMedia::remove(SharedMediaRemoveOne &&query) {
} }
void SharedMedia::remove(SharedMediaRemoveAll &&query) { void SharedMedia::remove(SharedMediaRemoveAll &&query) {
auto peerIt = _lists.lower_bound({ query.peerId, query.topicRootId }); auto peerIt = _lists.lower_bound({
query.peerId,
query.topicRootId,
query.monoforumPeerId,
});
while (peerIt != end(_lists) while (peerIt != end(_lists)
&& peerIt->first.peerId == query.peerId && peerIt->first.peerId == query.peerId
&& (!query.topicRootId && (!query.topicRootId
|| peerIt->first.topicRootId == query.topicRootId)) { || peerIt->first.topicRootId == query.topicRootId)
&& (!query.monoforumPeerId
|| peerIt->first.monoforumPeerId == query.monoforumPeerId)) {
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
auto type = static_cast<SharedMediaType>(index); auto type = static_cast<SharedMediaType>(index);
if (query.types.test(type)) { if (query.types.test(type)) {
@ -118,13 +139,17 @@ void SharedMedia::invalidate(SharedMediaInvalidateBottom &&query) {
} }
void SharedMedia::unload(SharedMediaUnloadThread &&query) { void SharedMedia::unload(SharedMediaUnloadThread &&query) {
_lists.erase({ query.peerId, query.topicRootId }); _lists.erase({ query.peerId, query.topicRootId, query.monoforumPeerId });
} }
rpl::producer<SharedMediaResult> SharedMedia::query(SharedMediaQuery &&query) const { rpl::producer<SharedMediaResult> SharedMedia::query(SharedMediaQuery &&query) const {
Expects(IsValidSharedMediaType(query.key.type)); Expects(IsValidSharedMediaType(query.key.type));
auto peerIt = _lists.find({ query.key.peerId, query.key.topicRootId }); auto peerIt = _lists.find({
query.key.peerId,
query.key.topicRootId,
query.key.monoforumPeerId,
});
if (peerIt != _lists.end()) { if (peerIt != _lists.end()) {
auto index = static_cast<int>(query.key.type); auto index = static_cast<int>(query.key.type);
return peerIt->second[index].query(SparseIdsListQuery( return peerIt->second[index].query(SparseIdsListQuery(
@ -141,7 +166,11 @@ rpl::producer<SharedMediaResult> SharedMedia::query(SharedMediaQuery &&query) co
SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const { SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const {
Expects(IsValidSharedMediaType(query.key.type)); Expects(IsValidSharedMediaType(query.key.type));
auto peerIt = _lists.find({ query.key.peerId, query.key.topicRootId }); auto peerIt = _lists.find({
query.key.peerId,
query.key.topicRootId,
query.key.monoforumPeerId,
});
if (peerIt != _lists.end()) { if (peerIt != _lists.end()) {
auto index = static_cast<int>(query.key.type); auto index = static_cast<int>(query.key.type);
return peerIt->second[index].snapshot(SparseIdsListQuery( return peerIt->second[index].snapshot(SparseIdsListQuery(
@ -155,7 +184,11 @@ SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const {
bool SharedMedia::empty(const SharedMediaKey &key) const { bool SharedMedia::empty(const SharedMediaKey &key) const {
Expects(IsValidSharedMediaType(key.type)); Expects(IsValidSharedMediaType(key.type));
auto peerIt = _lists.find({ key.peerId, key.topicRootId }); auto peerIt = _lists.find({
key.peerId,
key.topicRootId,
key.monoforumPeerId,
});
if (peerIt != _lists.end()) { if (peerIt != _lists.end()) {
auto index = static_cast<int>(key.type); auto index = static_cast<int>(key.type);
return peerIt->second[index].empty(); return peerIt->second[index].empty();

View File

@ -42,16 +42,19 @@ struct SharedMediaAddNew {
SharedMediaAddNew( SharedMediaAddNew(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaTypesMask types, SharedMediaTypesMask types,
MsgId messageId) MsgId messageId)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) , topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, messageId(messageId) , messageId(messageId)
, types(types) { , types(types) {
} }
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
MsgId messageId = 0; MsgId messageId = 0;
SharedMediaTypesMask types; SharedMediaTypesMask types;
@ -61,11 +64,13 @@ struct SharedMediaAddExisting {
SharedMediaAddExisting( SharedMediaAddExisting(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaTypesMask types, SharedMediaTypesMask types,
MsgId messageId, MsgId messageId,
MsgRange noSkipRange) MsgRange noSkipRange)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) , topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, messageId(messageId) , messageId(messageId)
, noSkipRange(noSkipRange) , noSkipRange(noSkipRange)
, types(types) { , types(types) {
@ -73,6 +78,7 @@ struct SharedMediaAddExisting {
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
MsgId messageId = 0; MsgId messageId = 0;
MsgRange noSkipRange; MsgRange noSkipRange;
SharedMediaTypesMask types; SharedMediaTypesMask types;
@ -83,12 +89,14 @@ struct SharedMediaAddSlice {
SharedMediaAddSlice( SharedMediaAddSlice(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type, SharedMediaType type,
std::vector<MsgId> &&messageIds, std::vector<MsgId> &&messageIds,
MsgRange noSkipRange, MsgRange noSkipRange,
std::optional<int> count = std::nullopt) std::optional<int> count = std::nullopt)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) , topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, messageIds(std::move(messageIds)) , messageIds(std::move(messageIds))
, noSkipRange(noSkipRange) , noSkipRange(noSkipRange)
, type(type) , type(type)
@ -97,6 +105,7 @@ struct SharedMediaAddSlice {
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
std::vector<MsgId> messageIds; std::vector<MsgId> messageIds;
MsgRange noSkipRange; MsgRange noSkipRange;
SharedMediaType type = SharedMediaType::kCount; SharedMediaType type = SharedMediaType::kCount;
@ -135,9 +144,18 @@ struct SharedMediaRemoveAll {
, topicRootId(topicRootId) , topicRootId(topicRootId)
, types(types) { , types(types) {
} }
SharedMediaRemoveAll(
PeerId peerId,
PeerId monoforumPeerId,
SharedMediaTypesMask types = SharedMediaTypesMask::All())
: peerId(peerId)
, monoforumPeerId(monoforumPeerId)
, types(types) {
}
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
SharedMediaTypesMask types; SharedMediaTypesMask types;
}; };
@ -154,10 +172,12 @@ struct SharedMediaKey {
SharedMediaKey( SharedMediaKey(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type, SharedMediaType type,
MsgId messageId) MsgId messageId)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) , topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, type(type) , type(type)
, messageId(messageId) { , messageId(messageId) {
} }
@ -168,6 +188,7 @@ struct SharedMediaKey {
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
SharedMediaType type = SharedMediaType::kCount; SharedMediaType type = SharedMediaType::kCount;
MsgId messageId = 0; MsgId messageId = 0;
@ -195,16 +216,19 @@ struct SharedMediaSliceUpdate {
SharedMediaSliceUpdate( SharedMediaSliceUpdate(
PeerId peerId, PeerId peerId,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type, SharedMediaType type,
const SparseIdsSliceUpdate &data) const SparseIdsSliceUpdate &data)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) , topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, type(type) , type(type)
, data(data) { , data(data) {
} }
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
SharedMediaType type = SharedMediaType::kCount; SharedMediaType type = SharedMediaType::kCount;
SparseIdsSliceUpdate data; SparseIdsSliceUpdate data;
}; };
@ -212,13 +236,16 @@ struct SharedMediaSliceUpdate {
struct SharedMediaUnloadThread { struct SharedMediaUnloadThread {
SharedMediaUnloadThread( SharedMediaUnloadThread(
PeerId peerId, PeerId peerId,
MsgId topicRootId) MsgId topicRootId,
PeerId monoforumPeerId)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId) { , topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId) {
} }
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
}; };
class SharedMedia { class SharedMedia {
@ -245,6 +272,7 @@ private:
struct Key { struct Key {
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
friend inline constexpr auto operator<=>(Key, Key) = default; friend inline constexpr auto operator<=>(Key, Key) = default;
}; };

View File

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/notify/data_notify_settings.h" #include "data/notify/data_notify_settings.h"
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
@ -349,6 +350,15 @@ void System::registerThread(not_null<Data::Thread*> thread) {
clearFromTopic(topic); clearFromTopic(topic);
}, i->second); }, i->second);
} }
} else if (const auto sublist = thread->asSublist()) {
const auto &[i, ok] = _watchedSublists.emplace(
sublist,
rpl::lifetime());
if (ok) {
sublist->destroyed() | rpl::start_with_next([=] {
clearFromSublist(sublist);
}, i->second);
}
} }
} }
@ -426,6 +436,7 @@ void System::clearAll() {
_waiters.clear(); _waiters.clear();
_settingWaiters.clear(); _settingWaiters.clear();
_watchedTopics.clear(); _watchedTopics.clear();
_watchedSublists.clear();
} }
void System::clearFromTopic(not_null<Data::ForumTopic*> topic) { void System::clearFromTopic(not_null<Data::ForumTopic*> topic) {
@ -445,6 +456,23 @@ void System::clearFromTopic(not_null<Data::ForumTopic*> topic) {
showNext(); showNext();
} }
void System::clearFromSublist(not_null<Data::SavedSublist*> sublist) {
if (_manager) {
_manager->clearFromSublist(sublist);
}
sublist->clearNotifications();
_whenMaps.remove(sublist);
_whenAlerts.remove(sublist);
_waiters.remove(sublist);
_settingWaiters.remove(sublist);
_watchedSublists.remove(sublist);
_waitTimer.cancel();
showNext();
}
void System::clearForThreadIf(Fn<bool(not_null<Data::Thread*>)> predicate) { void System::clearForThreadIf(Fn<bool(not_null<Data::Thread*>)> predicate) {
for (auto i = _whenMaps.begin(); i != _whenMaps.end();) { for (auto i = _whenMaps.begin(); i != _whenMaps.end();) {
const auto thread = i->first; const auto thread = i->first;
@ -460,6 +488,8 @@ void System::clearForThreadIf(Fn<bool(not_null<Data::Thread*>)> predicate) {
_settingWaiters.remove(thread); _settingWaiters.remove(thread);
if (const auto topic = thread->asTopic()) { if (const auto topic = thread->asTopic()) {
_watchedTopics.remove(topic); _watchedTopics.remove(topic);
} else if (const auto sublist = thread->asSublist()) {
_watchedSublists.remove(sublist);
} }
} }
const auto clearFrom = [&](auto &map) { const auto clearFrom = [&](auto &map) {
@ -468,6 +498,8 @@ void System::clearForThreadIf(Fn<bool(not_null<Data::Thread*>)> predicate) {
if (predicate(thread)) { if (predicate(thread)) {
if (const auto topic = thread->asTopic()) { if (const auto topic = thread->asTopic()) {
_watchedTopics.remove(topic); _watchedTopics.remove(topic);
} else if (const auto sublist = thread->asSublist()) {
_watchedSublists.remove(sublist);
} }
i = map.erase(i); i = map.erase(i);
} else { } else {
@ -517,6 +549,15 @@ void System::clearIncomingFromTopic(not_null<Data::ForumTopic*> topic) {
_whenAlerts.remove(topic); _whenAlerts.remove(topic);
} }
void System::clearIncomingFromSublist(
not_null<Data::SavedSublist*> sublist) {
if (_manager) {
_manager->clearFromSublist(sublist);
}
sublist->clearIncomingNotifications();
_whenAlerts.remove(sublist);
}
void System::clearFromItem(not_null<HistoryItem*> item) { void System::clearFromItem(not_null<HistoryItem*> item) {
if (_manager) { if (_manager) {
_manager->clearFromItem(item); _manager->clearFromItem(item);
@ -533,6 +574,7 @@ void System::clearAllFast() {
_waiters.clear(); _waiters.clear();
_settingWaiters.clear(); _settingWaiters.clear();
_watchedTopics.clear(); _watchedTopics.clear();
_watchedSublists.clear();
} }
void System::checkDelayed() { void System::checkDelayed() {
@ -1114,10 +1156,14 @@ void Manager::notificationActivated(
history->peer, history->peer,
id.msgId); id.msgId);
const auto topic = item ? item->topic() : nullptr; const auto topic = item ? item->topic() : nullptr;
const auto sublist = item ? item->savedSublist() : nullptr;
if (!options.draft.text.isEmpty()) { if (!options.draft.text.isEmpty()) {
const auto topicRootId = topic const auto topicRootId = topic
? topic->rootId() ? topic->rootId()
: id.contextId.topicRootId; : id.contextId.topicRootId;
const auto monoforumPeerId = (sublist && sublist->parentChat())
? sublist->sublistPeer()->id
: id.contextId.monoforumPeerId;
const auto replyToId = (id.msgId > 0 const auto replyToId = (id.msgId > 0
&& !history->peer->isUser() && !history->peer->isUser()
&& id.msgId != topicRootId) && id.msgId != topicRootId)
@ -1129,6 +1175,7 @@ void Manager::notificationActivated(
FullReplyTo{ FullReplyTo{
.messageId = replyToId, .messageId = replyToId,
.topicRootId = topicRootId, .topicRootId = topicRootId,
.monoforumPeerId = monoforumPeerId,
}, },
MessageCursor{ MessageCursor{
length, length,
@ -1167,13 +1214,13 @@ Window::SessionController *Manager::openNotificationMessage(
&& item->isRegular() && item->isRegular()
&& (item->out() || (item->mentionsMe() && !history->peer->isUser())); && (item->out() || (item->mentionsMe() && !history->peer->isUser()));
const auto topic = item ? item->topic() : nullptr; const auto topic = item ? item->topic() : nullptr;
const auto sublist = (item && item->history()->amMonoforumAdmin()) const auto sublist = item ? item->savedSublist() : nullptr;
? item->savedSublist()
: nullptr;
const auto guard = gsl::finally([&] { const auto guard = gsl::finally([&] {
if (topic) { if (topic) {
system()->clearFromTopic(topic); system()->clearFromTopic(topic);
} else if (sublist && sublist->parentChat()) {
system()->clearFromSublist(sublist);
} else { } else {
system()->clearFromHistory(history); system()->clearFromHistory(history);
} }
@ -1256,6 +1303,10 @@ void Manager::notificationReplied(
const auto topicRootId = topic const auto topicRootId = topic
? topic->rootId() ? topic->rootId()
: id.contextId.topicRootId; : id.contextId.topicRootId;
const auto sublist = item ? item->savedSublist() : nullptr;
const auto monoforumPeerId = (sublist && sublist->parentChat())
? sublist->sublistPeer()->id
: id.contextId.monoforumPeerId;
auto message = Api::MessageToSend(Api::SendAction(history)); auto message = Api::MessageToSend(Api::SendAction(history));
message.textWithTags = reply; message.textWithTags = reply;
@ -1268,6 +1319,7 @@ void Manager::notificationReplied(
message.action.replyTo = { message.action.replyTo = {
.messageId = { replyToId ? history->peer->id : 0, replyToId }, .messageId = { replyToId ? history->peer->id : 0, replyToId },
.topicRootId = topic ? topic->rootId() : 0, .topicRootId = topic ? topic->rootId() : 0,
.monoforumPeerId = monoforumPeerId,
}; };
message.action.clearDraft = false; message.action.clearDraft = false;
history->session().api().sendMessage(std::move(message)); history->session().api().sendMessage(std::move(message));
@ -1293,16 +1345,21 @@ void NativeManager::doShowNotification(NotificationFields &&fields) {
&& !reactionFrom && !reactionFrom
&& (item->out() || peer->isSelf()) && (item->out() || peer->isSelf())
&& item->isFromScheduled(); && item->isFromScheduled();
const auto topicWithChat = [&] { const auto subWithChat = [&] {
const auto name = peer->name(); const auto name = peer->name();
const auto topic = item->topic(); const auto topic = item->topic();
return topic ? (topic->title() + u" ("_q + name + ')') : name; const auto sublist = item->savedSublist();
return topic
? (topic->title() + u" ("_q + name + ')')
: (sublist && sublist->parentChat())
? (sublist->sublistPeer()->shortName() + u" ("_q + name + ')')
: name;
}; };
const auto title = options.hideNameAndPhoto const auto title = options.hideNameAndPhoto
? AppName.utf16() ? AppName.utf16()
: (scheduled && peer->isSelf()) : (scheduled && peer->isSelf())
? tr::lng_notification_reminder(tr::now) ? tr::lng_notification_reminder(tr::now)
: topicWithChat(); : subWithChat();
const auto fullTitle = addTargetAccountName(title, &peer->session()); const auto fullTitle = addTargetAccountName(title, &peer->session());
const auto subtitle = reactionFrom const auto subtitle = reactionFrom
? (reactionFrom != peer ? reactionFrom->name() : QString()) ? (reactionFrom != peer ? reactionFrom->name() : QString())
@ -1341,6 +1398,9 @@ void NativeManager::doShowNotification(NotificationFields &&fields) {
doShowNativeNotification({ doShowNativeNotification({
.peer = item->history()->peer, .peer = item->history()->peer,
.topicRootId = item->topicRootId(), .topicRootId = item->topicRootId(),
.monoforumPeerId = (item->history()->amMonoforumAdmin()
? item->sublistPeerId()
: PeerId()),
.itemId = item->id, .itemId = item->id,
.title = scheduled ? WrapFromScheduled(fullTitle) : fullTitle, .title = scheduled ? WrapFromScheduled(fullTitle) : fullTitle,
.subtitle = subtitle, .subtitle = subtitle,

View File

@ -17,6 +17,7 @@ class History;
namespace Data { namespace Data {
class Session; class Session;
class ForumTopic; class ForumTopic;
class SavedSublist;
class Thread; class Thread;
struct ItemNotification; struct ItemNotification;
enum class ItemNotificationType; enum class ItemNotificationType;
@ -109,8 +110,10 @@ public:
void checkDelayed(); void checkDelayed();
void schedule(Data::ItemNotification notification); void schedule(Data::ItemNotification notification);
void clearFromTopic(not_null<Data::ForumTopic*> topic); void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history); void clearFromHistory(not_null<History*> history);
void clearIncomingFromTopic(not_null<Data::ForumTopic*> topic); void clearIncomingFromTopic(not_null<Data::ForumTopic*> topic);
void clearIncomingFromSublist(not_null<Data::SavedSublist*> sublist);
void clearIncomingFromHistory(not_null<History*> history); void clearIncomingFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session); void clearFromSession(not_null<Main::Session*> session);
void clearFromItem(not_null<HistoryItem*> item); void clearFromItem(not_null<HistoryItem*> item);
@ -221,6 +224,9 @@ private:
base::flat_map< base::flat_map<
not_null<Data::ForumTopic*>, not_null<Data::ForumTopic*>,
rpl::lifetime> _watchedTopics; rpl::lifetime> _watchedTopics;
base::flat_map<
not_null<Data::SavedSublist*>,
rpl::lifetime> _watchedSublists;
int _lastForwardedCount = 0; int _lastForwardedCount = 0;
uint64 _lastHistorySessionId = 0; uint64 _lastHistorySessionId = 0;
@ -237,6 +243,7 @@ public:
uint64 sessionId = 0; uint64 sessionId = 0;
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
friend inline auto operator<=>( friend inline auto operator<=>(
const ContextId&, const ContextId&,
@ -279,6 +286,9 @@ public:
void clearFromTopic(not_null<Data::ForumTopic*> topic) { void clearFromTopic(not_null<Data::ForumTopic*> topic) {
doClearFromTopic(topic); doClearFromTopic(topic);
} }
void clearFromSublist(not_null<Data::SavedSublist*> sublist) {
doClearFromSublist(sublist);
}
void clearFromHistory(not_null<History*> history) { void clearFromHistory(not_null<History*> history) {
doClearFromHistory(history); doClearFromHistory(history);
} }
@ -341,6 +351,8 @@ protected:
virtual void doClearAllFast() = 0; virtual void doClearAllFast() = 0;
virtual void doClearFromItem(not_null<HistoryItem*> item) = 0; virtual void doClearFromItem(not_null<HistoryItem*> item) = 0;
virtual void doClearFromTopic(not_null<Data::ForumTopic*> topic) = 0; virtual void doClearFromTopic(not_null<Data::ForumTopic*> topic) = 0;
virtual void doClearFromSublist(
not_null<Data::SavedSublist*> sublist) = 0;
virtual void doClearFromHistory(not_null<History*> history) = 0; virtual void doClearFromHistory(not_null<History*> history) = 0;
virtual void doClearFromSession(not_null<Main::Session*> session) = 0; virtual void doClearFromSession(not_null<Main::Session*> session) = 0;
[[nodiscard]] virtual bool doSkipToast() const = 0; [[nodiscard]] virtual bool doSkipToast() const = 0;
@ -377,6 +389,7 @@ public:
struct NotificationInfo { struct NotificationInfo {
not_null<PeerData*> peer; not_null<PeerData*> peer;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
MsgId itemId = 0; MsgId itemId = 0;
QString title; QString title;
QString subtitle; QString subtitle;
@ -426,6 +439,8 @@ protected:
} }
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override { void doClearFromTopic(not_null<Data::ForumTopic*> topic) override {
} }
void doClearFromSublist(not_null<Data::SavedSublist*> sublist) override {
}
void doClearFromHistory(not_null<History*> history) override { void doClearFromHistory(not_null<History*> history) override {
} }
void doClearFromSession(not_null<Main::Session*> session) override { void doClearFromSession(not_null<Main::Session*> session) override {

View File

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/power_saving.h" #include "ui/power_saving.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
@ -236,6 +237,7 @@ void Manager::showNextFromQueue() {
this, this,
queued.history, queued.history,
queued.topicRootId, queued.topicRootId,
queued.monoforumPeerId,
queued.peer, queued.peer,
queued.author, queued.author,
queued.item, queued.item,
@ -383,7 +385,25 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
} }
} }
for (const auto &notification : _notifications) { for (const auto &notification : _notifications) {
if (notification->unlinkHistory(history, topicRootId)) { if (notification->unlinkHistory(history, topicRootId, PeerId())) {
_positionsOutdated = true;
}
}
showNextFromQueue();
}
void Manager::doClearFromSublist(not_null<Data::SavedSublist*> sublist) {
const auto history = sublist->owningHistory();
const auto sublistPeerId = sublist->sublistPeer()->id;
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.cend();) {
if (i->history == history && i->monoforumPeerId == sublistPeerId) {
i = _queuedNotifications.erase(i);
} else {
++i;
}
}
for (const auto &notification : _notifications) {
if (notification->unlinkHistory(history, MsgId(), sublistPeerId)) {
_positionsOutdated = true; _positionsOutdated = true;
} }
} }
@ -618,6 +638,7 @@ Notification::Notification(
not_null<Manager*> manager, not_null<Manager*> manager,
not_null<History*> history, not_null<History*> history,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
not_null<PeerData*> peer, not_null<PeerData*> peer,
const QString &author, const QString &author,
HistoryItem *item, HistoryItem *item,
@ -633,6 +654,8 @@ Notification::Notification(
, _history(history) , _history(history)
, _topic(history->peer->forumTopicFor(topicRootId)) , _topic(history->peer->forumTopicFor(topicRootId))
, _topicRootId(topicRootId) , _topicRootId(topicRootId)
, _sublist(history->peer->monoforumSublistFor(monoforumPeerId))
, _monoforumPeerId(monoforumPeerId)
, _userpicView(_peer->createUserpicView()) , _userpicView(_peer->createUserpicView())
, _author(author) , _author(author)
, _reaction(reaction) , _reaction(reaction)
@ -1149,10 +1172,14 @@ void Notification::changeHeight(int newHeight) {
manager()->changeNotificationHeight(this, newHeight); manager()->changeNotificationHeight(this, newHeight);
} }
bool Notification::unlinkHistory(History *history, MsgId topicRootId) { bool Notification::unlinkHistory(
History *history,
MsgId topicRootId,
PeerId monoforumPeerId) {
const auto unlink = _history const auto unlink = _history
&& (history == _history || !history) && (history == _history || !history)
&& (topicRootId == _topicRootId || !topicRootId); && (topicRootId == _topicRootId || !topicRootId)
&& (monoforumPeerId == _monoforumPeerId || !monoforumPeerId);
if (unlink) { if (unlink) {
hideFast(); hideFast();
_history = nullptr; _history = nullptr;

View File

@ -70,6 +70,7 @@ private:
void doClearAll() override; void doClearAll() override;
void doClearAllFast() override; void doClearAllFast() override;
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override; void doClearFromTopic(not_null<Data::ForumTopic*> topic) override;
void doClearFromSublist(not_null<Data::SavedSublist*> sublist) override;
void doClearFromHistory(not_null<History*> history) override; void doClearFromHistory(not_null<History*> history) override;
void doClearFromSession(not_null<Main::Session*> session) override; void doClearFromSession(not_null<Main::Session*> session) override;
void doClearFromItem(not_null<HistoryItem*> item) override; void doClearFromItem(not_null<HistoryItem*> item) override;
@ -111,6 +112,7 @@ private:
not_null<History*> history; not_null<History*> history;
MsgId topicRootId = 0; MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
not_null<PeerData*> peer; not_null<PeerData*> peer;
Data::ReactionId reaction; Data::ReactionId reaction;
QString author; QString author;
@ -203,6 +205,7 @@ public:
not_null<Manager*> manager, not_null<Manager*> manager,
not_null<History*> history, not_null<History*> history,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
not_null<PeerData*> peer, not_null<PeerData*> peer,
const QString &author, const QString &author,
HistoryItem *item, HistoryItem *item,
@ -231,7 +234,10 @@ public:
// Called only by Manager. // Called only by Manager.
bool unlinkItem(HistoryItem *del); bool unlinkItem(HistoryItem *del);
bool unlinkHistory(History *history = nullptr, MsgId topicRootId = 0); bool unlinkHistory(
History *history = nullptr,
MsgId topicRootId = 0,
PeerId monoforumPeerId = 0);
bool unlinkSession(not_null<Main::Session*> session); bool unlinkSession(not_null<Main::Session*> session);
bool checkLastInput( bool checkLastInput(
bool hasReplyingNotifications, bool hasReplyingNotifications,
@ -285,6 +291,8 @@ private:
History *_history = nullptr; History *_history = nullptr;
Data::ForumTopic *_topic = nullptr; Data::ForumTopic *_topic = nullptr;
MsgId _topicRootId = 0; MsgId _topicRootId = 0;
Data::SavedSublist *_sublist = nullptr;
PeerId _monoforumPeerId = 0;
Ui::PeerUserpicView _userpicView; Ui::PeerUserpicView _userpicView;
QString _author; QString _author;
Data::ReactionId _reaction; Data::ReactionId _reaction;

View File

@ -3040,14 +3040,18 @@ void HidePinnedBar(
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
Fn<void()> onHidden) { Fn<void()> onHidden) {
const auto callback = crl::guard(navigation, [=](Fn<void()> &&close) { const auto callback = crl::guard(navigation, [=](Fn<void()> &&close) {
close(); close();
auto &session = peer->session(); auto &session = peer->session();
const auto migrated = topicRootId ? nullptr : peer->migrateFrom(); const auto migrated = (topicRootId || monoforumPeerId)
? nullptr
: peer->migrateFrom();
const auto top = Data::ResolveTopPinnedId( const auto top = Data::ResolveTopPinnedId(
peer, peer,
topicRootId, topicRootId,
monoforumPeerId,
migrated); migrated);
const auto universal = !top const auto universal = !top
? MsgId(0) ? MsgId(0)
@ -3058,6 +3062,7 @@ void HidePinnedBar(
session.settings().setHiddenPinnedMessageId( session.settings().setHiddenPinnedMessageId(
peer->id, peer->id,
topicRootId, topicRootId,
monoforumPeerId,
universal); universal);
session.saveSettingsDelayed(); session.saveSettingsDelayed();
if (onHidden) { if (onHidden) {
@ -3091,6 +3096,7 @@ void UnpinAllMessages(
const auto history = strong->owningHistory(); const auto history = strong->owningHistory();
const auto topicRootId = strong->topicRootId(); const auto topicRootId = strong->topicRootId();
const auto sublist = strong->asSublist(); const auto sublist = strong->asSublist();
const auto monoforumPeerId = strong->monoforumPeerId();
using Flag = MTPmessages_UnpinAllMessages::Flag; using Flag = MTPmessages_UnpinAllMessages::Flag;
api->request(MTPmessages_UnpinAllMessages( api->request(MTPmessages_UnpinAllMessages(
MTP_flags((topicRootId ? Flag::f_top_msg_id : Flag()) MTP_flags((topicRootId ? Flag::f_top_msg_id : Flag())
@ -3104,7 +3110,7 @@ void UnpinAllMessages(
if (offset > 0) { if (offset > 0) {
self(self); self(self);
} else { } else {
history->unpinMessagesFor(topicRootId); history->unpinMessagesFor(topicRootId, monoforumPeerId);
} }
}).send(); }).send();
}; };

View File

@ -218,6 +218,7 @@ void HidePinnedBar(
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId, MsgId topicRootId,
PeerId monoforumPeerId,
Fn<void()> onHidden); Fn<void()> onHidden);
void UnpinAllMessages( void UnpinAllMessages(
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,

View File

@ -2927,8 +2927,12 @@ void SessionController::openPhoto(
if (openSharedStory(item) || openFakeItemStory(message.id, stories)) { if (openSharedStory(item) || openFakeItemStory(message.id, stories)) {
return; return;
} }
_window->openInMediaView( _window->openInMediaView(Media::View::OpenRequest(
Media::View::OpenRequest(this, photo, item, message.topicRootId)); this,
photo,
item,
message.topicRootId,
message.monoforumPeerId));
} }
void SessionController::openPhoto( void SessionController::openPhoto(
@ -2963,11 +2967,17 @@ void SessionController::openDocument(
document, document,
item, item,
message.topicRootId, message.topicRootId,
message.monoforumPeerId,
false, false,
usedTimestamp)); usedTimestamp));
return; return;
} }
Data::ResolveDocument(this, document, item, message.topicRootId); Data::ResolveDocument(
this,
document,
item,
message.topicRootId,
message.monoforumPeerId);
} }
bool SessionController::openSharedStory(HistoryItem *item) { bool SessionController::openSharedStory(HistoryItem *item) {

View File

@ -523,6 +523,7 @@ public:
struct MessageContext { struct MessageContext {
FullMsgId id; FullMsgId id;
MsgId topicRootId; MsgId topicRootId;
PeerId monoforumPeerId;
}; };
void openPhoto( void openPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,