Merge pinned list with migrated legacy group.

This commit is contained in:
John Preston 2020-10-22 15:40:33 +03:00
parent 18d218044c
commit 68041d2ffb
13 changed files with 248 additions and 104 deletions

View file

@ -69,6 +69,21 @@ TextParseOptions kMarkedTextBoxOptions = {
Qt::LayoutDirectionAuto, // dir
};
[[nodiscard]] bool IsOldForPin(MsgId id, not_null<PeerData*> peer) {
const auto normal = peer->migrateToOrMe();
const auto migrated = normal->migrateFrom();
const auto top = Data::ResolveTopPinnedId(normal, migrated);
if (!top) {
return false;
} else if (peer == migrated) {
return top.channel || (id < top.msg);
} else if (migrated) {
return top.channel && (id < top.msg);
} else {
return (id < top.msg);
}
}
} // namespace
ConfirmBox::ConfirmBox(
@ -444,7 +459,7 @@ PinMessageBox::PinMessageBox(
: _peer(peer)
, _api(&peer->session().mtp())
, _msgId(msgId)
, _pinningOld(msgId < Data::ResolveTopPinnedId(peer))
, _pinningOld(IsOldForPin(msgId, peer))
, _text(
this,
(_pinningOld

View file

@ -1017,7 +1017,9 @@ void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) {
peer->setHasPinnedMessages(true);
}
MsgId ResolveTopPinnedId(not_null<PeerData*> peer) {
FullMsgId ResolveTopPinnedId(
not_null<PeerData*> peer,
PeerData *migrated) {
const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
@ -1026,10 +1028,32 @@ MsgId ResolveTopPinnedId(not_null<PeerData*> peer) {
ServerMaxMsgId - 1),
1,
1));
return slice.messageIds.empty() ? 0 : slice.messageIds.back();
const auto old = migrated
? migrated->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
migrated->id,
Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1),
1,
1))
: Storage::SharedMediaResult{
.count = 0,
.skippedBefore = 0,
.skippedAfter = 0,
};
if (!slice.messageIds.empty()) {
return FullMsgId(peerToChannel(peer->id), slice.messageIds.back());
} else if (!migrated || slice.count != 0 || old.messageIds.empty()) {
return FullMsgId();
} else {
return FullMsgId(0, old.messageIds.back());
}
}
std::optional<int> ResolvePinnedCount(not_null<PeerData*> peer) {
std::optional<int> ResolvePinnedCount(
not_null<PeerData*> peer,
PeerData *migrated) {
const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
@ -1038,7 +1062,23 @@ std::optional<int> ResolvePinnedCount(not_null<PeerData*> peer) {
0),
0,
0));
return slice.count;
const auto old = migrated
? migrated->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
migrated->id,
Storage::SharedMediaType::Pinned,
0),
0,
0))
: Storage::SharedMediaResult{
.count = 0,
.skippedBefore = 0,
.skippedAfter = 0,
};
return (slice.count.has_value() && old.count.has_value())
? std::make_optional(*slice.count + *old.count)
: std::nullopt;
}
} // namespace Data

View file

@ -443,7 +443,11 @@ std::optional<QString> RestrictionError(
ChatRestriction restriction);
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId);
[[nodiscard]] MsgId ResolveTopPinnedId(not_null<PeerData*> peer);
[[nodiscard]] std::optional<int> ResolvePinnedCount(not_null<PeerData*> peer);
[[nodiscard]] FullMsgId ResolveTopPinnedId(
not_null<PeerData*> peer,
PeerData *migrated);
[[nodiscard]] std::optional<int> ResolvePinnedCount(
not_null<PeerData*> peer,
PeerData *migrated);
} // namespace Data

View file

