Implement local pinned bar hiding.

This commit is contained in:
John Preston 2020-10-12 12:41:05 +03:00
parent 67290eed58
commit 91a0416037
10 changed files with 167 additions and 131 deletions

View file

@ -166,6 +166,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_pinned_quiz" = "Pinned quiz"; "lng_pinned_quiz" = "Pinned quiz";
"lng_pinned_unpin_sure" = "Would you like to unpin this message?"; "lng_pinned_unpin_sure" = "Would you like to unpin this message?";
"lng_pinned_pin_sure" = "Would you like to pin this message?"; "lng_pinned_pin_sure" = "Would you like to pin this message?";
"lng_pinned_pin_old_sure" = "Do you want to pin an older message while leaving a more recent one pinned?";
"lng_pinned_pin" = "Pin"; "lng_pinned_pin" = "Pin";
"lng_pinned_unpin" = "Unpin"; "lng_pinned_unpin" = "Unpin";
"lng_pinned_notify" = "Notify all members"; "lng_pinned_notify" = "Notify all members";

View file

@ -448,7 +448,7 @@ PinMessageBox::PinMessageBox(
, _text( , _text(
this, this,
(_pinningOld (_pinningOld
? "Do you want to pin an older message while leaving a more recent one pinned?" // #TODO pinned ? tr::lng_pinned_pin_old_sure(tr::now)
: tr::lng_pinned_pin_sure(tr::now)), : tr::lng_pinned_pin_sure(tr::now)),
st::boxLabel) { st::boxLabel) {
} }

View file

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h" #include "apiwrap.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_session_settings.h"
#include "main/main_account.h" #include "main/main_account.h"
#include "main/main_domain.h" #include "main/main_domain.h"
#include "main/main_app_config.h" #include "main/main_app_config.h"
@ -469,14 +470,12 @@ void PeerData::ensurePinnedMessagesCreated() {
if (!_pinnedMessages) { if (!_pinnedMessages) {
_pinnedMessages = std::make_unique<Data::PinnedMessages>( _pinnedMessages = std::make_unique<Data::PinnedMessages>(
peerToChannel(id)); peerToChannel(id));
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
} }
} }
void PeerData::removeEmptyPinnedMessages() { void PeerData::removeEmptyPinnedMessages() {
if (_pinnedMessages && _pinnedMessages->empty()) { if (_pinnedMessages && _pinnedMessages->empty()) {
_pinnedMessages = nullptr; _pinnedMessages = nullptr;
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
} }
} }
@ -489,18 +488,30 @@ bool PeerData::messageIdTooSmall(MsgId messageId) const {
void PeerData::setTopPinnedMessageId(MsgId messageId) { void PeerData::setTopPinnedMessageId(MsgId messageId) {
if (messageIdTooSmall(messageId)) { if (messageIdTooSmall(messageId)) {
clearPinnedMessages();
return; return;
} }
if (session().settings().hiddenPinnedMessageId(id) != messageId) {
session().settings().setHiddenPinnedMessageId(id, 0);
session().saveSettingsDelayed();
}
ensurePinnedMessagesCreated(); ensurePinnedMessagesCreated();
_pinnedMessages->setTopId(messageId); _pinnedMessages->setTopId(messageId);
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
} }
void PeerData::clearPinnedMessages(MsgId lessThanId) { void PeerData::clearPinnedMessages(MsgId lessThanId) {
if (lessThanId == ServerMaxMsgId
&& session().settings().hiddenPinnedMessageId(id) != 0) {
session().settings().setHiddenPinnedMessageId(id, 0);
session().saveSettingsDelayed();
}
if (!_pinnedMessages) { if (!_pinnedMessages) {
return; return;
} }
_pinnedMessages->clearLessThanId(lessThanId); _pinnedMessages->clearLessThanId(lessThanId);
removeEmptyPinnedMessages(); removeEmptyPinnedMessages();
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
} }
void PeerData::addPinnedMessage(MsgId messageId) { void PeerData::addPinnedMessage(MsgId messageId) {
@ -509,6 +520,7 @@ void PeerData::addPinnedMessage(MsgId messageId) {
} }
ensurePinnedMessagesCreated(); ensurePinnedMessagesCreated();
_pinnedMessages->add(messageId); _pinnedMessages->add(messageId);
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
} }
void PeerData::addPinnedSlice( void PeerData::addPinnedSlice(
@ -532,6 +544,7 @@ void PeerData::addPinnedSlice(
} }
ensurePinnedMessagesCreated(); ensurePinnedMessagesCreated();
_pinnedMessages->add(std::move(ids), noSkipRange, std::nullopt); _pinnedMessages->add(std::move(ids), noSkipRange, std::nullopt);
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
} }
void PeerData::removePinnedMessage(MsgId messageId) { void PeerData::removePinnedMessage(MsgId messageId) {
@ -540,6 +553,7 @@ void PeerData::removePinnedMessage(MsgId messageId) {
} }
_pinnedMessages->remove(messageId); _pinnedMessages->remove(messageId);
removeEmptyPinnedMessages(); removeEmptyPinnedMessages();
session().changes().peerUpdated(this, UpdateFlag::PinnedMessage);
} }
bool PeerData::canExportChatHistory() const { bool PeerData::canExportChatHistory() const {

View file

@ -1005,9 +1005,12 @@ void History::applyServiceChanges(
case mtpc_messageActionPinMessage: { case mtpc_messageActionPinMessage: {
if (const auto replyTo = data.vreply_to()) { if (const auto replyTo = data.vreply_to()) {
replyTo->match([&](const MTPDmessageReplyHeader &data) { replyTo->match([&](const MTPDmessageReplyHeader &data) {
const auto id = data.vreply_to_msg_id().v;
if (item) { if (item) {
//item->history()->peer->setTopPinnedMessageId( // #TODO pinned item->history()->peer->addPinnedSlice(
// data.vreply_to_msg_id().v); { id },
{ id, ServerMaxMsgId },
std::nullopt);
} }
}); });
} }

View file

@ -563,6 +563,7 @@ HistoryWidget::HistoryWidget(
| UpdateFlag::ChannelLinkedChat | UpdateFlag::ChannelLinkedChat
| UpdateFlag::Slowmode | UpdateFlag::Slowmode
| UpdateFlag::BotStartToken | UpdateFlag::BotStartToken
| UpdateFlag::PinnedMessage
) | rpl::filter([=](const Data::PeerUpdate &update) { ) | rpl::filter([=](const Data::PeerUpdate &update) {
return (update.peer.get() == _peer); return (update.peer.get() == _peer);
}) | rpl::map([](const Data::PeerUpdate &update) { }) | rpl::map([](const Data::PeerUpdate &update) {
@ -603,6 +604,9 @@ HistoryWidget::HistoryWidget(
| UpdateFlag::ChannelLinkedChat)) { | UpdateFlag::ChannelLinkedChat)) {
handlePeerUpdate(); handlePeerUpdate();
} }
if (_pinnedTracker && (flags & UpdateFlag::PinnedMessage)) {
checkPinnedBarState();
}
}, lifetime()); }, lifetime());
rpl::merge( rpl::merge(
@ -5211,12 +5215,50 @@ void HistoryWidget::setupPinnedTracker() {
Expects(_history != nullptr); Expects(_history != nullptr);
_pinnedTracker = std::make_unique<HistoryView::PinnedTracker>(_history); _pinnedTracker = std::make_unique<HistoryView::PinnedTracker>(_history);
_pinnedBar = nullptr;
checkPinnedBarState();
}
void HistoryWidget::checkPinnedBarState() {
Expects(_pinnedTracker != nullptr);
const auto hiddenId = _peer->canPinMessages()
? MsgId(0)
: session().settings().hiddenPinnedMessageId(_peer->id);
const auto currentPinnedId = _peer->topPinnedMessageId();
if (currentPinnedId == hiddenId) {
if (_pinnedBar) {
_pinnedTracker->reset();
auto qobject = base::unique_qptr{
Ui::WrapAsQObject(this, std::move(_pinnedBar)).get()
};
auto destroyer = [this, object = std::move(qobject)]() mutable {
object = nullptr;
updateHistoryGeometry();
updateControlsGeometry();
};
base::call_delayed(
st::defaultMessageBar.duration,
this,
std::move(destroyer));
}
return;
}
if (_pinnedBar || !currentPinnedId) {
return;
}
auto shown = _pinnedTracker->shownMessageId(
) | rpl::map([=](HistoryView::PinnedId messageId) {
return HistoryView::PinnedBarId{
FullMsgId{ peerToChannel(_peer->id), messageId.message },
messageId.type
};
});
_pinnedBar = std::make_unique<HistoryView::PinnedBar>( _pinnedBar = std::make_unique<HistoryView::PinnedBar>(
this, this,
&session(), &session(),
_pinnedTracker->shownMessageId() | rpl::map([=](MsgId messageId) { std::move(shown),
return FullMsgId{ peerToChannel(_peer->id), messageId };
}),
true); true);
_pinnedBar->closeClicks( _pinnedBar->closeClicks(
@ -5233,68 +5275,13 @@ void HistoryWidget::setupPinnedTracker() {
updateControlsGeometry(); updateControlsGeometry();
_topDelta = 0; _topDelta = 0;
}, _pinnedBar->lifetime()); }, _pinnedBar->lifetime());
orderWidgets(); orderWidgets();
if (_a_show.animating()) { if (_a_show.animating()) {
_pinnedBar->hide(); _pinnedBar->hide();
} }
} }
//
//bool HistoryWidget::pinnedMsgVisibilityUpdated() {
// auto result = false;
// auto pinnedId = _pinnedId;
// if (pinnedId && !_peer->canPinMessages()) {
// const auto hiddenId = session().settings().hiddenPinnedMessageId(
// _peer->id);
// if (hiddenId == pinnedId.msg) {
// pinnedId = FullMsgId();
// } else if (hiddenId) {
// session().settings().setHiddenPinnedMessageId(_peer->id, 0);
// session().saveSettings();
// }
// }
// if (pinnedId) {
// if (!_pinnedBar) {
// _pinnedBar = std::make_unique<PinnedBar>(pinnedId.msg, this);
// if (_a_show.animating()) {
// _pinnedBar->cancel->hide();
// _pinnedBar->bar->widget()->hide();
// _pinnedBar->shadow->hide();
// } else {
// _pinnedBar->cancel->show();
// _pinnedBar->bar->widget()->show();
// _pinnedBar->shadow->show();
// }
// _pinnedBar->cancel->addClickHandler([=] {
// hidePinnedMessage();
// });
// orderWidgets();
//
// updatePinnedBar();
// result = true;
//
// const auto barTop = unreadBarTop();
// if (!barTop || _scroll->scrollTop() != *barTop) {
// synteticScrollToY(_scroll->scrollTop() + st::historyReplyHeight);
// }
// } else if (_pinnedBar->msgId != pinnedId.msg) {
// _pinnedBar->msgId = pinnedId.msg;
// _pinnedBar->msg = nullptr;
// updatePinnedBar();
// }
// if (!_pinnedBar->msg) {
// requestMessageData(_pinnedBar->msgId);
// }
// } else if (_pinnedBar) {
// destroyPinnedBar();
// result = true;
// const auto barTop = unreadBarTop();
// if (!barTop || _scroll->scrollTop() != *barTop) {
// synteticScrollToY(_scroll->scrollTop() - st::historyReplyHeight);
// }
// updateControlsGeometry();
// }
// return result;
//}
void HistoryWidget::requestMessageData(MsgId msgId) { void HistoryWidget::requestMessageData(MsgId msgId) {
const auto callback = [=](ChannelData *channel, MsgId msgId) { const auto callback = [=](ChannelData *channel, MsgId msgId) {
@ -5574,25 +5561,25 @@ void HistoryWidget::UnpinMessage(not_null<PeerData*> peer, MsgId msgId) {
} }
void HistoryWidget::hidePinnedMessage() { void HistoryWidget::hidePinnedMessage() {
//const auto pinnedId = _pinnedId; // #TODO pinned Expects(_pinnedBar != nullptr);
//if (!pinnedId) {
// if (pinnedMsgVisibilityUpdated()) {
// updateControlsGeometry();
// update();
// }
// return;
//}
//if (_peer->canPinMessages()) { const auto id = _pinnedTracker->currentMessageId();
// unpinMessage(pinnedId); if (!id.message) {
//} else { return;
// session().settings().setHiddenPinnedMessageId(_peer->id, pinnedId.msg); }
// session().saveSettings(); if (_peer->canPinMessages()) {
// if (pinnedMsgVisibilityUpdated()) { unpinMessage({ peerToChannel(_peer->id), id.message });
// updateControlsGeometry(); } else {
// update(); const auto top = _peer->topPinnedMessageId();
// } if (top) {
//} session().settings().setHiddenPinnedMessageId(_peer->id, top);
session().saveSettingsDelayed();
checkPinnedBarState();
} else {
session().api().requestFullPeer(_peer);
}
}
} }
bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const { bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const {
@ -6373,16 +6360,6 @@ void HistoryWidget::drawRecording(Painter &p, float64 recordActive) {
} }
// //
//void HistoryWidget::drawPinnedBar(Painter &p) { //void HistoryWidget::drawPinnedBar(Painter &p) {
// Expects(_pinnedBar != nullptr);
//
// auto top = _topBar->bottomNoMargins();
// p.fillRect(myrtlrect(0, top, width(), st::historyReplyHeight), st::historyPinnedBg);
//
// top += st::msgReplyPadding.top();
// QRect rbar(myrtlrect(st::msgReplyBarSkip + st::msgReplyBarPos.x(), top + st::msgReplyBarPos.y(), st::msgReplyBarSize.width(), st::msgReplyBarSize.height()));
// p.fillRect(rbar, st::msgInReplyBarColor);
//
// //int32 left = st::msgReplyBarSkip + st::msgReplyBarSkip;
// //if (_pinnedBar->msg) { // //if (_pinnedBar->msg) {
// // const auto media = _pinnedBar->msg->media(); // // const auto media = _pinnedBar->msg->media();
// // if (media && media->hasReplyPreview()) { // // if (media && media->hasReplyPreview()) {
@ -6392,22 +6369,6 @@ void HistoryWidget::drawRecording(Painter &p, float64 recordActive) {
// // } // // }
// // left += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); // // left += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
// // } // // }
// // p.setPen(st::historyReplyNameFg);
// // p.setFont(st::msgServiceNameFont);
// // const auto poll = media ? media->poll() : nullptr;
// // const auto pinnedHeader = (_pinnedBar->msgId < _peer->topPinnedMessageId())
// // ? tr::lng_pinned_previous(tr::now)
// // : !poll
// // ? tr::lng_pinned_message(tr::now)
// // : poll->quiz()
// // ? tr::lng_pinned_quiz(tr::now)
// // : tr::lng_pinned_poll(tr::now);
// // p.drawText(left, top + st::msgServiceNameFont->ascent, pinnedHeader);
//
// // p.setPen(st::historyComposeAreaFg);
// // p.setTextPalette(st::historyComposeAreaPalette);
// // _pinnedBar->text.drawElided(p, left, top + st::msgServiceNameFont->height, width() - left - _pinnedBar->cancel->width() - st::msgReplyPadding.right());
// // p.restoreTextPalette();
// //} else { // //} else {
// // p.setFont(st::msgDateFont); // // p.setFont(st::msgDateFont);
// // p.setPen(st::historyComposeAreaFgService); // // p.setPen(st::historyComposeAreaFgService);

View file

@ -486,6 +486,7 @@ private:
void updatePinnedViewer(); void updatePinnedViewer();
void setupPinnedTracker(); void setupPinnedTracker();
void checkPinnedBarState();
void sendInlineResult( void sendInlineResult(
not_null<InlineBots::Result*> result, not_null<InlineBots::Result*> result,

View file

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_poll.h" #include "data/data_poll.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "history/view/history_view_pinned_tracker.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h" #include "history/history.h"
#include "apiwrap.h" #include "apiwrap.h"
@ -23,7 +24,8 @@ namespace HistoryView {
namespace { namespace {
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem( [[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem(
not_null<HistoryItem*> item) { not_null<HistoryItem*> item,
PinnedIdType type) {
return item->history()->session().changes().messageFlagsValue( return item->history()->session().changes().messageFlagsValue(
item, item,
Data::MessageUpdate::Flag::Edited Data::MessageUpdate::Flag::Edited
@ -32,7 +34,9 @@ namespace {
const auto poll = media ? media->poll() : nullptr; const auto poll = media ? media->poll() : nullptr;
return Ui::MessageBarContent{ return Ui::MessageBarContent{
.id = item->id, .id = item->id,
.title = ((item->id < item->history()->peer->topPinnedMessageId()) .title = ((type == PinnedIdType::First)
? "First message"
: (type == PinnedIdType::Middle)
? tr::lng_pinned_previous(tr::now) ? tr::lng_pinned_previous(tr::now)
: !poll : !poll
? tr::lng_pinned_message(tr::now) ? tr::lng_pinned_message(tr::now)
@ -46,12 +50,12 @@ namespace {
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId( [[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId(
not_null<Main::Session*> session, not_null<Main::Session*> session,
FullMsgId id, PinnedBarId id,
bool alreadyLoaded = false) { bool alreadyLoaded = false) {
if (!id) { if (!id.message) {
return rpl::single(Ui::MessageBarContent()); return rpl::single(Ui::MessageBarContent());
} else if (const auto item = session->data().message(id)) { } else if (const auto item = session->data().message(id.message)) {
return ContentByItem(item); return ContentByItem(item, id.type);
} else if (alreadyLoaded) { } else if (alreadyLoaded) {
return rpl::single(Ui::MessageBarContent()); // Deleted message?.. return rpl::single(Ui::MessageBarContent()); // Deleted message?..
} }
@ -59,13 +63,13 @@ namespace {
consumer.put_next(Ui::MessageBarContent{ consumer.put_next(Ui::MessageBarContent{
.text = tr::lng_contacts_loading(tr::now), .text = tr::lng_contacts_loading(tr::now),
}); });
const auto channel = id.channel const auto channel = id.message.channel
? session->data().channel(id.channel).get() ? session->data().channel(id.message.channel).get()
: nullptr; : nullptr;
const auto callback = [=](ChannelData *channel, MsgId id) { const auto callback = [=](ChannelData *channel, MsgId id) {
consumer.put_done(); consumer.put_done();
}; };
session->api().requestMessageData(channel, id.msg, callback); session->api().requestMessageData(channel, id.message.msg, callback);
return rpl::lifetime(); return rpl::lifetime();
}); });
return std::move( return std::move(
@ -80,7 +84,7 @@ namespace {
PinnedBar::PinnedBar( PinnedBar::PinnedBar(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Main::Session*> session, not_null<Main::Session*> session,
rpl::producer<FullMsgId> itemId, rpl::producer<PinnedBarId> itemId,
bool withClose) bool withClose)
: _wrap(parent, object_ptr<Ui::RpWidget>(parent)) : _wrap(parent, object_ptr<Ui::RpWidget>(parent))
, _close(withClose , _close(withClose
@ -101,7 +105,7 @@ PinnedBar::PinnedBar(
rpl::duplicate( rpl::duplicate(
itemId itemId
) | rpl::distinct_until_changed( ) | rpl::distinct_until_changed(
) | rpl::map([=](FullMsgId id) { ) | rpl::map([=](PinnedBarId id) {
return ContentByItemId(session, id); return ContentByItemId(session, id);
}) | rpl::flatten_latest( }) | rpl::flatten_latest(
) | rpl::filter([=](const Ui::MessageBarContent &content) { ) | rpl::filter([=](const Ui::MessageBarContent &content) {
@ -119,15 +123,18 @@ PinnedBar::PinnedBar(
std::move( std::move(
itemId itemId
) | rpl::map([=](FullMsgId id) { ) | rpl::map([=](PinnedBarId id) {
return !id; return !id.message;
}) | rpl::start_with_next([=](bool hidden) { }) | rpl::start_with_next_done([=](bool hidden) {
_shouldBeShown = !hidden; _shouldBeShown = !hidden;
if (!_forceHidden) { if (!_forceHidden) {
_wrap.toggle(_shouldBeShown, anim::type::normal); _wrap.toggle(_shouldBeShown, anim::type::normal);
} else if (!_shouldBeShown) { } else if (!_shouldBeShown) {
_bar = nullptr; _bar = nullptr;
} }
}, [=] {
_forceHidden = true;
_wrap.toggle(false, anim::type::normal);
}, lifetime()); }, lifetime());
} }

View file

@ -21,12 +21,25 @@ class PlainShadow;
namespace HistoryView { namespace HistoryView {
enum class PinnedIdType;
struct PinnedBarId {
FullMsgId message;
PinnedIdType type = PinnedIdType();
bool operator<(const PinnedBarId &other) const {
return std::tie(message, type) < std::tie(other.message, other.type);
}
bool operator==(const PinnedBarId &other) const {
return std::tie(message, type) == std::tie(other.message, other.type);
}
};
class PinnedBar final { class PinnedBar final {
public: public:
PinnedBar( PinnedBar(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Main::Session*> session, not_null<Main::Session*> session,
rpl::producer<FullMsgId> itemId, rpl::producer<PinnedBarId> itemId,
bool withClose = false); bool withClose = false);
void show(); void show();

View file

@ -40,15 +40,23 @@ PinnedTracker::~PinnedTracker() {
_history->owner().histories().cancelRequest(_afterRequestId); _history->owner().histories().cancelRequest(_afterRequestId);
} }
rpl::producer<MsgId> PinnedTracker::shownMessageId() const { rpl::producer<PinnedId> PinnedTracker::shownMessageId() const {
return _current.value(); return _current.value();
} }
void PinnedTracker::reset() {
_current.reset(currentMessageId());
}
PinnedId PinnedTracker::currentMessageId() const {
return _current.current();
}
void PinnedTracker::refreshData() { void PinnedTracker::refreshData() {
const auto now = _history->peer->currentPinnedMessages(); const auto now = _history->peer->currentPinnedMessages();
if (!now) { if (!now) {
_dataLifetime.destroy(); _dataLifetime.destroy();
_current = MsgId(0); _current = PinnedId();
} else if (_data.get() != now) { } else if (_data.get() != now) {
_dataLifetime.destroy(); _dataLifetime.destroy();
_data = now; _data = now;
@ -65,7 +73,7 @@ void PinnedTracker::trackAround(MsgId messageId) {
_dataLifetime.destroy(); _dataLifetime.destroy();
_aroundId = messageId; _aroundId = messageId;
if (!_aroundId) { if (!_aroundId) {
_current = MsgId(0); _current = PinnedId();
} else if (const auto now = _data.get()) { } else if (const auto now = _data.get()) {
setupViewer(now); setupViewer(now);
} }
@ -90,10 +98,19 @@ void PinnedTracker::setupViewer(not_null<Data::PinnedMessages*> data) {
Data::LoadDirection::After, Data::LoadDirection::After,
empty ? _aroundId : snapshot.ids.back()); empty ? _aroundId : snapshot.ids.back());
} }
if (snapshot.ids.empty()) {
_current = PinnedId();
return;
}
const auto type = (!after && (snapshot.skippedAfter == 0))
? PinnedIdType::Last
: (before < 2 && (snapshot.skippedBefore == 0))
? PinnedIdType::First
: PinnedIdType::Middle;
if (i != begin(snapshot.ids)) { if (i != begin(snapshot.ids)) {
_current = *(i - 1); _current = PinnedId{ *(i - 1), type };
} else if (snapshot.skippedBefore == 0) { } else if (snapshot.skippedBefore == 0) {
_current = 0; _current = PinnedId{ snapshot.ids.front(), type };
} }
}, _dataLifetime); }, _dataLifetime);
} }

View file

@ -16,13 +16,32 @@ enum class LoadDirection : char;
namespace HistoryView { namespace HistoryView {
enum class PinnedIdType {
First,
Middle,
Last,
};
struct PinnedId {
MsgId message = 0;
PinnedIdType type = PinnedIdType::Middle;
bool operator<(const PinnedId &other) const {
return std::tie(message, type) < std::tie(other.message, other.type);
}
bool operator==(const PinnedId &other) const {
return std::tie(message, type) == std::tie(other.message, other.type);
}
};
class PinnedTracker final { class PinnedTracker final {
public: public:
explicit PinnedTracker(not_null<History*> history); explicit PinnedTracker(not_null<History*> history);
~PinnedTracker(); ~PinnedTracker();
[[nodiscard]] rpl::producer<MsgId> shownMessageId() const; [[nodiscard]] rpl::producer<PinnedId> shownMessageId() const;
[[nodiscard]] PinnedId currentMessageId() const;
void trackAround(MsgId messageId); void trackAround(MsgId messageId);
void reset();
private: private:
void refreshData(); void refreshData();
@ -36,7 +55,7 @@ private:
const not_null<History*> _history; const not_null<History*> _history;
base::weak_ptr<Data::PinnedMessages> _data; base::weak_ptr<Data::PinnedMessages> _data;
rpl::variable<MsgId> _current = MsgId(); rpl::variable<PinnedId> _current;
rpl::lifetime _dataLifetime; rpl::lifetime _dataLifetime;
MsgId _aroundId = 0; MsgId _aroundId = 0;