diff --git a/Telegram/Resources/icons/pinned_show_all.png b/Telegram/Resources/icons/pinned_show_all.png new file mode 100644 index 000000000..af6e182ad Binary files /dev/null and b/Telegram/Resources/icons/pinned_show_all.png differ diff --git a/Telegram/Resources/icons/pinned_show_all@2x.png b/Telegram/Resources/icons/pinned_show_all@2x.png new file mode 100644 index 000000000..f00311c0c Binary files /dev/null and b/Telegram/Resources/icons/pinned_show_all@2x.png differ diff --git a/Telegram/Resources/icons/pinned_show_all@3x.png b/Telegram/Resources/icons/pinned_show_all@3x.png new file mode 100644 index 000000000..09e63eb9a Binary files /dev/null and b/Telegram/Resources/icons/pinned_show_all@3x.png differ diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 44d0fe991..c066a84c9 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -5239,10 +5239,22 @@ void HistoryWidget::checkPinnedBarState() { messageId.count }; }); + auto barContent = HistoryView::PinnedBarContent( + &session(), + std::move(shown)); _pinnedBar = std::make_unique( this, - HistoryView::PinnedBarContent(&session(), std::move(shown)), - true); + std::move(barContent)); + Info::Profile::SharedMediaCountValue( + _peer, + nullptr, + Storage::SharedMediaType::Pinned + ) | rpl::map([=](int count) { + return (count > 1); + }) | rpl::distinct_until_changed( + ) | rpl::start_with_next([=](bool many) { + refreshPinnedBarButton(many); + }, _pinnedBar->lifetime()); rpl::single( rpl::empty_value() @@ -5259,18 +5271,11 @@ void HistoryWidget::checkPinnedBarState() { }); }, _pinnedBar->lifetime()); - _pinnedBar->closeClicks( - ) | rpl::start_with_next([=] { - hidePinnedMessage(); - }, _pinnedBar->lifetime()); - _pinnedBar->barClicks( ) | rpl::start_with_next([=] { const auto id = _pinnedTracker->currentMessageId(); if (id.message) { - controller()->showSection( - HistoryView::PinnedMemento(_history, id.message)); - //Ui::showPeerHistory(_peer, id.message); + Ui::showPeerHistory(_peer, id.message); } }, _pinnedBar->lifetime()); @@ -5291,6 +5296,26 @@ void HistoryWidget::checkPinnedBarState() { } } +void HistoryWidget::refreshPinnedBarButton(bool many) { + const auto close = !many; + auto button = object_ptr( + this, + close ? st::historyReplyCancel : st::historyPinnedShowAll); + button->clicks( + ) | rpl::start_with_next([=] { + if (close) { + hidePinnedMessage(); + } else { + const auto id = _pinnedTracker->currentMessageId(); + if (id.message) { + controller()->showSection( + HistoryView::PinnedMemento(_history, id.message)); + } + } + }, button->lifetime()); + _pinnedBar->setRightButton(std::move(button)); +} + void HistoryWidget::requestMessageData(MsgId msgId) { const auto callback = [=](ChannelData *channel, MsgId msgId) { messageDataReceived(channel, msgId); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 1a56edba1..4d72f0f32 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -481,6 +481,7 @@ private: void updatePinnedViewer(); void setupPinnedTracker(); void checkPinnedBarState(); + void refreshPinnedBarButton(bool many); void sendInlineResult( not_null result, diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 5c9e86e6e..92f63e34c 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -56,6 +56,19 @@ namespace { } // namespace +PinnedMemento::PinnedMemento( + not_null history, + MsgId highlightId) +: _history(history) +, _highlightId(highlightId) { + _list.setAroundPosition({ + .fullId = FullMsgId( + history->channelId(), + highlightId), + .date = TimeId(0), + }); +} + object_ptr PinnedMemento::createWidget( QWidget *parent, not_null controller, diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index b355e7788..09935471c 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -148,12 +148,9 @@ private: class PinnedMemento : public Window::SectionMemento { public: - PinnedMemento( + explicit PinnedMemento( not_null history, - MsgId highlightId = 0) - : _history(history) - , _highlightId(highlightId) { - } + MsgId highlightId = 0); object_ptr createWidget( QWidget *parent, diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp index 7600c5bfd..5a3673181 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.cpp @@ -12,19 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer.h" #include "data/data_channel.h" #include "data/data_session.h" -#include "data/data_histories.h" #include "main/main_session.h" #include "storage/storage_facade.h" #include "storage/storage_shared_media.h" #include "history/history.h" #include "history/history_item.h" -#include "apiwrap.h" namespace HistoryView { -namespace { +namespace{ constexpr auto kLoadedLimit = 4; -constexpr auto kPerPage = 40; } // namespace @@ -37,10 +34,7 @@ PinnedTracker::PinnedTracker(not_null history) : _history(history) { }, _lifetime); } -PinnedTracker::~PinnedTracker() { - _history->owner().histories().cancelRequest(_beforeRequestId); - _history->owner().histories().cancelRequest(_afterRequestId); -} +PinnedTracker::~PinnedTracker() = default; rpl::producer PinnedTracker::shownMessageId() const { return _current.value(); @@ -90,16 +84,6 @@ void PinnedTracker::setupViewer(not_null data) { const auto empty = snapshot.ids.empty(); const auto before = (i - begin(snapshot.ids)); const auto after = (end(snapshot.ids) - i); - //if (before < kLoadedLimit && !snapshot.skippedBefore) { - // load( - // Data::LoadDirection::Before, - // empty ? _aroundId : snapshot.ids.front()); - //} - //if (after < kLoadedLimit && !snapshot.skippedAfter) { - // load( - // Data::LoadDirection::After, - // empty ? _aroundId : snapshot.ids.back()); - //} if (snapshot.ids.empty()) { _current = PinnedId(); return; @@ -119,156 +103,5 @@ void PinnedTracker::setupViewer(not_null data) { } }, _dataLifetime); } -// -//void PinnedTracker::load(Data::LoadDirection direction, MsgId id) { -// const auto requestId = (direction == Data::LoadDirection::Before) -// ? &_beforeRequestId -// : &_afterRequestId; -// const auto aroundId = (direction == Data::LoadDirection::Before) -// ? &_beforeId -// : &_afterId; -// if (*requestId) { -// if (*aroundId == id) { -// return; -// } -// _history->owner().histories().cancelRequest(*requestId); -// } -// *aroundId = id; -// const auto send = [=](Fn finish) { -// const auto offsetId = [&] { -// switch (direction) { -// case Data::LoadDirection::Before: return id; -// case Data::LoadDirection::After: return id + 1; -// } -// Unexpected("Direction in PinnedTracker::load"); -// }(); -// const auto addOffset = [&] { -// switch (direction) { -// case Data::LoadDirection::Before: return 0; -// case Data::LoadDirection::After: return -kPerPage; -// } -// Unexpected("Direction in PinnedTracker::load"); -// }(); -// return _history->session().api().request(MTPmessages_Search( -// MTP_flags(0), -// _history->peer->input, -// MTP_string(QString()), -// MTP_inputPeerEmpty(), -// MTPint(), // top_msg_id -// MTP_inputMessagesFilterPinned(), -// MTP_int(0), -// MTP_int(0), -// MTP_int(offsetId), -// MTP_int(addOffset), -// MTP_int(kPerPage), -// MTP_int(0), // max_id -// MTP_int(0), // min_id -// MTP_int(0) // hash -// )).done([=](const MTPmessages_Messages &result) { -// *aroundId = 0; -// *requestId = 0; -// finish(); -// -// apply(direction, id, result); -// }).fail([=](const RPCError &error) { -// *aroundId = 0; -// *requestId = 0; -// finish(); -// }).send(); -// }; -// _beforeRequestId = _history->owner().histories().sendRequest( -// _history, -// Data::Histories::RequestType::History, -// send); -//} -// -//void PinnedTracker::apply( -// Data::LoadDirection direction, -// MsgId aroundId, -// const MTPmessages_Messages &result) { -// auto noSkipRange = MsgRange{ aroundId, aroundId }; -// auto fullCount = std::optional(); -// auto messages = [&] { -// switch (result.type()) { -// case mtpc_messages_messages: { -// auto &d = result.c_messages_messages(); -// _history->owner().processUsers(d.vusers()); -// _history->owner().processChats(d.vchats()); -// fullCount = d.vmessages().v.size(); -// return &d.vmessages().v; -// } break; -// -// case mtpc_messages_messagesSlice: { -// auto &d = result.c_messages_messagesSlice(); -// _history->owner().processUsers(d.vusers()); -// _history->owner().processChats(d.vchats()); -// fullCount = d.vcount().v; -// return &d.vmessages().v; -// } break; -// -// case mtpc_messages_channelMessages: { -// auto &d = result.c_messages_channelMessages(); -// if (auto channel = _history->peer->asChannel()) { -// channel->ptsReceived(d.vpts().v); -// } else { -// LOG(("API Error: received messages.channelMessages when " -// "no channel was passed! (PinnedTracker::apply)")); -// } -// _history->owner().processUsers(d.vusers()); -// _history->owner().processChats(d.vchats()); -// fullCount = d.vcount().v; -// return &d.vmessages().v; -// } break; -// -// case mtpc_messages_messagesNotModified: { -// LOG(("API Error: received messages.messagesNotModified! " -// "(PinnedTracker::apply)")); -// return (const QVector*)nullptr; -// } break; -// } -// Unexpected("messages.Messages type in PinnedTracker::apply."); -// }(); -// -// if (!messages) { -// return; -// } -// -// const auto addType = NewMessageType::Existing; -// auto list = std::vector(); -// list.reserve(messages->size()); -// for (const auto &message : *messages) { -// const auto item = _history->owner().addNewMessage( -// message, -// MTPDmessage_ClientFlags(), -// addType); -// if (item) { -// const auto itemId = item->id; -// if (item->isPinned()) { -// list.push_back(itemId); -// } -// accumulate_min(noSkipRange.from, itemId); -// accumulate_max(noSkipRange.till, itemId); -// } -// } -// if (aroundId && list.empty()) { -// noSkipRange = [&]() -> MsgRange { -// switch (direction) { -// case Data::LoadDirection::Before: // All old loaded. -// return { 0, noSkipRange.till }; -// case Data::LoadDirection::Around: // All loaded. -// return { 0, ServerMaxMsgId }; -// case Data::LoadDirection::After: // All new loaded. -// return { noSkipRange.from, ServerMaxMsgId }; -// } -// Unexpected("Direction in PinnedTracker::apply."); -// }(); -// } -// _history->session().storage().add(Storage::SharedMediaAddSlice( -// _history->peer->id, -// Storage::SharedMediaType::Pinned, -// std::move(list), -// noSkipRange, -// fullCount)); -//} } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h index 916d9ada7..21f18bb4e 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_tracker.h @@ -48,11 +48,6 @@ public: private: void refreshData(); void setupViewer(not_null data); - //void load(Data::LoadDirection direction, MsgId id); - //void apply( - // Data::LoadDirection direction, - // MsgId aroundId, - // const MTPmessages_Messages &result); const not_null _history; @@ -61,10 +56,6 @@ private: rpl::lifetime _dataLifetime; MsgId _aroundId = 0; - MsgId _beforeId = 0; - MsgId _afterId = 0; - MsgId _beforeRequestId = 0; - MsgId _afterRequestId = 0; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index d2d4a9b9b..7763d2acb 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -111,9 +111,10 @@ RepliesMemento::RepliesMemento( : RepliesMemento(commentsItem->history(), commentsItem->id, commentId) { if (commentId) { _list.setAroundPosition({ - .fullId = FullMsgId(commentsItem->history()->channelId(), commentId), + .fullId = FullMsgId( + commentsItem->history()->channelId(), + commentId), .date = TimeId(0), - }); } else if (commentsItem->computeRepliesInboxReadTillFull() == MsgId(1)) { _list.setAroundPosition(Data::MinMessagePosition); diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 8bc2f2200..62472aeb6 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -361,6 +361,10 @@ historyReplyCancel: IconButton { color: windowBgOver; } } +historyPinnedShowAll: IconButton(historyReplyCancel) { + icon: icon {{ "pinned_show_all", historyReplyCancelFg }}; + iconOver: icon {{ "pinned_show_all", historyReplyCancelFgOver }}; +} msgBotKbDuration: 200; msgBotKbFont: semiboldFont; diff --git a/Telegram/SourceFiles/ui/chat/pinned_bar.cpp b/Telegram/SourceFiles/ui/chat/pinned_bar.cpp index c4878ed28..3181835dc 100644 --- a/Telegram/SourceFiles/ui/chat/pinned_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/pinned_bar.cpp @@ -19,14 +19,8 @@ namespace Ui { PinnedBar::PinnedBar( not_null parent, - rpl::producer content, - bool withClose) + rpl::producer content) : _wrap(parent, object_ptr(parent)) -, _close(withClose - ? std::make_unique( - _wrap.entity(), - st::historyReplyCancel) - : nullptr) , _shadow(std::make_unique(_wrap.parentWidget())) { _wrap.hide(anim::type::instant); _shadow->hide(); @@ -73,7 +67,33 @@ PinnedBar::PinnedBar( }, lifetime()); } -PinnedBar::~PinnedBar() = default; +PinnedBar::~PinnedBar() { + _rightButton.destroy(); +} + +void PinnedBar::setRightButton(object_ptr button) { + _rightButton.destroy(); + _rightButton = std::move(button); + if (_rightButton) { + _rightButton->setParent(_wrap.entity()); + _rightButton->show(); + } + if (_bar) { + updateControlsGeometry(_wrap.geometry()); + } +} + +void PinnedBar::updateControlsGeometry(QRect wrapGeometry) { + _bar->widget()->resizeToWidth( + wrapGeometry.width() - (_rightButton ? _rightButton->width() : 0)); + const auto hidden = _wrap.isHidden() || !wrapGeometry.height(); + if (_shadow->isHidden() != hidden) { + _shadow->setVisible(!hidden); + } + if (_rightButton) { + _rightButton->moveToRight(0, 0); + } +} void PinnedBar::setShadowGeometryPostprocess(Fn postprocess) { _shadowGeometryPostprocess = std::move(postprocess); @@ -97,8 +117,8 @@ void PinnedBar::createControls() { _bar = std::make_unique( _wrap.entity(), st::defaultMessageBar); - if (_close) { - _close->raise(); + if (_rightButton) { + _rightButton->raise(); } // Clicks. @@ -126,15 +146,7 @@ void PinnedBar::createControls() { _wrap.geometryValue( ) | rpl::start_with_next([=](QRect rect) { updateShadowGeometry(rect); - _bar->widget()->resizeToWidth( - rect.width() - (_close ? _close->width() : 0)); - const auto hidden = _wrap.isHidden() || !rect.height(); - if (_shadow->isHidden() != hidden) { - _shadow->setVisible(!hidden); - } - if (_close) { - _close->moveToRight(0, 0); - } + updateControlsGeometry(rect); }, _bar->widget()->lifetime()); _wrap.shownValue( @@ -198,12 +210,6 @@ rpl::producer PinnedBar::heightValue() const { return _wrap.heightValue(); } -rpl::producer<> PinnedBar::closeClicks() const { - return !_close - ? (rpl::never<>() | rpl::type_erased()) - : (_close->clicks() | rpl::map([] { return rpl::empty_value(); })); -} - rpl::producer<> PinnedBar::barClicks() const { return _barClicks.events(); } diff --git a/Telegram/SourceFiles/ui/chat/pinned_bar.h b/Telegram/SourceFiles/ui/chat/pinned_bar.h index 55ca6a283..fd47824af 100644 --- a/Telegram/SourceFiles/ui/chat/pinned_bar.h +++ b/Telegram/SourceFiles/ui/chat/pinned_bar.h @@ -6,7 +6,9 @@ For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once + #include "ui/wrap/slide_wrap.h" +#include "base/object_ptr.h" namespace Ui { @@ -14,13 +16,13 @@ struct MessageBarContent; class MessageBar; class IconButton; class PlainShadow; +class RpWidget; class PinnedBar final { public: PinnedBar( not_null parent, - rpl::producer content, - bool withClose = false); + rpl::producer content); ~PinnedBar(); void show(); @@ -30,11 +32,12 @@ public: void setShadowGeometryPostprocess(Fn postprocess); + void setRightButton(object_ptr button); + void move(int x, int y); void resizeToWidth(int width); [[nodiscard]] int height() const; [[nodiscard]] rpl::producer heightValue() const; - [[nodiscard]] rpl::producer<> closeClicks() const; [[nodiscard]] rpl::producer<> barClicks() const; [[nodiscard]] rpl::lifetime &lifetime() { @@ -44,10 +47,11 @@ public: private: void createControls(); void updateShadowGeometry(QRect wrapGeometry); + void updateControlsGeometry(QRect wrapGeometry); Ui::SlideWrap<> _wrap; std::unique_ptr _bar; - std::unique_ptr _close; + object_ptr _rightButton = { nullptr }; std::unique_ptr _shadow; rpl::event_stream<> _barClicks; Fn _shadowGeometryPostprocess;