diff --git a/Telegram/SourceFiles/data/data_feed.cpp b/Telegram/SourceFiles/data/data_feed.cpp index eb0742c47f..d99e0e7604 100644 --- a/Telegram/SourceFiles/data/data_feed.cpp +++ b/Telegram/SourceFiles/data/data_feed.cpp @@ -203,6 +203,8 @@ void Feed::setChannels(std::vector> channels) { _channels.push_back(App::history(channel)); } _channelsLoaded = true; + + _parent->notifyFeedUpdated(this, FeedUpdateFlag::Channels); } bool Feed::justSetLastMessage(not_null item) { diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.cpp b/Telegram/SourceFiles/history/feed/history_feed_section.cpp index 9bf3c4f4e1..4e8705d2d6 100644 --- a/Telegram/SourceFiles/history/feed/history_feed_section.cpp +++ b/Telegram/SourceFiles/history/feed/history_feed_section.cpp @@ -116,11 +116,13 @@ Widget::Widget( rpl::single( Data::FeedUpdate{ _feed, Data::FeedUpdateFlag::Channels } ) | rpl::then( - Auth().data().feedUpdated() - ) | rpl::filter([=](const Data::FeedUpdate &update) { - return (update.feed == _feed); - }) | rpl::start_with_next([=](const Data::FeedUpdate &update) { - checkForSingleChannelFeed(); + Auth().data().feedUpdated( + ) | rpl::filter([=](const Data::FeedUpdate &update) { + return (update.feed == _feed) + && (update.flag == Data::FeedUpdateFlag::Channels); + }) + ) | rpl::start_with_next([=] { + crl::on_main(this, [=] { checkForSingleChannelFeed(); }); }, lifetime()); } diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 805caf7cd5..feaf4190a7 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -355,16 +355,7 @@ void TopBarWidget::setActiveChat(Dialogs::Key chat) { update(); updateUnreadBadge(); - if (const auto peer = _activeChat.peer()) { - _info.create( - this, - _controller, - peer, - Ui::UserpicButton::Role::Custom, - st::topBarInfoButton); - _info->showSavedMessagesOnSelf(true); - _info->setAttribute(Qt::WA_TransparentForMouseEvents); - } + refreshInfoButton(); if (_menu) { _menuToggle->removeEventFilter(_menu); _menu->hideFast(); @@ -374,6 +365,28 @@ void TopBarWidget::setActiveChat(Dialogs::Key chat) { } } +void TopBarWidget::refreshInfoButton() { + if (const auto peer = _activeChat.peer()) { + auto info = object_ptr( + this, + _controller, + peer, + Ui::UserpicButton::Role::Custom, + st::topBarInfoButton); + info->showSavedMessagesOnSelf(true); + _info = std::move(info); + } else if (const auto feed = _activeChat.feed()) { + _info = object_ptr( + this, + _controller, + feed, + st::topBarFeedInfoButton); + } + if (_info) { + _info->setAttribute(Qt::WA_TransparentForMouseEvents); + } +} + void TopBarWidget::resizeEvent(QResizeEvent *e) { updateControlsGeometry(); } diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h index 9df60669a6..000f23d902 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h @@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_key.h" namespace Ui { -class UserpicButton; +class AbstractButton; class RoundButton; class IconButton; class DropdownMenu; @@ -67,6 +67,7 @@ protected: int resizeGetHeight(int newWidth) override; private: + void refreshInfoButton(); void refreshLang(); void updateControlsGeometry(); void selectedShowCallback(); @@ -107,7 +108,7 @@ private: object_ptr _back; object_ptr _unreadBadge = { nullptr }; - object_ptr _info = { nullptr }; + object_ptr _info = { nullptr }; object_ptr _call; object_ptr _search; diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 6a69d93eb2..a943d5e310 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -661,8 +661,20 @@ topBarInfo: IconButton(topBarSearch) { topBarInfoActive: icon {{ "top_bar_profile", windowActiveTextFg }}; topBarActionSkip: 10px; +topBarInfoButtonSize: size(52px, topBarHeight); +topBarInfoButtonInnerSize: 42px; +topBarInfoButtonInnerPosition: point(2px, -1px); topBarInfoButton: UserpicButton(defaultUserpicButton) { - size: size(52px, topBarHeight); - photoSize: 42px; - photoPosition: point(2px, -1px); + size: topBarInfoButtonSize; + photoSize: topBarInfoButtonInnerSize; + photoPosition: topBarInfoButtonInnerPosition; +} +topBarFeedInfoButton: FeedUserpicButton(defaultFeedUserpicButton) { + size: topBarInfoButtonSize; + innerSize: topBarInfoButtonInnerSize; + innerPosition: topBarInfoButtonInnerPosition; + innerPart: UserpicButton(defaultUserpicButton) { + size: size(20px, 20px); + photoSize: 20px; + } } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4f4fa80c3d..fb7a640056 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2203,6 +2203,11 @@ void MainWidget::ui_showPeerHistory( } updateControlsGeometry(); + + if (noPeer) { + _controller->setActiveChatEntry(Dialogs::Key()); + } + if (onlyDialogs) { _history->hide(); if (!_a_show.animating()) { @@ -2250,10 +2255,6 @@ void MainWidget::ui_showPeerHistory( _dialogs->update(); } - if (noPeer) { - _controller->setActiveChatEntry(Dialogs::Key()); - } - checkFloatPlayerVisibility(); } diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index 82cb8b714b..affd69847d 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/empty_userpic.h" #include "data/data_photo.h" #include "data/data_session.h" +#include "data/data_feed.h" +#include "history/history.h" #include "core/file_utilities.h" #include "boxes/photo_crop_box.h" #include "boxes/confirm_box.h" @@ -824,6 +826,94 @@ void UserpicButton::prepareUserpicPixmap() { : StorageKey(); } +FeedUserpicButton::FeedUserpicButton( + QWidget *parent, + not_null controller, + not_null feed, + const style::FeedUserpicButton &st) +: AbstractButton(parent) +, _st(st) +, _controller(controller) +, _feed(feed) { + prepare(); +} + +void FeedUserpicButton::prepare() { + resize(_st.size); + + Auth().data().feedUpdated( + ) | rpl::filter([=](const Data::FeedUpdate &update) { + return (update.feed == _feed) + && (update.flag == Data::FeedUpdateFlag::Channels); + }) | rpl::start_with_next([=] { + crl::on_main(this, [=] { checkParts(); }); + }, lifetime()); + + refreshParts(); +} + +void FeedUserpicButton::checkParts() { + if (!partsAreValid()) { + refreshParts(); + } +} + +bool FeedUserpicButton::partsAreValid() const { + const auto &channels = _feed->channels(); + if (std::min(int(channels.size()), 4) != _parts.size()) { + return false; + } + for (auto i = 0; i != 4; ++i) { + if (channels[i]->peer != _parts[i].channel) { + return false; + } + } + return true; +} + +void FeedUserpicButton::refreshParts() { + const auto &channels = _feed->channels(); + const auto count = std::min(int(channels.size()), 4); + + const auto createButton = [&](not_null channel) { + auto result = base::make_unique_q( + this, + _controller, + channel, + Ui::UserpicButton::Role::Custom, + _st.innerPart); + result->setAttribute(Qt::WA_TransparentForMouseEvents); + result->show(); + return result; + }; + + const auto position = countInnerPosition(); + auto x = position.x(); + auto y = position.y(); + const auto delta = _st.innerSize - _st.innerPart.photoSize; + _parts.clear(); + for (auto i = 0; i != count; ++i) { + const auto channel = channels[i]->peer->asChannel(); + _parts.push_back({ channel, createButton(channel) }); + _parts.back().button->moveToLeft(x, y); + switch (i) { + case 0: + case 2: x += delta; break; + case 1: x -= delta; y += delta; break; + } + } +} + +QPoint FeedUserpicButton::countInnerPosition() const { + auto innerLeft = (_st.innerPosition.x() < 0) + ? (width() - _st.innerSize) / 2 + : _st.innerPosition.x(); + auto innerTop = (_st.innerPosition.y() < 0) + ? (height() - _st.innerSize) / 2 + : _st.innerPosition.y(); + return { innerLeft, innerTop }; +} + SilentToggle::SilentToggle(QWidget *parent, not_null channel) : IconButton(parent, st::historySilentToggle) , _channel(channel) diff --git a/Telegram/SourceFiles/ui/special_buttons.h b/Telegram/SourceFiles/ui/special_buttons.h index 012ef72749..8c06eef5f4 100644 --- a/Telegram/SourceFiles/ui/special_buttons.h +++ b/Telegram/SourceFiles/ui/special_buttons.h @@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class PeerData; +namespace Data { +class Feed; +} // namespace Data + namespace Window { class Controller; } // namespace Window @@ -218,6 +222,33 @@ private: }; +class FeedUserpicButton : public AbstractButton { +public: + FeedUserpicButton( + QWidget *parent, + not_null controller, + not_null feed, + const style::FeedUserpicButton &st); + +private: + struct Part { + not_null channel; + base::unique_qptr button; + }; + + void prepare(); + void checkParts(); + bool partsAreValid() const; + void refreshParts(); + QPoint countInnerPosition() const; + + const style::FeedUserpicButton &_st; + not_null _controller; + not_null _feed; + std::vector _parts; + +}; + class SilentToggle : public Ui::IconButton, public Ui::AbstractTooltipShower { public: SilentToggle(QWidget *parent, not_null channel); diff --git a/Telegram/SourceFiles/ui/widgets/widgets.style b/Telegram/SourceFiles/ui/widgets/widgets.style index 6db0416298..c60cdec77f 100644 --- a/Telegram/SourceFiles/ui/widgets/widgets.style +++ b/Telegram/SourceFiles/ui/widgets/widgets.style @@ -494,6 +494,13 @@ UserpicButton { uploadIconPosition: point; } +FeedUserpicButton { + size: size; + innerSize: pixels; + innerPosition: point; + innerPart: UserpicButton; +} + InfoProfileButton { textFg: color; textFgOver: color; @@ -988,6 +995,12 @@ defaultUserpicButton: UserpicButton { uploadIcon: defaultUploadUserpicIcon; uploadIconPosition: point(-1px, 1px); } +defaultFeedUserpicButton: FeedUserpicButton { + size: size(76px, 76px); + innerSize: 76px; + innerPosition: point(-1px, -1px); + innerPart: defaultUserpicButton; +} historyToDownBelow: icon { { "history_down_shadow", historyToDownShadow },