mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +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
|
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
|
} // namespace
|
||||||
|
|
||||||
ConfirmBox::ConfirmBox(
|
ConfirmBox::ConfirmBox(
|
||||||
|
@ -444,7 +459,7 @@ PinMessageBox::PinMessageBox(
|
||||||
: _peer(peer)
|
: _peer(peer)
|
||||||
, _api(&peer->session().mtp())
|
, _api(&peer->session().mtp())
|
||||||
, _msgId(msgId)
|
, _msgId(msgId)
|
||||||
, _pinningOld(msgId < Data::ResolveTopPinnedId(peer))
|
, _pinningOld(IsOldForPin(msgId, peer))
|
||||||
, _text(
|
, _text(
|
||||||
this,
|
this,
|
||||||
(_pinningOld
|
(_pinningOld
|
||||||
|
|
|
@ -1017,7 +1017,9 @@ void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) {
|
||||||
peer->setHasPinnedMessages(true);
|
peer->setHasPinnedMessages(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgId ResolveTopPinnedId(not_null<PeerData*> peer) {
|
FullMsgId ResolveTopPinnedId(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
PeerData *migrated) {
|
||||||
const auto slice = peer->session().storage().snapshot(
|
const auto slice = peer->session().storage().snapshot(
|
||||||
Storage::SharedMediaQuery(
|
Storage::SharedMediaQuery(
|
||||||
Storage::SharedMediaKey(
|
Storage::SharedMediaKey(
|
||||||
|
@ -1026,10 +1028,32 @@ MsgId ResolveTopPinnedId(not_null<PeerData*> peer) {
|
||||||
ServerMaxMsgId - 1),
|
ServerMaxMsgId - 1),
|
||||||
1,
|
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(
|
const auto slice = peer->session().storage().snapshot(
|
||||||
Storage::SharedMediaQuery(
|
Storage::SharedMediaQuery(
|
||||||
Storage::SharedMediaKey(
|
Storage::SharedMediaKey(
|
||||||
|
@ -1038,7 +1062,23 @@ std::optional<int> ResolvePinnedCount(not_null<PeerData*> peer) {
|
||||||
0),
|
0),
|
||||||
0,
|
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
|
} // namespace Data
|
||||||
|
|
|
@ -443,7 +443,11 @@ std::optional<QString> RestrictionError(
|
||||||
ChatRestriction restriction);
|
ChatRestriction restriction);
|
||||||
|
|
||||||
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId);
|
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId);
|
||||||
[[nodiscard]] MsgId ResolveTopPinnedId(not_null<PeerData*> peer);
|
[[nodiscard]] FullMsgId ResolveTopPinnedId(
|
||||||
[[nodiscard]] std::optional<int> ResolvePinnedCount(not_null<PeerData*> peer);
|
not_null<PeerData*> peer,
|
||||||
|
PeerData *migrated);
|
||||||
|
[[nodiscard]] std::optional<int> ResolvePinnedCount(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
PeerData *migrated);
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -2998,6 +2998,31 @@ int HistoryInner::itemTop(const Element *view) const {
|
||||||
return (top < 0) ? top : (top + view->y() + view->block()->y());
|
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() {
|
void HistoryInner::notifyIsBotChanged() {
|
||||||
const auto newinfo = _peer->isUser()
|
const auto newinfo = _peer->isUser()
|
||||||
? _peer->asUser()->botInfo.get()
|
? _peer->asUser()->botInfo.get()
|
||||||
|
|
|
@ -111,6 +111,10 @@ public:
|
||||||
int itemTop(const HistoryItem *item) const;
|
int itemTop(const HistoryItem *item) const;
|
||||||
int itemTop(const Element *view) const;
|
int itemTop(const Element *view) const;
|
||||||
|
|
||||||
|
// Returns (view, offset-from-top).
|
||||||
|
[[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking(
|
||||||
|
int top) const;
|
||||||
|
|
||||||
void notifyIsBotChanged();
|
void notifyIsBotChanged();
|
||||||
void notifyMigrateUpdated();
|
void notifyMigrateUpdated();
|
||||||
|
|
||||||
|
|
|
@ -569,6 +569,12 @@ HistoryWidget::HistoryWidget(
|
||||||
| UpdateFlag::BotStartToken
|
| UpdateFlag::BotStartToken
|
||||||
| UpdateFlag::PinnedMessages
|
| UpdateFlag::PinnedMessages
|
||||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
) | 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);
|
return (update.peer.get() == _peer);
|
||||||
}) | rpl::map([](const Data::PeerUpdate &update) {
|
}) | rpl::map([](const Data::PeerUpdate &update) {
|
||||||
return update.flags;
|
return update.flags;
|
||||||
|
@ -3398,6 +3404,7 @@ void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
if (_replyForwardPressed) {
|
if (_replyForwardPressed) {
|
||||||
_replyForwardPressed = false;
|
_replyForwardPressed = false;
|
||||||
update(0, _field->y() - st::historySendPadding - st::historyReplyHeight, width(), st::historyReplyHeight);
|
update(0, _field->y() - st::historySendPadding - st::historyReplyHeight, width(), st::historyReplyHeight);
|
||||||
|
setupPinnedTracker(); AssertIsDebug();
|
||||||
}
|
}
|
||||||
if (_recording) {
|
if (_recording) {
|
||||||
stopRecording(_peer && _inField);
|
stopRecording(_peer && _inField);
|
||||||
|
@ -5021,6 +5028,7 @@ void HistoryWidget::handlePeerMigration() {
|
||||||
} else {
|
} else {
|
||||||
_migrated = _history->migrateFrom();
|
_migrated = _history->migrateFrom();
|
||||||
_list->notifyMigrateUpdated();
|
_list->notifyMigrateUpdated();
|
||||||
|
setupPinnedTracker();
|
||||||
updateHistoryGeometry();
|
updateHistoryGeometry();
|
||||||
}
|
}
|
||||||
const auto from = chat->owner().historyLoaded(chat);
|
const auto from = chat->owner().historyLoaded(chat);
|
||||||
|
@ -5168,23 +5176,14 @@ void HistoryWidget::updatePinnedViewer() {
|
||||||
|| !_historyInited) {
|
|| !_historyInited) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto [item, offset] = [&] {
|
const auto visibleTop = _scroll->scrollTop();
|
||||||
auto visibleTop = _scroll->scrollTop();
|
const auto add = (st::historyReplyHeight - _pinnedBarHeight);
|
||||||
if (_migrated
|
auto [view, offset] = _list->findViewForPinnedTracking(visibleTop + add);
|
||||||
&& _history->loadedAtBottom()
|
const auto lessThanId = !view
|
||||||
&& _migrated->loadedAtTop()) {
|
? (ServerMaxMsgId - 1)
|
||||||
visibleTop -= _migrated->height();
|
: (view->data()->history() != _history)
|
||||||
}
|
? (view->data()->id + (offset > 0 ? 1 : 0) - ServerMaxMsgId)
|
||||||
auto [item, offset] = _history->findItemAndOffset(visibleTop);
|
: (view->data()->id + (offset > 0 ? 1 : 0));
|
||||||
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);
|
|
||||||
_pinnedTracker->trackAround(lessThanId);
|
_pinnedTracker->trackAround(lessThanId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5202,8 +5201,15 @@ void HistoryWidget::checkPinnedBarState() {
|
||||||
const auto hiddenId = _peer->canPinMessages()
|
const auto hiddenId = _peer->canPinMessages()
|
||||||
? MsgId(0)
|
? MsgId(0)
|
||||||
: session().settings().hiddenPinnedMessageId(_peer->id);
|
: session().settings().hiddenPinnedMessageId(_peer->id);
|
||||||
const auto currentPinnedId = Data::ResolveTopPinnedId(_peer);
|
const auto currentPinnedId = Data::ResolveTopPinnedId(
|
||||||
if (currentPinnedId == hiddenId) {
|
_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) {
|
if (_pinnedBar) {
|
||||||
_pinnedTracker->reset();
|
_pinnedTracker->reset();
|
||||||
auto qobject = base::unique_qptr{
|
auto qobject = base::unique_qptr{
|
||||||
|
@ -5221,21 +5227,13 @@ void HistoryWidget::checkPinnedBarState() {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_pinnedBar || !currentPinnedId) {
|
if (_pinnedBar || !universalPinnedId) {
|
||||||
return;
|
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(
|
auto barContent = HistoryView::PinnedBarContent(
|
||||||
&session(),
|
&session(),
|
||||||
std::move(shown));
|
_pinnedTracker->shownMessageId());
|
||||||
_pinnedBar = std::make_unique<Ui::PinnedBar>(
|
_pinnedBar = std::make_unique<Ui::PinnedBar>(
|
||||||
this,
|
this,
|
||||||
std::move(barContent));
|
std::move(barContent));
|
||||||
|
@ -5268,8 +5266,8 @@ void HistoryWidget::checkPinnedBarState() {
|
||||||
_pinnedBar->barClicks(
|
_pinnedBar->barClicks(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
const auto id = _pinnedTracker->currentMessageId();
|
const auto id = _pinnedTracker->currentMessageId();
|
||||||
if (id.message) {
|
if (const auto item = session().data().message(id.message)) {
|
||||||
Ui::showPeerHistory(_peer, id.message);
|
Ui::showPeerHistory(item->history()->peer, item->id);
|
||||||
}
|
}
|
||||||
}, _pinnedBar->lifetime());
|
}, _pinnedBar->lifetime());
|
||||||
|
|
||||||
|
@ -5303,7 +5301,11 @@ void HistoryWidget::refreshPinnedBarButton(bool many) {
|
||||||
const auto id = _pinnedTracker->currentMessageId();
|
const auto id = _pinnedTracker->currentMessageId();
|
||||||
if (id.message) {
|
if (id.message) {
|
||||||
controller()->showSection(
|
controller()->showSection(
|
||||||
HistoryView::PinnedMemento(_history, id.message));
|
HistoryView::PinnedMemento(
|
||||||
|
_history,
|
||||||
|
((!_migrated || id.message.channel)
|
||||||
|
? id.message.msg
|
||||||
|
: (id.message.msg - ServerMaxMsgId))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, button->lifetime());
|
}, button->lifetime());
|
||||||
|
@ -5560,10 +5562,7 @@ void HistoryWidget::hidePinnedMessage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_peer->canPinMessages()) {
|
if (_peer->canPinMessages()) {
|
||||||
Window::ToggleMessagePinned(
|
Window::ToggleMessagePinned(controller(), id.message, false);
|
||||||
controller(),
|
|
||||||
{ peerToChannel(_peer->id), id.message },
|
|
||||||
false);
|
|
||||||
} else {
|
} else {
|
||||||
const auto callback = [=] {
|
const auto callback = [=] {
|
||||||
if (_pinnedTracker) {
|
if (_pinnedTracker) {
|
||||||
|
@ -5877,7 +5876,9 @@ void HistoryWidget::handlePeerUpdate() {
|
||||||
updateHistoryGeometry();
|
updateHistoryGeometry();
|
||||||
if (_peer->isChat() && _peer->asChat()->noParticipantInfo()) {
|
if (_peer->isChat() && _peer->asChat()->noParticipantInfo()) {
|
||||||
session().api().requestFullPeer(_peer);
|
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);
|
session().api().requestFullPeer(_peer);
|
||||||
} else if (auto channel = _peer->asMegagroup()) {
|
} else if (auto channel = _peer->asMegagroup()) {
|
||||||
if (!channel->mgInfo->botStatus) {
|
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) {
|
return [=](Ui::MessageBarContent &&content) {
|
||||||
const auto item = session->data().message(id.message);
|
const auto item = session->data().message(id.message);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
|
@ -144,11 +144,11 @@ rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
|
||||||
|
|
||||||
rpl::producer<Ui::MessageBarContent> PinnedBarContent(
|
rpl::producer<Ui::MessageBarContent> PinnedBarContent(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
rpl::producer<PinnedBarId> id) {
|
rpl::producer<PinnedId> id) {
|
||||||
return std::move(
|
return std::move(
|
||||||
id
|
id
|
||||||
) | rpl::distinct_until_changed(
|
) | rpl::distinct_until_changed(
|
||||||
) | rpl::map([=](PinnedBarId id) {
|
) | rpl::map([=](PinnedId id) {
|
||||||
return ContentByItemId(
|
return ContentByItemId(
|
||||||
session,
|
session,
|
||||||
id.message
|
id.message
|
||||||
|
|
|
@ -28,25 +28,25 @@ namespace HistoryView {
|
||||||
FullMsgId id);
|
FullMsgId id);
|
||||||
|
|
||||||
enum class PinnedIdType;
|
enum class PinnedIdType;
|
||||||
struct PinnedBarId {
|
struct PinnedId {
|
||||||
FullMsgId message;
|
FullMsgId message;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int count = 1;
|
int count = 1;
|
||||||
|
|
||||||
bool operator<(const PinnedBarId &other) const {
|
bool operator<(const PinnedId &other) const {
|
||||||
return std::tie(message, index, count)
|
return std::tie(message, index, count)
|
||||||
< std::tie(other.message, other.index, other.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)
|
return std::tie(message, index, count)
|
||||||
== std::tie(other.message, other.index, other.count);
|
== std::tie(other.message, other.index, other.count);
|
||||||
}
|
}
|
||||||
bool operator!=(const PinnedBarId &other) const {
|
bool operator!=(const PinnedId &other) const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
[[nodiscard]] rpl::producer<Ui::MessageBarContent> PinnedBarContent(
|
[[nodiscard]] rpl::producer<Ui::MessageBarContent> PinnedBarContent(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
rpl::producer<PinnedBarId> id);
|
rpl::producer<PinnedId> id);
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history_item_components.h"
|
#include "history/history_item_components.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "boxes/confirm_box.h"
|
#include "boxes/confirm_box.h"
|
||||||
#include "data/data_peer_values.h"
|
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/layers/generic_box.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 "main/main_session.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_sparse_ids.h"
|
#include "data/data_sparse_ids.h"
|
||||||
#include "data/data_shared_media.h"
|
#include "data/data_shared_media.h"
|
||||||
|
#include "data/data_peer_values.h"
|
||||||
#include "storage/storage_account.h"
|
#include "storage/storage_account.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -90,7 +91,8 @@ PinnedWidget::PinnedWidget(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<History*> history)
|
not_null<History*> history)
|
||||||
: Window::SectionWidget(parent, controller)
|
: Window::SectionWidget(parent, controller)
|
||||||
, _history(history)
|
, _history(history->migrateToOrMe())
|
||||||
|
, _migratedPeer(_history->peer->migrateFrom())
|
||||||
, _topBar(this, controller)
|
, _topBar(this, controller)
|
||||||
, _topBarShadow(this)
|
, _topBarShadow(this)
|
||||||
, _scroll(std::make_unique<Ui::ScrollArea>(this, st::historyScroll, false))
|
, _scroll(std::make_unique<Ui::ScrollArea>(this, st::historyScroll, false))
|
||||||
|
@ -321,7 +323,8 @@ bool PinnedWidget::showInternal(
|
||||||
not_null<Window::SectionMemento*> memento,
|
not_null<Window::SectionMemento*> memento,
|
||||||
const Window::SectionShow ¶ms) {
|
const Window::SectionShow ¶ms) {
|
||||||
if (auto logMemento = dynamic_cast<PinnedMemento*>(memento.get())) {
|
if (auto logMemento = dynamic_cast<PinnedMemento*>(memento.get())) {
|
||||||
if (logMemento->getHistory() == history()) {
|
if (logMemento->getHistory() == history()
|
||||||
|
|| logMemento->getHistory()->migrateToOrMe() == history()) {
|
||||||
restoreState(logMemento);
|
restoreState(logMemento);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -358,7 +361,9 @@ void PinnedWidget::restoreState(not_null<PinnedMemento*> memento) {
|
||||||
_inner->restoreState(memento->list());
|
_inner->restoreState(memento->list());
|
||||||
if (const auto highlight = memento->getHighlightId()) {
|
if (const auto highlight = memento->getHighlightId()) {
|
||||||
const auto position = Data::MessagePosition{
|
const auto position = Data::MessagePosition{
|
||||||
.fullId = FullMsgId(_history->channelId(), highlight),
|
.fullId = ((highlight > 0 || !_migratedPeer)
|
||||||
|
? FullMsgId(_history->channelId(), highlight)
|
||||||
|
: FullMsgId(0, -highlight)),
|
||||||
.date = TimeId(0),
|
.date = TimeId(0),
|
||||||
};
|
};
|
||||||
_inner->showAroundPosition(position, [=] {
|
_inner->showAroundPosition(position, [=] {
|
||||||
|
@ -508,6 +513,28 @@ void PinnedWidget::listDeleteRequest() {
|
||||||
confirmDeleteSelected();
|
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(
|
rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
|
||||||
Data::MessagePosition aroundId,
|
Data::MessagePosition aroundId,
|
||||||
int limitBefore,
|
int limitBefore,
|
||||||
|
@ -516,15 +543,18 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
|
||||||
const auto messageId = aroundId.fullId.msg
|
const auto messageId = aroundId.fullId.msg
|
||||||
? aroundId.fullId.msg
|
? aroundId.fullId.msg
|
||||||
: (ServerMaxMsgId - 1);
|
: (ServerMaxMsgId - 1);
|
||||||
return SharedMediaViewer(
|
|
||||||
|
return SharedMediaMergedViewer(
|
||||||
&_history->session(),
|
&_history->session(),
|
||||||
Storage::SharedMediaKey(
|
SharedMediaMergedKey(
|
||||||
_history->peer->id,
|
SparseIdsMergedSlice::Key(
|
||||||
Storage::SharedMediaType::Pinned,
|
_history->peer->id,
|
||||||
messageId),
|
_migratedPeer ? _migratedPeer->id : 0,
|
||||||
|
messageId),
|
||||||
|
Storage::SharedMediaType::Pinned),
|
||||||
limitBefore,
|
limitBefore,
|
||||||
limitAfter
|
limitAfter
|
||||||
) | rpl::filter([=](const SparseIdsSlice &slice) {
|
) | rpl::filter([=](const SparseIdsMergedSlice &slice) {
|
||||||
const auto count = slice.fullCount();
|
const auto count = slice.fullCount();
|
||||||
if (!count.has_value()) {
|
if (!count.has_value()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -535,7 +565,7 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
|
||||||
controller()->showBackFromStack();
|
controller()->showBackFromStack();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}) | rpl::map([=](SparseIdsSlice &&slice) {
|
}) | rpl::map([=](SparseIdsMergedSlice &&slice) {
|
||||||
auto result = Data::MessagesSlice();
|
auto result = Data::MessagesSlice();
|
||||||
result.fullCount = slice.fullCount();
|
result.fullCount = slice.fullCount();
|
||||||
result.skippedAfter = slice.skippedAfter();
|
result.skippedAfter = slice.skippedAfter();
|
||||||
|
@ -543,10 +573,10 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
|
||||||
const auto count = slice.size();
|
const auto count = slice.size();
|
||||||
result.ids.reserve(count);
|
result.ids.reserve(count);
|
||||||
if (const auto msgId = slice.nearest(messageId)) {
|
if (const auto msgId = slice.nearest(messageId)) {
|
||||||
result.nearestToAround = FullMsgId(channelId, *msgId);
|
result.nearestToAround = *msgId;
|
||||||
}
|
}
|
||||||
for (auto i = 0; i != count; ++i) {
|
for (auto i = 0; i != count; ++i) {
|
||||||
result.ids.emplace_back(channelId, slice[i]);
|
result.ids.push_back(slice[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
|
@ -136,6 +136,7 @@ private:
|
||||||
void refreshClearButtonText();
|
void refreshClearButtonText();
|
||||||
|
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
PeerData *_migratedPeer = nullptr;
|
||||||
QPointer<ListWidget> _inner;
|
QPointer<ListWidget> _inner;
|
||||||
object_ptr<TopBarWidget> _topBar;
|
object_ptr<TopBarWidget> _topBar;
|
||||||
object_ptr<Ui::PlainShadow> _topBarShadow;
|
object_ptr<Ui::PlainShadow> _topBarShadow;
|
||||||
|
@ -155,9 +156,11 @@ private:
|
||||||
|
|
||||||
class PinnedMemento : public Window::SectionMemento {
|
class PinnedMemento : public Window::SectionMemento {
|
||||||
public:
|
public:
|
||||||
|
using UniversalMsgId = int32;
|
||||||
|
|
||||||
explicit PinnedMemento(
|
explicit PinnedMemento(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
MsgId highlightId = 0);
|
UniversalMsgId highlightId = 0);
|
||||||
|
|
||||||
object_ptr<Window::SectionWidget> createWidget(
|
object_ptr<Window::SectionWidget> createWidget(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
@ -172,13 +175,13 @@ public:
|
||||||
[[nodiscard]] not_null<ListMemento*> list() {
|
[[nodiscard]] not_null<ListMemento*> list() {
|
||||||
return &_list;
|
return &_list;
|
||||||
}
|
}
|
||||||
[[nodiscard]] MsgId getHighlightId() const {
|
[[nodiscard]] UniversalMsgId getHighlightId() const {
|
||||||
return _highlightId;
|
return _highlightId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
const MsgId _highlightId = 0;
|
const UniversalMsgId _highlightId = 0;
|
||||||
ListMemento _list;
|
ListMemento _list;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_shared_media.h"
|
#include "data/data_shared_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -26,13 +27,25 @@ constexpr auto kChangeViewerLimit = 2;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PinnedTracker::PinnedTracker(not_null<History*> history) : _history(history) {
|
PinnedTracker::PinnedTracker(not_null<History*> history)
|
||||||
_history->session().changes().peerFlagsValue(
|
: _history(history->migrateToOrMe())
|
||||||
_history->peer,
|
, _migratedPeer(_history->peer->migrateFrom()) {
|
||||||
Data::PeerUpdate::Flag::PinnedMessages
|
using namespace rpl::mappers;
|
||||||
) | rpl::map([=] {
|
const auto has = [&](PeerData *peer) -> rpl::producer<bool> {
|
||||||
return _history->peer->hasPinnedMessages();
|
auto &changes = _history->session().changes();
|
||||||
}) | rpl::distinct_until_changed(
|
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) {
|
) | rpl::start_with_next([=](bool has) {
|
||||||
if (has) {
|
if (has) {
|
||||||
refreshViewer();
|
refreshViewer();
|
||||||
|
@ -62,15 +75,17 @@ void PinnedTracker::refreshViewer() {
|
||||||
}
|
}
|
||||||
_dataLifetime.destroy();
|
_dataLifetime.destroy();
|
||||||
_viewerAroundId = _aroundId;
|
_viewerAroundId = _aroundId;
|
||||||
SharedMediaViewer(
|
SharedMediaMergedViewer(
|
||||||
&_history->peer->session(),
|
&_history->peer->session(),
|
||||||
Storage::SharedMediaKey(
|
SharedMediaMergedKey(
|
||||||
_history->peer->id,
|
SparseIdsMergedSlice::Key(
|
||||||
Storage::SharedMediaType::Pinned,
|
_history->peer->id,
|
||||||
_viewerAroundId),
|
_migratedPeer ? _migratedPeer->id : 0,
|
||||||
|
_viewerAroundId),
|
||||||
|
Storage::SharedMediaType::Pinned),
|
||||||
kLoadedLimit,
|
kLoadedLimit,
|
||||||
kLoadedLimit
|
kLoadedLimit
|
||||||
) | rpl::start_with_next([=](const SparseIdsSlice &result) {
|
) | rpl::start_with_next([=](const SparseIdsMergedSlice &result) {
|
||||||
_slice.fullCount = result.fullCount();
|
_slice.fullCount = result.fullCount();
|
||||||
_slice.skippedBefore = result.skippedBefore();
|
_slice.skippedBefore = result.skippedBefore();
|
||||||
_slice.skippedAfter = result.skippedAfter();
|
_slice.skippedAfter = result.skippedAfter();
|
||||||
|
@ -83,12 +98,23 @@ void PinnedTracker::refreshViewer() {
|
||||||
refreshCurrentFromSlice();
|
refreshCurrentFromSlice();
|
||||||
if (_slice.fullCount == 0) {
|
if (_slice.fullCount == 0) {
|
||||||
_history->peer->setHasPinnedMessages(false);
|
_history->peer->setHasPinnedMessages(false);
|
||||||
|
if (_migratedPeer) {
|
||||||
|
_migratedPeer->setHasPinnedMessages(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, _dataLifetime);
|
}, _dataLifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PinnedTracker::refreshCurrentFromSlice() {
|
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 empty = _slice.ids.empty();
|
||||||
const auto before = int(i - begin(_slice.ids));
|
const auto before = int(i - begin(_slice.ids));
|
||||||
const auto after = int(end(_slice.ids) - i);
|
const auto after = int(end(_slice.ids) - i);
|
||||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "history/view/history_view_pinned_bar.h"
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
@ -15,29 +17,16 @@ enum class LoadDirection : char;
|
||||||
|
|
||||||
namespace HistoryView {
|
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 {
|
class PinnedTracker final {
|
||||||
public:
|
public:
|
||||||
|
using UniversalMsgId = int32;
|
||||||
|
|
||||||
explicit PinnedTracker(not_null<History*> history);
|
explicit PinnedTracker(not_null<History*> history);
|
||||||
~PinnedTracker();
|
~PinnedTracker();
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<PinnedId> shownMessageId() const;
|
[[nodiscard]] rpl::producer<PinnedId> shownMessageId() const;
|
||||||
[[nodiscard]] PinnedId currentMessageId() const;
|
[[nodiscard]] PinnedId currentMessageId() const;
|
||||||
void trackAround(MsgId messageId);
|
void trackAround(UniversalMsgId messageId);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
[[nodiscard]] rpl::lifetime &lifetime() {
|
[[nodiscard]] rpl::lifetime &lifetime() {
|
||||||
|
@ -46,7 +35,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Slice {
|
struct Slice {
|
||||||
std::vector<MsgId> ids;
|
std::vector<FullMsgId> ids;
|
||||||
std::optional<int> fullCount;
|
std::optional<int> fullCount;
|
||||||
std::optional<int> skippedBefore;
|
std::optional<int> skippedBefore;
|
||||||
std::optional<int> skippedAfter;
|
std::optional<int> skippedAfter;
|
||||||
|
@ -56,12 +45,13 @@ private:
|
||||||
void refreshCurrentFromSlice();
|
void refreshCurrentFromSlice();
|
||||||
|
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
PeerData *_migratedPeer = nullptr;
|
||||||
|
|
||||||
rpl::variable<PinnedId> _current;
|
rpl::variable<PinnedId> _current;
|
||||||
rpl::lifetime _dataLifetime;
|
rpl::lifetime _dataLifetime;
|
||||||
|
|
||||||
MsgId _aroundId = 0;
|
UniversalMsgId _aroundId = 0;
|
||||||
MsgId _viewerAroundId = 0;
|
UniversalMsgId _viewerAroundId = 0;
|
||||||
Slice _slice;
|
Slice _slice;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
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::show(Box<ConfirmBox>(tr::lng_pinned_hide_all_sure(tr::now), tr::lng_pinned_hide_all_hide(tr::now), crl::guard(navigation, [=] {
|
||||||
Ui::hideLayer();
|
Ui::hideLayer();
|
||||||
auto &session = peer->session();
|
auto &session = peer->session();
|
||||||
const auto top = Data::ResolveTopPinnedId(peer);
|
const auto migrated = peer->migrateFrom();
|
||||||
if (top) {
|
const auto top = Data::ResolveTopPinnedId(peer, migrated);
|
||||||
session.settings().setHiddenPinnedMessageId(peer->id, top);
|
const auto universal = !top
|
||||||
|
? int32(0)
|
||||||
|
: (migrated && !top.channel)
|
||||||
|
? (top.msg - ServerMaxMsgId)
|
||||||
|
: top.msg;
|
||||||
|
if (universal) {
|
||||||
|
session.settings().setHiddenPinnedMessageId(peer->id, universal);
|
||||||
session.saveSettingsDelayed();
|
session.saveSettingsDelayed();
|
||||||
if (onHidden) {
|
if (onHidden) {
|
||||||
onHidden();
|
onHidden();
|
||||||
|
|
Loading…
Add table
Reference in a new issue