@ -2998,6 +2998,31 @@ int HistoryInner::itemTop(const Element *view) const {
return (top < 0) ? top : (top + view->y() + view->block()->y());
}
auto HistoryInner::findViewForPinnedTracking(int top) const
-> std::pair<Element*, int> {
const auto normalTop = historyTop();
const auto oldTop = migratedTop();
const auto fromHistory = [&](not_null<History*> history, int historyTop)
-> std::pair<Element*, int> {
auto [view, offset] = history->findItemAndOffset(top - historyTop);
while (view && !IsServerMsgId(view->data()->id)) {
offset -= view->height();
view = view->nextInBlocks();
}
return { view, offset };
};
if (normalTop >= 0 && (oldTop < 0 || top >= normalTop)) {
return fromHistory(_history, normalTop);
} else if (oldTop >= 0) {
auto [view, offset] = fromHistory(_migrated, oldTop);
if (!view && normalTop >= 0) {
return fromHistory(_history, normalTop);
}
return { view, offset };
}
return { nullptr, 0 };
}
void HistoryInner::notifyIsBotChanged() {
const auto newinfo = _peer->isUser()
? _peer->asUser()->botInfo.get()

View file

@ -111,6 +111,10 @@ public:
int itemTop(const HistoryItem *item) const;
int itemTop(const Element *view) const;
// Returns (view, offset-from-top).
[[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking(
int top) const;
void notifyIsBotChanged();
void notifyMigrateUpdated();

View file

@ -569,6 +569,12 @@ HistoryWidget::HistoryWidget(
| UpdateFlag::BotStartToken
| UpdateFlag::PinnedMessages
) | rpl::filter([=](const Data::PeerUpdate &update) {
if (_migrated && update.peer.get() == _migrated->peer) {
if (_pinnedTracker
&& (update.flags & UpdateFlag::PinnedMessages)) {
checkPinnedBarState();
}
}
return (update.peer.get() == _peer);
}) | rpl::map([](const Data::PeerUpdate &update) {
return update.flags;
@ -3398,6 +3404,7 @@ void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
if (_replyForwardPressed) {
_replyForwardPressed = false;
update(0, _field->y() - st::historySendPadding - st::historyReplyHeight, width(), st::historyReplyHeight);
setupPinnedTracker(); AssertIsDebug();
}
if (_recording) {
stopRecording(_peer && _inField);
@ -5021,6 +5028,7 @@ void HistoryWidget::handlePeerMigration() {
} else {
_migrated = _history->migrateFrom();
_list->notifyMigrateUpdated();
setupPinnedTracker();
updateHistoryGeometry();
}
const auto from = chat->owner().historyLoaded(chat);
@ -5168,23 +5176,14 @@ void HistoryWidget::updatePinnedViewer() {
|| !_historyInited) {
return;
}
const auto [item, offset] = [&] {
auto visibleTop = _scroll->scrollTop();
if (_migrated
&& _history->loadedAtBottom()
&& _migrated->loadedAtTop()) {
visibleTop -= _migrated->height();
}
auto [item, offset] = _history->findItemAndOffset(visibleTop);
while (item && !IsServerMsgId(item->data()->id)) {
offset -= item->height();
item = item->nextInBlocks();
}
return std::pair(item, offset);
}();
const auto lessThanId = item
? (item->data()->id + (offset > 0 ? 1 : 0))
: (ServerMaxMsgId - 1);
const auto visibleTop = _scroll->scrollTop();
const auto add = (st::historyReplyHeight - _pinnedBarHeight);
auto [view, offset] = _list->findViewForPinnedTracking(visibleTop + add);
const auto lessThanId = !view
? (ServerMaxMsgId - 1)
: (view->data()->history() != _history)
? (view->data()->id + (offset > 0 ? 1 : 0) - ServerMaxMsgId)
: (view->data()->id + (offset > 0 ? 1 : 0));
_pinnedTracker->trackAround(lessThanId);
}
@ -5202,8 +5201,15 @@ void HistoryWidget::checkPinnedBarState() {
const auto hiddenId = _peer->canPinMessages()
? MsgId(0)
: session().settings().hiddenPinnedMessageId(_peer->id);
const auto currentPinnedId = Data::ResolveTopPinnedId(_peer);
if (currentPinnedId == hiddenId) {
const auto currentPinnedId = Data::ResolveTopPinnedId(
_peer,
_migrated ? _migrated->peer.get() : nullptr);
const auto universalPinnedId = !currentPinnedId
? int32(0)
: (_migrated && !currentPinnedId.channel)
? (currentPinnedId.msg - ServerMaxMsgId)
: currentPinnedId.msg;
if (universalPinnedId == hiddenId) {
if (_pinnedBar) {
_pinnedTracker->reset();
auto qobject = base::unique_qptr{
@ -5221,21 +5227,13 @@ void HistoryWidget::checkPinnedBarState() {
}
return;
}
if (_pinnedBar || !currentPinnedId) {
if (_pinnedBar || !universalPinnedId) {
return;
}
auto shown = _pinnedTracker->shownMessageId(
) | rpl::map([=](HistoryView::PinnedId messageId) {
return HistoryView::PinnedBarId{
FullMsgId{ peerToChannel(_peer->id), messageId.message },
messageId.index,
messageId.count
};
});
auto barContent = HistoryView::PinnedBarContent(
&session(),
std::move(shown));
_pinnedTracker->shownMessageId());
_pinnedBar = std::make_unique<Ui::PinnedBar>(
this,
std::move(barContent));
@ -5268,8 +5266,8 @@ void HistoryWidget::checkPinnedBarState() {
_pinnedBar->barClicks(
) | rpl::start_with_next([=] {
const auto id = _pinnedTracker->currentMessageId();
if (id.message) {
Ui::showPeerHistory(_peer, id.message);
if (const auto item = session().data().message(id.message)) {
Ui::showPeerHistory(item->history()->peer, item->id);
}
}, _pinnedBar->lifetime());
@ -5303,7 +5301,11 @@ void HistoryWidget::refreshPinnedBarButton(bool many) {
const auto id = _pinnedTracker->currentMessageId();
if (id.message) {
controller()->showSection(
HistoryView::PinnedMemento(_history, id.message));
HistoryView::PinnedMemento(
_history,
((!_migrated || id.message.channel)
? id.message.msg
: (id.message.msg - ServerMaxMsgId))));
}
}
}, button->lifetime());
@ -5560,10 +5562,7 @@ void HistoryWidget::hidePinnedMessage() {
return;
}
if (_peer->canPinMessages()) {
Window::ToggleMessagePinned(
controller(),
{ peerToChannel(_peer->id), id.message },
false);
Window::ToggleMessagePinned(controller(), id.message, false);
} else {
const auto callback = [=] {
if (_pinnedTracker) {
@ -5877,7 +5876,9 @@ void HistoryWidget::handlePeerUpdate() {
updateHistoryGeometry();
if (_peer->isChat() && _peer->asChat()->noParticipantInfo()) {
session().api().requestFullPeer(_peer);
} else if (_peer->isUser() && (_peer->asUser()->blockStatus() == UserData::BlockStatus::Unknown || _peer->asUser()->callsStatus() == UserData::CallsStatus::Unknown)) {
} else if (_peer->isUser()
&& (_peer->asUser()->blockStatus() == UserData::BlockStatus::Unknown
|| _peer->asUser()->callsStatus() == UserData::CallsStatus::Unknown)) {
session().api().requestFullPeer(_peer);
} else if (auto channel = _peer->asMegagroup()) {
if (!channel->mgInfo->botStatus) {

View file

@ -117,7 +117,7 @@ namespace {
}));
}
auto WithPinnedTitle(not_null<Main::Session*> session, PinnedBarId id) {
auto WithPinnedTitle(not_null<Main::Session*> session, PinnedId id) {
return [=](Ui::MessageBarContent &&content) {
const auto item = session->data().message(id.message);
if (!item) {
@ -144,11 +144,11 @@ rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
rpl::producer<Ui::MessageBarContent> PinnedBarContent(
not_null<Main::Session*> session,
rpl::producer<PinnedBarId> id) {
rpl::producer<PinnedId> id) {
return std::move(
id
) | rpl::distinct_until_changed(
) | rpl::map([=](PinnedBarId id) {
) | rpl::map([=](PinnedId id) {
return ContentByItemId(
session,
id.message

View file

@ -28,25 +28,25 @@ namespace HistoryView {
FullMsgId id);
enum class PinnedIdType;
struct PinnedBarId {
struct PinnedId {
FullMsgId message;
int index = 0;
int count = 1;
bool operator<(const PinnedBarId &other) const {
bool operator<(const PinnedId &other) const {
return std::tie(message, index, count)
< std::tie(other.message, other.index, other.count);
}
bool operator==(const PinnedBarId &other) const {
bool operator==(const PinnedId &other) const {
return std::tie(message, index, count)
== std::tie(other.message, other.index, other.count);
}
bool operator!=(const PinnedBarId &other) const {
bool operator!=(const PinnedId &other) const {
return !(*this == other);
}
};
[[nodiscard]] rpl::producer<Ui::MessageBarContent> PinnedBarContent(
not_null<Main::Session*> session,
rpl::producer<PinnedBarId> id);
rpl::producer<PinnedId> id);
} // namespace HistoryView

View file

@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h"
#include "history/history_item.h"
#include "boxes/confirm_box.h"
#include "data/data_peer_values.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/shadow.h"
#include "ui/layers/generic_box.h"
@ -34,10 +33,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_chat.h"
#include "data/data_channel.h"
#include "data/data_changes.h"
#include "data/data_sparse_ids.h"
#include "data/data_shared_media.h"
#include "data/data_peer_values.h"
#include "storage/storage_account.h"
#include "platform/platform_specific.h"
#include "lang/lang_keys.h"
@ -90,7 +91,8 @@ PinnedWidget::PinnedWidget(
not_null<Window::SessionController*> controller,
not_null<History*> history)
: Window::SectionWidget(parent, controller)
, _history(history)
, _history(history->migrateToOrMe())
, _migratedPeer(_history->peer->migrateFrom())
, _topBar(this, controller)
, _topBarShadow(this)
, _scroll(std::make_unique<Ui::ScrollArea>(this, st::historyScroll, false))
@ -321,7 +323,8 @@ bool PinnedWidget::showInternal(
not_null<Window::SectionMemento*> memento,
const Window::SectionShow &params) {
if (auto logMemento = dynamic_cast<PinnedMemento*>(memento.get())) {
if (logMemento->getHistory() == history()) {
if (logMemento->getHistory() == history()
|| logMemento->getHistory()->migrateToOrMe() == history()) {
restoreState(logMemento);
return true;
}
@ -358,7 +361,9 @@ void PinnedWidget::restoreState(not_null<PinnedMemento*> memento) {
_inner->restoreState(memento->list());
if (const auto highlight = memento->getHighlightId()) {
const auto position = Data::MessagePosition{
.fullId = FullMsgId(_history->channelId(), highlight),
.fullId = ((highlight > 0 || !_migratedPeer)
? FullMsgId(_history->channelId(), highlight)
: FullMsgId(0, -highlight)),
.date = TimeId(0),
};
_inner->showAroundPosition(position, [=] {
@ -508,6 +513,28 @@ void PinnedWidget::listDeleteRequest() {
confirmDeleteSelected();
}
rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer,
PeerData *migrated,
Storage::SharedMediaType type) {
auto aroundId = 0;
auto limit = 0;
auto updated = SharedMediaMergedViewer(
&peer->session(),
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
peer->id,
migrated ? migrated->id : 0,
aroundId),
type),
limit,
limit
) | rpl::map([](const SparseIdsMergedSlice &slice) {
return slice.fullCount();
}) | rpl::filter_optional();
return rpl::single(0) | rpl::then(std::move(updated));
}
rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
Data::MessagePosition aroundId,
int limitBefore,
@ -516,15 +543,18 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
const auto messageId = aroundId.fullId.msg
? aroundId.fullId.msg
: (ServerMaxMsgId - 1);
return SharedMediaViewer(
return SharedMediaMergedViewer(
&_history->session(),
Storage::SharedMediaKey(
_history->peer->id,
Storage::SharedMediaType::Pinned,
messageId),
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
_history->peer->id,
_migratedPeer ? _migratedPeer->id : 0,
messageId),
Storage::SharedMediaType::Pinned),
limitBefore,
limitAfter
) | rpl::filter([=](const SparseIdsSlice &slice) {
) | rpl::filter([=](const SparseIdsMergedSlice &slice) {
const auto count = slice.fullCount();
if (!count.has_value()) {
return true;
@ -535,7 +565,7 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
controller()->showBackFromStack();
return false;
}
}) | rpl::map([=](SparseIdsSlice &&slice) {
}) | rpl::map([=](SparseIdsMergedSlice &&slice) {
auto result = Data::MessagesSlice();
result.fullCount = slice.fullCount();
result.skippedAfter = slice.skippedAfter();
@ -543,10 +573,10 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
const auto count = slice.size();
result.ids.reserve(count);
if (const auto msgId = slice.nearest(messageId)) {
result.nearestToAround = FullMsgId(channelId, *msgId);
result.nearestToAround = *msgId;
}
for (auto i = 0; i != count; ++i) {
result.ids.emplace_back(channelId, slice[i]);
result.ids.push_back(slice[i]);
}
return result;
});

View file

@ -136,6 +136,7 @@ private:
void refreshClearButtonText();
const not_null<History*> _history;
PeerData *_migratedPeer = nullptr;
QPointer<ListWidget> _inner;
object_ptr<TopBarWidget> _topBar;
object_ptr<Ui::PlainShadow> _topBarShadow;
@ -155,9 +156,11 @@ private:
class PinnedMemento : public Window::SectionMemento {
public:
using UniversalMsgId = int32;
explicit PinnedMemento(
not_null<History*> history,
MsgId highlightId = 0);
UniversalMsgId highlightId = 0);
object_ptr<Window::SectionWidget> createWidget(
QWidget *parent,
@ -172,13 +175,13 @@ public:
[[nodiscard]] not_null<ListMemento*> list() {
return &_list;
}
[[nodiscard]] MsgId getHighlightId() const {
[[nodiscard]] UniversalMsgId getHighlightId() const {
return _highlightId;
}
private:
const not_null<History*> _history;
const MsgId _highlightId = 0;
const UniversalMsgId _highlightId = 0;
ListMemento _list;
};

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_changes.h"
#include "data/data_peer.h"
#include "data/data_chat.h"
#include "data/data_channel.h"
#include "data/data_shared_media.h"
#include "data/data_session.h"
@ -26,13 +27,25 @@ constexpr auto kChangeViewerLimit = 2;
} // namespace
PinnedTracker::PinnedTracker(not_null<History*> history) : _history(history) {
_history->session().changes().peerFlagsValue(
_history->peer,
Data::PeerUpdate::Flag::PinnedMessages
) | rpl::map([=] {
return _history->peer->hasPinnedMessages();
}) | rpl::distinct_until_changed(
PinnedTracker::PinnedTracker(not_null<History*> history)
: _history(history->migrateToOrMe())
, _migratedPeer(_history->peer->migrateFrom()) {
using namespace rpl::mappers;
const auto has = [&](PeerData *peer) -> rpl::producer<bool> {
auto &changes = _history->session().changes();
const auto flag = Data::PeerUpdate::Flag::PinnedMessages;
if (!peer) {
return rpl::single(false);
}
return changes.peerFlagsValue(peer, flag) | rpl::map([=] {
return peer->hasPinnedMessages();
});
};
rpl::combine(
has(_history->peer),
has(_migratedPeer),
_1 || _2
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool has) {
if (has) {
refreshViewer();
@ -62,15 +75,17 @@ void PinnedTracker::refreshViewer() {
}
_dataLifetime.destroy();
_viewerAroundId = _aroundId;
SharedMediaViewer(
SharedMediaMergedViewer(
&_history->peer->session(),
Storage::SharedMediaKey(
_history->peer->id,
Storage::SharedMediaType::Pinned,
_viewerAroundId),
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
_history->peer->id,
_migratedPeer ? _migratedPeer->id : 0,
_viewerAroundId),
Storage::SharedMediaType::Pinned),
kLoadedLimit,
kLoadedLimit
) | rpl::start_with_next([=](const SparseIdsSlice &result) {
) | rpl::start_with_next([=](const SparseIdsMergedSlice &result) {
_slice.fullCount = result.fullCount();
_slice.skippedBefore = result.skippedBefore();
_slice.skippedAfter = result.skippedAfter();
@ -83,12 +98,23 @@ void PinnedTracker::refreshViewer() {
refreshCurrentFromSlice();
if (_slice.fullCount == 0) {
_history->peer->setHasPinnedMessages(false);
if (_migratedPeer) {
_migratedPeer->setHasPinnedMessages(false);
}
}
}, _dataLifetime);
}
void PinnedTracker::refreshCurrentFromSlice() {
const auto i = ranges::lower_bound(_slice.ids, _aroundId);
const auto proj1 = [](FullMsgId id) {
return id.channel ? id.msg : (id.msg - ServerMaxMsgId);
};
const auto proj2 = [](FullMsgId id) {
return id.msg;
};
const auto i = _migratedPeer
? ranges::lower_bound(_slice.ids, _aroundId, ranges::less(), proj1)
: ranges::lower_bound(_slice.ids, _aroundId, ranges::less(), proj2);
const auto empty = _slice.ids.empty();
const auto before = int(i - begin(_slice.ids));
const auto after = int(end(_slice.ids) - i);

View file

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "history/view/history_view_pinned_bar.h"
class History;
namespace Data {
@ -15,29 +17,16 @@ enum class LoadDirection : char;
namespace HistoryView {
struct PinnedId {
MsgId message = 0;
int index = 0;
int count = 1;
bool operator<(const PinnedId &other) const {
return std::tie(message, index, count)
< std::tie(other.message, other.index, other.count);
}
bool operator==(const PinnedId &other) const {
return std::tie(message, index, count)
== std::tie(other.message, other.index, other.count);
}
};
class PinnedTracker final {
public:
using UniversalMsgId = int32;
explicit PinnedTracker(not_null<History*> history);
~PinnedTracker();
[[nodiscard]] rpl::producer<PinnedId> shownMessageId() const;
[[nodiscard]] PinnedId currentMessageId() const;
void trackAround(MsgId messageId);
void trackAround(UniversalMsgId messageId);
void reset();
[[nodiscard]] rpl::lifetime &lifetime() {
@ -46,7 +35,7 @@ public:
private:
struct Slice {
std::vector<MsgId> ids;
std::vector<FullMsgId> ids;
std::optional<int> fullCount;
std::optional<int> skippedBefore;
std::optional<int> skippedAfter;
@ -56,12 +45,13 @@ private:
void refreshCurrentFromSlice();
const not_null<History*> _history;
PeerData *_migratedPeer = nullptr;
rpl::variable<PinnedId> _current;
rpl::lifetime _dataLifetime;
MsgId _aroundId = 0;
MsgId _viewerAroundId = 0;
UniversalMsgId _aroundId = 0;
UniversalMsgId _viewerAroundId = 0;
Slice _slice;
rpl::lifetime _lifetime;

View file

@ -1157,9 +1157,15 @@ void HidePinnedBar(
Ui::show(Box<ConfirmBox>(tr::lng_pinned_hide_all_sure(tr::now), tr::lng_pinned_hide_all_hide(tr::now), crl::guard(navigation, [=] {
Ui::hideLayer();
auto &session = peer->session();
const auto top = Data::ResolveTopPinnedId(peer);
if (top) {
session.settings().setHiddenPinnedMessageId(peer->id, top);
const auto migrated = peer->migrateFrom();
const auto top = Data::ResolveTopPinnedId(peer, migrated);
const auto universal = !top
? int32(0)
: (migrated && !top.channel)
? (top.msg - ServerMaxMsgId)
: top.msg;
if (universal) {
session.settings().setHiddenPinnedMessageId(peer->id, universal);
session.saveSettingsDelayed();
if (onHidden) {
onHidden();