diff --git a/Telegram/SourceFiles/data/components/recent_peers.cpp b/Telegram/SourceFiles/data/components/recent_peers.cpp index bd80b28185..63d2668a41 100644 --- a/Telegram/SourceFiles/data/components/recent_peers.cpp +++ b/Telegram/SourceFiles/data/components/recent_peers.cpp @@ -164,4 +164,13 @@ void RecentPeers::chatOpenPush(not_null thread) { } } +void RecentPeers::chatOpenDestroyed(not_null thread) { + _opens.erase(ranges::remove(_opens, thread), end(_opens)); +} + +void RecentPeers::chatOpenKeepUserpics( + base::flat_map, Ui::PeerUserpicView> userpics) { + _chatOpenUserpicsCache = std::move(userpics); +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/components/recent_peers.h b/Telegram/SourceFiles/data/components/recent_peers.h index 4d0fa5dc6a..624b9d3c33 100644 --- a/Telegram/SourceFiles/data/components/recent_peers.h +++ b/Telegram/SourceFiles/data/components/recent_peers.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "ui/userpic_view.h" + namespace Main { class Session; } // namespace Main @@ -33,12 +35,18 @@ public: [[nodiscard]] auto collectChatOpenHistory() const -> std::vector>; void chatOpenPush(not_null thread); + void chatOpenDestroyed(not_null thread); + void chatOpenKeepUserpics( + base::flat_map, Ui::PeerUserpicView> userpics); private: const not_null _session; std::vector> _list; std::vector> _opens; + base::flat_map< + not_null, + Ui::PeerUserpicView> _chatOpenUserpicsCache; rpl::event_stream<> _updates; diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index 0a20f0aeac..0038b189a2 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_forum.h" +#include "data/components/recent_peers.h" #include "data/data_channel.h" #include "data/data_histories.h" #include "data/data_changes.h" @@ -194,6 +195,7 @@ void Forum::applyTopicDeleted(MsgId rootId) { _activeSubsectionTopic = nullptr; } _topicDestroyed.fire(raw); + _history->session().recentPeers().chatOpenDestroyed(raw); session().changes().topicUpdated( raw, Data::TopicUpdate::Flag::Destroyed); diff --git a/Telegram/SourceFiles/data/data_saved_messages.cpp b/Telegram/SourceFiles/data/data_saved_messages.cpp index a7ee009257..571a7663da 100644 --- a/Telegram/SourceFiles/data/data_saved_messages.cpp +++ b/Telegram/SourceFiles/data/data_saved_messages.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "core/application.h" +#include "data/components/recent_peers.h" #include "data/data_changes.h" #include "data/data_channel.h" #include "data/data_histories.h" @@ -452,6 +453,7 @@ void SavedMessages::applySublistDeleted(not_null sublistPeer) { } _sublistDestroyed.fire(raw); + _owner->session().recentPeers().chatOpenDestroyed(raw); session().changes().sublistUpdated( raw, Data::SublistUpdate::Flag::Destroyed); diff --git a/Telegram/SourceFiles/window/window_chat_switch_process.cpp b/Telegram/SourceFiles/window/window_chat_switch_process.cpp index a43b06d22a..a66b31c6b3 100644 --- a/Telegram/SourceFiles/window/window_chat_switch_process.cpp +++ b/Telegram/SourceFiles/window/window_chat_switch_process.cpp @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/shortcuts.h" #include "data/components/recent_peers.h" +#include "data/data_forum_topic.h" +#include "data/data_peer.h" #include "data/data_saved_sublist.h" #include "data/data_thread.h" #include "info/profile/info_profile_cover.h" @@ -23,10 +25,160 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_window.h" namespace Window { +namespace { + +class Button final : public Ui::AbstractButton { +public: + Button( + QWidget *parent, + not_null thread, + base::flat_map, Ui::PeerUserpicView> &userpics); + + [[nodiscard]] rpl::producer<> selectRequests() const; + + void setSelected( + bool selected, + anim::type animated = anim::type::normal); + +private: + void setup( + not_null thread, + base::flat_map, Ui::PeerUserpicView> &userpics); + + void paintEvent(QPaintEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + + rpl::event_stream<> _selectRequests; + Ui::Animations::Simple _overAnimation; + bool _selected = false; + +}; + +Button::Button( + QWidget *parent, + not_null thread, + base::flat_map, Ui::PeerUserpicView> &userpics) +: AbstractButton(parent) { + setup(thread, userpics); +} + +void Button::setup( + not_null thread, + base::flat_map, Ui::PeerUserpicView> &userpics) { + resize(st::chatSwitchSize); + + auto userpicSt = &st::chatSwitchUserpic; + const auto userpicSize = userpicSt->size; + if (const auto topic = thread->asTopic()) { + using namespace Info::Profile; + const auto userpic = Ui::CreateChild( + this, + topic, + [] { return true; }); // paused + userpic->show(); + userpic->move( + ((width() - userpic->width()) / 2), + st::chatSwitchUserpicTop); + userpic->setAttribute(Qt::WA_TransparentForMouseEvents); + + userpicSt = &st::chatSwitchUserpicSmall; + } else if (const auto sublist = thread->asSublist()) { + const auto sublistPeer = sublist->sublistPeer(); + const auto userpic = Ui::CreateChild( + this, + sublistPeer, + st::chatSwitchUserpicSublist); + userpic->show(); + userpic->move( + ((width() - userpicSize.width()) / 2), + st::chatSwitchUserpicTop); + userpic->setAttribute(Qt::WA_TransparentForMouseEvents); + userpics.emplace(sublistPeer, sublistPeer->createUserpicView()); + + userpicSt = &st::chatSwitchUserpicSmall; + } + const auto peer = thread->peer(); + const auto userpic = Ui::CreateChild( + this, + peer, + *userpicSt); + userpic->show(); + userpic->move( + (((width() - userpicSize.width()) / 2) + + (userpicSize.width() - userpicSt->size.width())), + (st::chatSwitchUserpicTop + + (userpicSize.height() - userpicSt->size.height()))); + userpic->setAttribute(Qt::WA_TransparentForMouseEvents); + userpics.emplace(peer, peer->createUserpicView()); + + const auto label = Ui::CreateChild( + this, + thread->chatListName(), + st::chatSwitchNameLabel); + label->setBreakEverywhere(true); + label->show(); + label->resizeToNaturalWidth( + width() - 2 * st::chatSwitchNameSkip); + label->move( + (width() - label->width()) / 2, + (height() + userpic->y() + userpic->height() - label->height()) / 2); + + show(); +} + +rpl::producer<> Button::selectRequests() const { + return _selectRequests.events(); +} + +void Button::setSelected(bool selected, anim::type animated) { + if (_selected == selected) { + if (animated == anim::type::instant) { + _overAnimation.stop(); + } + return; + } + _selected = selected; + if (animated == anim::type::instant) { + _overAnimation.stop(); + update(); + } else { + _overAnimation.start( + [=] { update(); }, + selected ? 0. : 1., + selected ? 1. : 0., + st::slideWrapDuration); + } +} + +void Button::paintEvent(QPaintEvent *e) { + const auto selected = _selected ? 1. : 0.; + const auto selection = _overAnimation.value(selected); + if (selection <= 0.) { + return; + } + + auto p = QPainter(this); + auto hq = PainterHighQualityEnabler(p); + const auto radius = st::boxRadius; + const auto line = st::chatSwitchSelectLine; + auto pen = st::defaultRoundCheckbox.bgActive->p; + pen.setWidthF(line * selection); + p.setPen(pen); + const auto r = QRectF(rect()).marginsRemoved( + { line / 2., line / 2., line / 2., line / 2. }); + p.drawRoundedRect(r, radius, radius); +} + +void Button::mouseMoveEvent(QMouseEvent *e) { + if (!_selected) { + _selectRequests.fire({}); + } +} + +} // namespace struct ChatSwitchProcess::Entry { - not_null button; - Ui::Animations::Simple overAnimation; + std::unique_ptr