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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -18,6 +18,16 @@ namespace Data {
class Session;
class SavedSublist;
struct SavedMessagesOffsets {
TimeId date = 0;
MsgId id = 0;
PeerData *peer = nullptr;
friend inline constexpr auto operator<=>(
SavedMessagesOffsets,
SavedMessagesOffsets) = default;
};
class SavedMessages final {
public:
explicit SavedMessages(
@ -37,6 +47,7 @@ public:
[[nodiscard]] not_null<Dialogs::MainList*> chatsList();
[[nodiscard]] not_null<SavedSublist*> sublist(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<> chatsListLoadedEvents() const;
@ -59,13 +70,31 @@ public:
[[nodiscard]] auto recentSublists() const
-> const std::vector<not_null<SavedSublist*>> &;
void clear();
[[nodiscard]] rpl::lifetime &lifetime();
private:
struct SublistRequest {
mtpRequestId id = 0;
std::vector<Fn<void()>> callbacks;
};
struct ApplyResult {
SavedMessagesOffsets offset;
bool allLoaded = false;
};
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 requestSomeStale();
void finishSublistRequest(not_null<PeerData*> peer);
void sendLoadMore();
void sendLoadMoreRequests();
@ -80,13 +109,14 @@ private:
base::flat_map<
not_null<PeerData*>,
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 _pinnedRequestId = 0;
TimeId _offsetDate = 0;
MsgId _offsetId = 0;
PeerData *_offsetPeer = nullptr;
SavedMessagesOffsets _offset;
SingleQueuedInvokation _loadMore;
bool _loadMoreScheduled = false;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -18,6 +18,7 @@ struct WhoReadList;
namespace Data {
class ForumTopic;
class SavedSublist;
} // namespace Data
namespace Ui {
@ -94,6 +95,7 @@ class Key {
public:
explicit Key(not_null<PeerData*> peer);
explicit Key(not_null<Data::ForumTopic*> topic);
explicit Key(not_null<Data::SavedSublist*> sublist);
Key(Settings::Tag settings);
Key(Downloads::Tag downloads);
Key(Stories::Tag stories);
@ -108,6 +110,7 @@ public:
PeerData *peer() const;
Data::ForumTopic *topic() const;
Data::SavedSublist *sublist() const;
UserData *settingsSelf() const;
bool isDownloads() const;
bool isGlobalMedia() const;
@ -135,6 +138,7 @@ private:
std::variant<
not_null<PeerData*>,
not_null<Data::ForumTopic*>,
not_null<Data::SavedSublist*>,
Settings::Tag,
Downloads::Tag,
Stories::Tag,
@ -225,6 +229,9 @@ public:
[[nodiscard]] Data::ForumTopic *topic() const {
return key().topic();
}
[[nodiscard]] Data::SavedSublist *sublist() const {
return key().sublist();
}
[[nodiscard]] UserData *settingsSelf() const {
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_chat.h"
#include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "data/data_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::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(DefaultStack(settings, section)) {
}
@ -66,9 +75,12 @@ Memento::Memento(
Memento::Memento(std::vector<std::shared_ptr<ContentMemento>> stack)
: _stack(std::move(stack)) {
auto topics = base::flat_set<not_null<Data::ForumTopic*>>();
auto sublists = base::flat_set<not_null<Data::SavedSublist*>>();
for (auto &entry : _stack) {
if (const auto topic = entry->topic()) {
topics.emplace(topic);
} else if (const auto sublist = entry->sublist()) {
sublists.emplace(sublist);
}
}
for (const auto &topic : topics) {
@ -86,6 +98,21 @@ Memento::Memento(std::vector<std::shared_ptr<ContentMemento>> stack)
}
}, _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(
@ -104,6 +131,14 @@ std::vector<std::shared_ptr<ContentMemento>> Memento::DefaultStack(
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(
Settings::Tag settings,
Section section) {
@ -205,6 +240,20 @@ std::shared_ptr<ContentMemento> 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(
QWidget *parent,
not_null<Window::SessionController*> controller,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -105,6 +105,7 @@ private:
const not_null<PeerData*> _peer;
const MsgId _topicRootId = 0;
const PeerId _monoforumPeerId = 0;
PeerData * const _migrated = nullptr;
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 "history/history.h"
#include "info/media/info_media_inner_widget.h"
#include "info/info_controller.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_channel.h"
#include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "lang/lang_keys.h"
#include "styles/style_info.h"
@ -70,6 +72,7 @@ Memento::Memento(not_null<Controller*> controller)
? controller->storiesPeer()
: controller->parentController()->session().user()),
controller->topic(),
controller->sublist(),
controller->migratedPeerId(),
(controller->section().type() == Section::Type::Downloads
? Type::File
@ -79,23 +82,31 @@ Memento::Memento(not_null<Controller*> controller)
}
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(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(
not_null<PeerData*> peer,
Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId,
Type type)
: ContentMemento(peer, topic, migratedPeerId)
: ContentMemento(peer, topic, sublist, migratedPeerId)
, _type(type) {
_searchState.query.type = type;
_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;
if (migratedPeerId) {
_searchState.migratedList = Storage::SparseIdsList();

View file

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

View file

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

View file

@ -678,7 +678,7 @@ void InnerWidget::restoreState(not_null<Memento*> memento) {
}
Memento::Memento(not_null<PeerData*> peer)
: ContentMemento(peer, nullptr, PeerId()) {
: ContentMemento(peer, nullptr, nullptr, PeerId()) {
}
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_file_origin.h"
#include "data/data_user.h"
#include "data/data_saved_sublist.h"
#include "main/main_session.h"
#include "apiwrap.h"
#include "api/api_peer_photo.h"
@ -46,6 +47,7 @@ InnerWidget::InnerWidget(
, _peer(_controller->key().peer())
, _migrated(_controller->migrated())
, _topic(_controller->key().topic())
, _sublist(_controller->key().sublist())
, _content(setupContent(this, origin)) {
_content->heightValue(
) | rpl::start_with_next([this](int height) {
@ -82,7 +84,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
AddDetails(result, _controller, _peer, _topic, origin);
result->add(setupSharedMedia(result.data()));
if (_topic) {
if (_topic || _sublist) {
return result;
}
{
@ -147,7 +149,8 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
content,
_controller,
_peer,
_topic ? _topic->rootId() : 0,
_topic ? _topic->rootId() : MsgId(),
_sublist ? _sublist->sublistPeer()->id : PeerId(),
_migrated,
type,
tracker);

View file

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

View file

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

View file

@ -113,6 +113,7 @@ struct LinkWithUrl {
[[nodiscard]] rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer,
MsgId topicRootId,
PeerId monoforumPeerId,
PeerData *migrated,
Storage::SharedMediaType type);
[[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 "dialogs/ui/dialogs_stories_content.h"
#include "history/history.h"
#include "info/profile/info_profile_inner_widget.h"
#include "info/profile/info_profile_members.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_channel.h"
#include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h"
#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "info/info_controller.h"
@ -25,6 +27,7 @@ Memento::Memento(not_null<Controller*> controller)
: Memento(
controller->peer(),
controller->topic(),
controller->sublist(),
controller->migratedPeerId(),
{ v::null }) {
}
@ -33,20 +36,25 @@ Memento::Memento(
not_null<PeerData*> peer,
PeerId migratedPeerId,
Origin origin)
: Memento(peer, nullptr, migratedPeerId, origin) {
: Memento(peer, nullptr, nullptr, migratedPeerId, origin) {
}
Memento::Memento(
not_null<PeerData*> peer,
Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId,
Origin origin)
: ContentMemento(peer, topic, migratedPeerId)
: ContentMemento(peer, topic, sublist, migratedPeerId)
, _origin(origin) {
}
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 {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -170,6 +170,7 @@ private:
not_null<DocumentData*>> data;
HistoryItem *item = nullptr;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
};
enum class SavePhotoVideo {
None,
@ -674,6 +675,7 @@ private:
History *_migrated = nullptr;
History *_history = nullptr; // if conversation photos or files overview
MsgId _topicRootId = 0;
PeerId _monoforumPeerId = 0;
PeerData *_peer = nullptr;
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/core_settings.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_item.h"
#include "main/main_session.h"
@ -156,6 +158,7 @@ public:
void clearAll();
void clearFromItem(not_null<HistoryItem*> item);
void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session);
void clearNotification(NotificationId id);
@ -367,6 +370,8 @@ Manager::Private::Private(not_null<Manager*> manager)
.sessionId = dict.lookup_value("session").get_uint64(),
.peerId = PeerId(dict.lookup_value("peer").get_uint64()),
.topicRootId = dict.lookup_value("topic").get_int64(),
.monoforumPeerId = dict.lookup_value(
"monoforumpeer").get_uint64(),
},
.msgId = dict.lookup_value("msgid").get_int64(),
};
@ -531,6 +536,7 @@ void Manager::Private::showNotification(
.sessionId = peer->session().uniqueId(),
.peerId = peer->id,
.topicRootId = info.topicRootId,
.monoforumPeerId = info.monoforumPeerId,
};
const auto notificationId = NotificationId{
.contextId = key,
@ -591,6 +597,10 @@ void Manager::Private::showNotification(
GLib::Variant::new_string("topic"),
GLib::Variant::new_variant(
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_string("msgid"),
GLib::Variant::new_variant(
@ -809,6 +819,7 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
.sessionId = item->history()->session().uniqueId(),
.peerId = item->history()->peer->id,
.topicRootId = item->topicRootId(),
.monoforumPeerId = item->sublistPeerId(),
});
if (i != _notifications.cend()
&& 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) {
const auto sessionId = history->session().uniqueId();
const auto peerId = history->peer->id;
@ -889,6 +909,10 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
_private->clearFromTopic(topic);
}
void Manager::doClearFromSublist(not_null<Data::SavedSublist*> sublist) {
_private->clearFromSublist(sublist);
}
void Manager::doClearFromHistory(not_null<History*> history) {
_private->clearFromHistory(history);
}

View file

@ -24,6 +24,7 @@ protected:
void doClearAllFast() override;
void doClearFromItem(not_null<HistoryItem*> item) 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 doClearFromSession(not_null<Main::Session*> session) override;
bool doSkipToast() const override;

View file

@ -25,6 +25,7 @@ protected:
void doClearAllFast() override;
void doClearFromItem(not_null<HistoryItem*> item) 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 doClearFromSession(not_null<Main::Session*> session) 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/random.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_item.h"
#include "ui/empty_userpic.h"
@ -131,6 +133,12 @@ using Manager = Platform::Notifications::Manager;
return;
}
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"];
const auto notificationMsgId = msgObject ? [msgObject longLongValue] : 0LL;
@ -140,6 +148,7 @@ using Manager = Platform::Notifications::Manager;
.sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId),
.topicRootId = MsgId(notificationTopicRootId),
.monoforumPeerId = PeerId(notificationMonoforumPeerId),
},
.msgId = notificationMsgId,
};
@ -210,6 +219,7 @@ public:
void clearAll();
void clearFromItem(not_null<HistoryItem*> item);
void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session);
void updateDelegate();
@ -237,6 +247,9 @@ private:
struct ClearFromTopic {
ContextId contextId;
};
struct ClearFromSublist {
ContextId contextId;
}
struct ClearFromHistory {
ContextId partialContextId;
};
@ -250,6 +263,7 @@ private:
using ClearTask = std::variant<
ClearFromItem,
ClearFromTopic,
ClearFromSublist,
ClearFromHistory,
ClearFromSession,
ClearAll,
@ -311,6 +325,8 @@ void Manager::Private::showNotification(
@"peer",
[NSNumber numberWithLongLong:info.topicRootId.bare],
@"topic",
[NSNumber numberWithUnsignedLongLong:info.monoforumPeerId.value],
@"monoforumpeer",
[NSNumber numberWithLongLong:info.itemId.bare],
@"msgid",
[NSNumber numberWithUnsignedLongLong:_managerId],
@ -351,6 +367,7 @@ void Manager::Private::clearingThreadLoop() {
auto clearAll = false;
auto clearFromItems = base::flat_set<NotificationId>();
auto clearFromTopics = base::flat_set<ContextId>();
auto clearFromSublists = base::flat_set<ContextId>();
auto clearFromHistories = base::flat_set<ContextId>();
auto clearFromSessions = base::flat_set<uint64>();
{
@ -368,6 +385,8 @@ void Manager::Private::clearingThreadLoop() {
clearFromItems.emplace(value.id);
}, [&](const ClearFromTopic &value) {
clearFromTopics.emplace(value.contextId);
}, [&](const ClearFromSublist &value) {
clearFromSublists.emplace(value.contextId);
}, [&](const ClearFromHistory &value) {
clearFromHistories.emplace(value.partialContextId);
}, [&](const ClearFromSession &value) {
@ -395,21 +414,35 @@ void Manager::Private::clearingThreadLoop() {
return true;
}
const auto notificationTopicRootId = [topicObject longLongValue];
NSNumber *monoforumPeerObject = [notificationUserInfo objectForKey:@"monoforumpeer"];
if (!monoforumPeerObject) {
return true;
}
const auto notificationMonoforumPeerId = [monoforumPeerObject unsignedLongLongValue];
NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"];
const auto msgId = msgObject ? [msgObject longLongValue] : 0LL;
const auto partialContextId = ContextId{
.sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId),
};
const auto contextId = ContextId{
const auto contextId = notificationTopicRootId
? ContextId{
.sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId),
.topicRootId = MsgId(notificationTopicRootId),
};
}
: notificationMonoforumPeerId
? ContextId{
.sessionId = notificationSessionId,
.peerId = PeerId(notificationPeerId),
.monoforumPeerId = PeerId(notificationMonoforumPeerId),
}
: partialContextId;
const auto id = NotificationId{ contextId, MsgId(msgId) };
return clearFromSessions.contains(notificationSessionId)
|| clearFromHistories.contains(partialContextId)
|| clearFromTopics.contains(contextId)
|| clearFromSublists.contains(contextId)
|| (msgId && clearFromItems.contains(id));
};
@ -450,6 +483,7 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
.sessionId = item->history()->session().uniqueId(),
.peerId = item->history()->peer->id,
.topicRootId = item->topicRootId(),
.monoforumPeerId = item->sublistPeerId(),
}, 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) {
putClearTask(ClearFromHistory{ ContextId{
.sessionId = history->session().uniqueId(),
@ -511,6 +554,10 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
_private->clearFromTopic(topic);
}
void Manager::doClearFromSublist(not_null<Data::SavedSublist*> sublist) {
_private->clearFromSublist(sublist);
}
void Manager::doClearFromHistory(not_null<History*> 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/specific_win.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_item.h"
#include "core/application.h"
@ -433,6 +435,7 @@ public:
void clearAll();
void clearFromItem(not_null<HistoryItem*> item);
void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session);
void beforeNotificationActivated(NotificationId id);
@ -508,6 +511,7 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
.sessionId = item->history()->session().uniqueId(),
.peerId = item->history()->peer->id,
.topicRootId = item->topicRootId(),
.monoforumPeerId = item->sublistPeerId(),
});
if (i == _notifications.cend()) {
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) {
if (!_notifier) {
return;
@ -626,7 +651,9 @@ void Manager::Private::handleActivation(const ToastActivation &activation) {
.contextId = ContextId{
.sessionId = parsed.value("session").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()),
};
@ -694,16 +721,18 @@ bool Manager::Private::showNotificationInTryCatch(
.sessionId = peer->session().uniqueId(),
.peerId = peer->id,
.topicRootId = info.topicRootId,
.monoforumPeerId = info.monoforumPeerId,
};
const auto notificationId = NotificationId{
.contextId = key,
.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(key.sessionId)
.arg(key.peerId.value)
.arg(info.topicRootId.bare)
.arg(info.monoforumPeerId.value)
.arg(info.itemId.bare);
const auto modern = Platform::IsWindows10OrGreater();
@ -897,6 +926,10 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
_private->clearFromTopic(topic);
}
void Manager::doClearFromSublist(not_null<Data::SavedSublist*> sublist) {
_private->clearFromSublist(sublist);
}
void Manager::doClearFromHistory(not_null<History*> history) {
_private->clearFromHistory(history);
}

View file

@ -31,6 +31,7 @@ protected:
void doClearAllFast() override;
void doClearFromItem(not_null<HistoryItem*> item) 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 doClearFromSession(not_null<Main::Session*> session) override;
void onBeforeNotificationActivated(NotificationId id) override;

View file

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

View file

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

View file

@ -42,16 +42,19 @@ struct SharedMediaAddNew {
SharedMediaAddNew(
PeerId peerId,
MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaTypesMask types,
MsgId messageId)
: peerId(peerId)
, topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, messageId(messageId)
, types(types) {
}
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
MsgId messageId = 0;
SharedMediaTypesMask types;
@ -61,11 +64,13 @@ struct SharedMediaAddExisting {
SharedMediaAddExisting(
PeerId peerId,
MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaTypesMask types,
MsgId messageId,
MsgRange noSkipRange)
: peerId(peerId)
, topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, messageId(messageId)
, noSkipRange(noSkipRange)
, types(types) {
@ -73,6 +78,7 @@ struct SharedMediaAddExisting {
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
MsgId messageId = 0;
MsgRange noSkipRange;
SharedMediaTypesMask types;
@ -83,12 +89,14 @@ struct SharedMediaAddSlice {
SharedMediaAddSlice(
PeerId peerId,
MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type,
std::vector<MsgId> &&messageIds,
MsgRange noSkipRange,
std::optional<int> count = std::nullopt)
: peerId(peerId)
, topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, messageIds(std::move(messageIds))
, noSkipRange(noSkipRange)
, type(type)
@ -97,6 +105,7 @@ struct SharedMediaAddSlice {
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
std::vector<MsgId> messageIds;
MsgRange noSkipRange;
SharedMediaType type = SharedMediaType::kCount;
@ -135,9 +144,18 @@ struct SharedMediaRemoveAll {
, topicRootId(topicRootId)
, types(types) {
}
SharedMediaRemoveAll(
PeerId peerId,
PeerId monoforumPeerId,
SharedMediaTypesMask types = SharedMediaTypesMask::All())
: peerId(peerId)
, monoforumPeerId(monoforumPeerId)
, types(types) {
}
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
SharedMediaTypesMask types;
};
@ -154,10 +172,12 @@ struct SharedMediaKey {
SharedMediaKey(
PeerId peerId,
MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type,
MsgId messageId)
: peerId(peerId)
, topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, type(type)
, messageId(messageId) {
}
@ -168,6 +188,7 @@ struct SharedMediaKey {
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
SharedMediaType type = SharedMediaType::kCount;
MsgId messageId = 0;
@ -195,16 +216,19 @@ struct SharedMediaSliceUpdate {
SharedMediaSliceUpdate(
PeerId peerId,
MsgId topicRootId,
PeerId monoforumPeerId,
SharedMediaType type,
const SparseIdsSliceUpdate &data)
: peerId(peerId)
, topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId)
, type(type)
, data(data) {
}
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
SharedMediaType type = SharedMediaType::kCount;
SparseIdsSliceUpdate data;
};
@ -212,13 +236,16 @@ struct SharedMediaSliceUpdate {
struct SharedMediaUnloadThread {
SharedMediaUnloadThread(
PeerId peerId,
MsgId topicRootId)
MsgId topicRootId,
PeerId monoforumPeerId)
: peerId(peerId)
, topicRootId(topicRootId) {
, topicRootId(topicRootId)
, monoforumPeerId(monoforumPeerId) {
}
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
};
class SharedMedia {
@ -245,6 +272,7 @@ private:
struct Key {
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
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/stickers/data_custom_emoji.h"
#include "data/data_document_media.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h"
#include "data/data_channel.h"
#include "data/data_forum_topic.h"
@ -349,6 +350,15 @@ void System::registerThread(not_null<Data::Thread*> thread) {
clearFromTopic(topic);
}, 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();
_settingWaiters.clear();
_watchedTopics.clear();
_watchedSublists.clear();
}
void System::clearFromTopic(not_null<Data::ForumTopic*> topic) {
@ -445,6 +456,23 @@ void System::clearFromTopic(not_null<Data::ForumTopic*> topic) {
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) {
for (auto i = _whenMaps.begin(); i != _whenMaps.end();) {
const auto thread = i->first;
@ -460,6 +488,8 @@ void System::clearForThreadIf(Fn<bool(not_null<Data::Thread*>)> predicate) {
_settingWaiters.remove(thread);
if (const auto topic = thread->asTopic()) {
_watchedTopics.remove(topic);
} else if (const auto sublist = thread->asSublist()) {
_watchedSublists.remove(sublist);
}
}
const auto clearFrom = [&](auto &map) {
@ -468,6 +498,8 @@ void System::clearForThreadIf(Fn<bool(not_null<Data::Thread*>)> predicate) {
if (predicate(thread)) {
if (const auto topic = thread->asTopic()) {
_watchedTopics.remove(topic);
} else if (const auto sublist = thread->asSublist()) {
_watchedSublists.remove(sublist);
}
i = map.erase(i);
} else {
@ -517,6 +549,15 @@ void System::clearIncomingFromTopic(not_null<Data::ForumTopic*> 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) {
if (_manager) {
_manager->clearFromItem(item);
@ -533,6 +574,7 @@ void System::clearAllFast() {
_waiters.clear();
_settingWaiters.clear();
_watchedTopics.clear();
_watchedSublists.clear();
}
void System::checkDelayed() {
@ -1114,10 +1156,14 @@ void Manager::notificationActivated(
history->peer,
id.msgId);
const auto topic = item ? item->topic() : nullptr;
const auto sublist = item ? item->savedSublist() : nullptr;
if (!options.draft.text.isEmpty()) {
const auto topicRootId = topic
? topic->rootId()
: id.contextId.topicRootId;
const auto monoforumPeerId = (sublist && sublist->parentChat())
? sublist->sublistPeer()->id
: id.contextId.monoforumPeerId;
const auto replyToId = (id.msgId > 0
&& !history->peer->isUser()
&& id.msgId != topicRootId)
@ -1129,6 +1175,7 @@ void Manager::notificationActivated(
FullReplyTo{
.messageId = replyToId,
.topicRootId = topicRootId,
.monoforumPeerId = monoforumPeerId,
},
MessageCursor{
length,
@ -1167,13 +1214,13 @@ Window::SessionController *Manager::openNotificationMessage(
&& item->isRegular()
&& (item->out() || (item->mentionsMe() && !history->peer->isUser()));
const auto topic = item ? item->topic() : nullptr;
const auto sublist = (item && item->history()->amMonoforumAdmin())
? item->savedSublist()
: nullptr;
const auto sublist = item ? item->savedSublist() : nullptr;
const auto guard = gsl::finally([&] {
if (topic) {
system()->clearFromTopic(topic);
} else if (sublist && sublist->parentChat()) {
system()->clearFromSublist(sublist);
} else {
system()->clearFromHistory(history);
}
@ -1256,6 +1303,10 @@ void Manager::notificationReplied(
const auto topicRootId = topic
? topic->rootId()
: 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));
message.textWithTags = reply;
@ -1268,6 +1319,7 @@ void Manager::notificationReplied(
message.action.replyTo = {
.messageId = { replyToId ? history->peer->id : 0, replyToId },
.topicRootId = topic ? topic->rootId() : 0,
.monoforumPeerId = monoforumPeerId,
};
message.action.clearDraft = false;
history->session().api().sendMessage(std::move(message));
@ -1293,16 +1345,21 @@ void NativeManager::doShowNotification(NotificationFields &&fields) {
&& !reactionFrom
&& (item->out() || peer->isSelf())
&& item->isFromScheduled();
const auto topicWithChat = [&] {
const auto subWithChat = [&] {
const auto name = peer->name();
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
? AppName.utf16()
: (scheduled && peer->isSelf())
? tr::lng_notification_reminder(tr::now)
: topicWithChat();
: subWithChat();
const auto fullTitle = addTargetAccountName(title, &peer->session());
const auto subtitle = reactionFrom
? (reactionFrom != peer ? reactionFrom->name() : QString())
@ -1341,6 +1398,9 @@ void NativeManager::doShowNotification(NotificationFields &&fields) {
doShowNativeNotification({
.peer = item->history()->peer,
.topicRootId = item->topicRootId(),
.monoforumPeerId = (item->history()->amMonoforumAdmin()
? item->sublistPeerId()
: PeerId()),
.itemId = item->id,
.title = scheduled ? WrapFromScheduled(fullTitle) : fullTitle,
.subtitle = subtitle,

View file

@ -17,6 +17,7 @@ class History;
namespace Data {
class Session;
class ForumTopic;
class SavedSublist;
class Thread;
struct ItemNotification;
enum class ItemNotificationType;
@ -109,8 +110,10 @@ public:
void checkDelayed();
void schedule(Data::ItemNotification notification);
void clearFromTopic(not_null<Data::ForumTopic*> topic);
void clearFromSublist(not_null<Data::SavedSublist*> sublist);
void clearFromHistory(not_null<History*> history);
void clearIncomingFromTopic(not_null<Data::ForumTopic*> topic);
void clearIncomingFromSublist(not_null<Data::SavedSublist*> sublist);
void clearIncomingFromHistory(not_null<History*> history);
void clearFromSession(not_null<Main::Session*> session);
void clearFromItem(not_null<HistoryItem*> item);
@ -221,6 +224,9 @@ private:
base::flat_map<
not_null<Data::ForumTopic*>,
rpl::lifetime> _watchedTopics;
base::flat_map<
not_null<Data::SavedSublist*>,
rpl::lifetime> _watchedSublists;
int _lastForwardedCount = 0;
uint64 _lastHistorySessionId = 0;
@ -237,6 +243,7 @@ public:
uint64 sessionId = 0;
PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
friend inline auto operator<=>(
const ContextId&,
@ -279,6 +286,9 @@ public:
void clearFromTopic(not_null<Data::ForumTopic*> topic) {
doClearFromTopic(topic);
}
void clearFromSublist(not_null<Data::SavedSublist*> sublist) {
doClearFromSublist(sublist);
}
void clearFromHistory(not_null<History*> history) {
doClearFromHistory(history);
}
@ -341,6 +351,8 @@ protected:
virtual void doClearAllFast() = 0;
virtual void doClearFromItem(not_null<HistoryItem*> item) = 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 doClearFromSession(not_null<Main::Session*> session) = 0;
[[nodiscard]] virtual bool doSkipToast() const = 0;
@ -377,6 +389,7 @@ public:
struct NotificationInfo {
not_null<PeerData*> peer;
MsgId topicRootId = 0;
PeerId monoforumPeerId = 0;
MsgId itemId = 0;
QString title;
QString subtitle;
@ -426,6 +439,8 @@ protected:
}
void doClearFromTopic(not_null<Data::ForumTopic*> topic) override {
}
void doClearFromSublist(not_null<Data::SavedSublist*> sublist) override {
}
void doClearFromHistory(not_null<History*> history) 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/power_saving.h"
#include "ui/ui_utility.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h"
#include "data/data_forum_topic.h"
#include "data/stickers/data_custom_emoji.h"
@ -236,6 +237,7 @@ void Manager::showNextFromQueue() {
this,
queued.history,
queued.topicRootId,
queued.monoforumPeerId,
queued.peer,
queued.author,
queued.item,
@ -383,7 +385,25 @@ void Manager::doClearFromTopic(not_null<Data::ForumTopic*> topic) {
}
}
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;
}
}
@ -618,6 +638,7 @@ Notification::Notification(
not_null<Manager*> manager,
not_null<History*> history,
MsgId topicRootId,
PeerId monoforumPeerId,
not_null<PeerData*> peer,
const QString &author,
HistoryItem *item,
@ -633,6 +654,8 @@ Notification::Notification(
, _history(history)
, _topic(history->peer->forumTopicFor(topicRootId))
, _topicRootId(topicRootId)
, _sublist(history->peer->monoforumSublistFor(monoforumPeerId))
, _monoforumPeerId(monoforumPeerId)
, _userpicView(_peer->createUserpicView())
, _author(author)
, _reaction(reaction)
@ -1149,10 +1172,14 @@ void Notification::changeHeight(int 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
&& (history == _history || !history)
&& (topicRootId == _topicRootId || !topicRootId);
&& (topicRootId == _topicRootId || !topicRootId)
&& (monoforumPeerId == _monoforumPeerId || !monoforumPeerId);
if (unlink) {
hideFast();
_history = nullptr;

View file

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

View file

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

View file

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

View file

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

View file

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