mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 23:27:09 +02:00
Merge pinned list with migrated legacy group.
This commit is contained in:
parent
18d218044c
commit
68041d2ffb
13 changed files with 248 additions and 104 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ¶ms) {
|
||||
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;
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue