From 5f0ba4830986da7fadfa1da5108e075c9d572733 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 7 Nov 2017 19:12:54 +0400 Subject: [PATCH] Add top bar menu and notifications toggle. --- .../dialogs/dialogs_inner_widget.cpp | 50 ++++------ .../dialogs/dialogs_inner_widget.h | 6 +- Telegram/SourceFiles/history/history.cpp | 3 + Telegram/SourceFiles/info/info.style | 36 +++++++- .../SourceFiles/info/info_wrap_widget.cpp | 92 +++++++++++++++++++ Telegram/SourceFiles/info/info_wrap_widget.h | 9 ++ Telegram/SourceFiles/mainwidget.cpp | 3 - .../SourceFiles/window/top_bar_widget.cpp | 17 +--- .../SourceFiles/window/window_peer_menu.cpp | 46 +++++++--- .../SourceFiles/window/window_peer_menu.h | 9 +- 10 files changed, 201 insertions(+), 70 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 2a1876b0fe..d06d66b43b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1044,7 +1044,7 @@ void DialogsInner::createDialog(History *history) { void DialogsInner::removeDialog(History *history) { if (!history) return; if (history->peer == _menuPeer && _menu) { - _menu->deleteLater(); + InvokeQueued(this, [this] { _menu = nullptr; }); } if (_selected && _selected->history() == history) { _selected = nullptr; @@ -1211,53 +1211,41 @@ void DialogsInner::clearSelection() { } void DialogsInner::contextMenuEvent(QContextMenuEvent *e) { - if (_menu) { - _menu->deleteLater(); - _menu = nullptr; - } - if (_menuPeer) { - updateSelectedRow(_menuPeer); - _menuPeer = nullptr; - } + _menu = nullptr; if (e->reason() == QContextMenuEvent::Mouse) { _mouseSelection = true; updateSelected(); } - History *history = nullptr; - if (_state == DefaultState) { - if (_selected) history = _selected->history(); - } else if (_state == FilteredState || _state == SearchedState) { - if (_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) { - history = _filterResults[_filteredSelected]->history(); + auto history = [&]() -> History* { + if (_state == DefaultState) { + if (_selected) { + return _selected->history(); + } + } else if (_state == FilteredState || _state == SearchedState) { + if (_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) { + return _filterResults[_filteredSelected]->history(); + } } - } + return nullptr; + }(); if (!history) return; - _menuPeer = history->peer; + _menuPeer = history->peer; if (_pressButton != Qt::LeftButton) { mousePressReleased(_pressButton); } - _menu = new Ui::PopupMenu(nullptr); - Window::PeerMenuOptions options; - options.fromChatsList = options.showInfo = true; + _menu = base::make_unique_q<Ui::PopupMenu>(nullptr); Window::FillPeerMenu( _controller, _menuPeer, [this](const QString &text, base::lambda<void()> callback) { return _menu->addAction(text, std::move(callback)); }, - options); - connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroyed(QObject*))); - _menu->popup(e->globalPos()); - e->accept(); -} - -void DialogsInner::onMenuDestroyed(QObject *obj) { - if (_menu == obj) { - _menu = nullptr; + Window::PeerMenuSource::ChatsList); + connect(_menu.get(), &QObject::destroyed, [this] { if (_menuPeer) { updateSelectedRow(base::take(_menuPeer)); } @@ -1267,7 +1255,9 @@ void DialogsInner::onMenuDestroyed(QObject *obj) { setMouseTracking(true); updateSelected(localPos); } - } + }); + _menu->popup(e->globalPos()); + e->accept(); } void DialogsInner::onParentGeometryChanged() { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 0d6398e641..eddb3fcb2d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -119,8 +119,6 @@ public slots: void onParentGeometryChanged(); void onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow); - void onMenuDestroyed(QObject*); - signals: void draggingScrollDelta(int delta); void mustScrollTo(int scrollToTop, int scrollToBottom); @@ -293,8 +291,8 @@ private: Text _searchFromUserText; PeerData *_menuPeer = nullptr; - Ui::PopupMenu *_menu = nullptr; - base::lambda<void()> _loadMoreCallback; + base::unique_qptr<Ui::PopupMenu> _menu; + }; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index c29142ef1f..b2b81de04b 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1812,6 +1812,9 @@ void History::setUnreadCount(int newUnreadCount) { Notify::historyMuteUpdated(this); } updateChatListEntry(); + Notify::peerUpdatedDelayed( + peer, + Notify::PeerUpdate::Flag::NotificationsEnabled); } } diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index c454a51ab9..518fb32371 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -138,6 +138,24 @@ infoTopBarSearch: IconButton(infoTopBarBack) { icon: icon {{ "top_bar_search", boxTitleCloseFg }}; iconOver: icon {{ "top_bar_search", boxTitleCloseFgOver }}; } +infoTopBarMenu: IconButton(infoTopBarBack) { + width: 48px; + icon: icon {{ "title_menu_dots", boxTitleCloseFg }}; + iconOver: icon {{ "title_menu_dots", boxTitleCloseFgOver }}; + iconPosition: point(18px, -1px); + rippleAreaPosition: point(1px, 6px); +} +infoTopBarNotifications: IconButton(infoTopBarMenu) { + width: 42px; + icon: icon {{ "info_notifications", boxTitleCloseFg }}; + iconOver: icon {{ "info_notifications", boxTitleCloseFgOver }}; + iconPosition: point(5px, 10px); + rippleAreaPosition: point(0px, 6px); +} +infoNotificationsActive: icon {{ + "info_notifications", + windowBgActive +}}; infoTopBarForward: IconButton(infoTopBarBack) { width: 46px; icon: icon {{ "info_media_forward", boxTitleCloseFg }}; @@ -173,14 +191,27 @@ infoLayerTopBarBack: IconButton(infoTopBarBack) { iconPosition: point(12px, -1px); icon: infoLayerTopBarBackIcon; iconOver: infoLayerTopBarBackIconOver; - rippleAreaSize: 44px; } infoLayerTopBarCloseIcon: icon {{ "info_close", boxTitleCloseFg }}; infoLayerTopBarCloseIconOver: icon {{ "info_close", boxTitleCloseFgOver }}; infoLayerTopBarClose: IconButton(infoLayerTopBarBack) { + width: 50px; icon: infoLayerTopBarCloseIcon; iconOver: infoLayerTopBarCloseIconOver; + iconPosition: point(6px, -1px); + rippleAreaPosition: point(0px, 6px); +} +infoLayerTopBarMenu: IconButton(infoLayerTopBarClose) { + width: 44px; + icon: icon {{ "title_menu_dots", boxTitleCloseFg }}; + iconOver: icon {{ "title_menu_dots", boxTitleCloseFgOver }}; + iconPosition: point(18px, -1px); +} +infoLayerTopBarNotifications: IconButton(infoLayerTopBarMenu) { + icon: icon {{ "info_notifications", boxTitleCloseFg }}; + iconOver: icon {{ "info_notifications", boxTitleCloseFgOver }}; + iconPosition: point(5px, 11px); } infoLayerTopBarForward: IconButton(infoLayerTopBarBack) { width: 45px; @@ -207,6 +238,9 @@ infoLayerTopBar: InfoTopBar { searchRow: infoTopBarSearchRow; } +infoTopBarMenuPosition: point(-2px, 35px); +infoLayerTopBarMenuPosition: point(40px, 37px); + infoMinimalWidth: 324px; infoDesiredWidth: 430px; infoMinimalLayerMargin: 48px; diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index 7430d68661..b0f607d30a 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include <rpl/flatten_latest.h> #include <rpl/combine.h> #include "info/profile/info_profile_widget.h" +#include "info/profile/info_profile_values.h" #include "info/media/info_media_widget.h" #include "info/info_content_widget.h" #include "info/info_controller.h" @@ -32,11 +33,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/discrete_sliders.h" #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" +#include "ui/widgets/dropdown_menu.h" #include "ui/wrap/fade_wrap.h" #include "ui/search_field_controller.h" #include "window/window_controller.h" #include "window/window_slide_animation.h" +#include "window/window_peer_menu.h" #include "auth_session.h" +#include "mainwidget.h" #include "lang/lang_keys.h" #include "styles/style_info.h" #include "styles/style_profile.h" @@ -256,12 +260,100 @@ void WrapWidget::createTopBar() { search, _controller->searchEnabledByContent()); } + if (_controller->section().type() == Section::Type::Profile) { + addProfileMenuButton(); + addProfileNotificationsButton(); + } _topBar->move(0, 0); _topBar->resizeToWidth(width()); _topBar->show(); } +void WrapWidget::addProfileMenuButton() { + Expects(_topBar != nullptr); + + _topBarMenuToggle.reset(_topBar->addButton( + base::make_unique_q<Ui::IconButton>( + _topBar, + (wrap() == Wrap::Layer + ? st::infoLayerTopBarMenu + : st::infoTopBarMenu)))); + _topBarMenuToggle->addClickHandler([this] { + showProfileMenu(); + }); +} + +void WrapWidget::addProfileNotificationsButton() { + Expects(_topBar != nullptr); + + auto peer = _controller->peer(); + auto notifications = _topBar->addButton( + base::make_unique_q<Ui::IconButton>( + _topBar, + (wrap() == Wrap::Layer + ? st::infoLayerTopBarNotifications + : st::infoTopBarNotifications))); + notifications->addClickHandler([peer] { + App::main()->updateNotifySetting( + peer, + peer->isMuted() + ? NotifySettingSetNotify + : NotifySettingSetMuted); + }); + Profile::NotificationsEnabledValue(peer) + | rpl::start_with_next([notifications](bool enabled) { + auto iconOverride = enabled + ? &st::infoNotificationsActive + : nullptr; + auto rippleOverride = enabled + ? &st::lightButtonBgOver + : nullptr; + notifications->setIconOverride(iconOverride, iconOverride); + notifications->setRippleColorOverride(rippleOverride); + }, notifications->lifetime()); +} + +void WrapWidget::showProfileMenu() { + if (_topBarMenu) { + _topBarMenu->hideAnimated( + Ui::InnerDropdown::HideOption::IgnoreShow); + return; + } + _topBarMenu = base::make_unique_q<Ui::DropdownMenu>(this); + + _topBarMenu->setHiddenCallback([this] { + InvokeQueued(this, [this] { _topBarMenu = nullptr; }); + if (auto toggle = _topBarMenuToggle.get()) { + toggle->setForceRippled(false); + } + }); + _topBarMenu->setShowStartCallback([this] { + if (auto toggle = _topBarMenuToggle.get()) { + toggle->setForceRippled(true); + } + }); + _topBarMenu->setHideStartCallback([this] { + if (auto toggle = _topBarMenuToggle.get()) { + toggle->setForceRippled(false); + } + }); + _topBarMenuToggle->installEventFilter(_topBarMenu.get()); + + Window::FillPeerMenu( + _controller->window(), + _controller->peer(), + [this](const QString &text, base::lambda<void()> callback) { + return _topBarMenu->addAction(text, std::move(callback)); + }, + Window::PeerMenuSource::Profile); + auto position = (wrap() == Wrap::Layer) + ? st::infoLayerTopBarMenuPosition + : st::infoTopBarMenuPosition; + _topBarMenu->moveToRight(position.x(), position.y()); + _topBarMenu->showAnimated(Ui::PanelAnimation::Origin::TopRight); +} + void WrapWidget::refreshTopBarOverride(SelectedItems &&items) { if (items.list.empty()) { destroyTopBarOverride(); diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h index fb61dfba6b..e15dba0d0f 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.h +++ b/Telegram/SourceFiles/info/info_wrap_widget.h @@ -28,6 +28,8 @@ namespace Ui { class SettingsSlider; class FadeShadow; class PlainShadow; +class DropdownMenu; +class IconButton; } // namespace Ui namespace Window { @@ -181,6 +183,10 @@ private: void destroyTopBarOverride(); bool requireTopBarSearch() const; + void addProfileMenuButton(); + void addProfileNotificationsButton(); + void showProfileMenu(); + rpl::variable<Wrap> _wrap; std::unique_ptr<Controller> _controller; object_ptr<ContentWidget> _content = { nullptr }; @@ -190,6 +196,9 @@ private: object_ptr<TopBarOverride> _topBarOverride = { nullptr }; Animation _topBarOverrideAnimation; object_ptr<Ui::FadeShadow> _topShadow; + base::unique_qptr<Ui::IconButton> _topBarMenuToggle; + base::unique_qptr<Ui::DropdownMenu> _topBarMenu; + Tab _tab = Tab::Profile; std::unique_ptr<ContentMemento> _anotherTabMemento; std::vector<StackItem> _historyStack; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index dedf0fe7dd..e9e656458f 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4525,9 +4525,6 @@ void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNoti if (_history->peer() == updatePeer) { _history->updateNotifySettings(); } - if (changed) { - Notify::peerUpdatedDelayed(updatePeer, Notify::PeerUpdate::Flag::NotificationsEnabled); - } } } diff --git a/Telegram/SourceFiles/window/top_bar_widget.cpp b/Telegram/SourceFiles/window/top_bar_widget.cpp index 418da9548f..684ec2fd3e 100644 --- a/Telegram/SourceFiles/window/top_bar_widget.cpp +++ b/Telegram/SourceFiles/window/top_bar_widget.cpp @@ -186,24 +186,13 @@ void TopBarWidget::showMenu() { } })); _menuToggle->installEventFilter(_menu); - Window::PeerMenuOptions options; - options.showInfo = [&] { - if (!Adaptive::ThreeColumn()) { - return true; - } else if ( - !Auth().data().thirdSectionInfoEnabled() && - !Auth().data().tabbedReplacedWithInfo()) { - return true; - } - return false; - }(); Window::FillPeerMenu( _controller, peer, [this](const QString &text, base::lambda<void()> callback) { return _menu->addAction(text, std::move(callback)); }, - options); + Window::PeerMenuSource::History); _menu->moveToRight((parentWidget()->width() - width()) + st::topBarMenuPosition.x(), st::topBarMenuPosition.y()); _menu->showAnimated(Ui::PanelAnimation::Origin::TopRight); } @@ -512,11 +501,11 @@ void TopBarWidget::updateInfoToggleActive() { auto iconOverride = infoThirdActive ? &st::topBarInfoActive : nullptr; - auto ripplOverride = infoThirdActive + auto rippleOverride = infoThirdActive ? &st::lightButtonBgOver : nullptr; _infoToggle->setIconOverride(iconOverride, iconOverride); - _infoToggle->setRippleColorOverride(ripplOverride); + _infoToggle->setRippleColorOverride(rippleOverride); } Ui::RoundButton *TopBarWidget::mediaTypeButton() { diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 1b971b8ae3..fa0d31e380 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -65,10 +65,11 @@ public: not_null<Controller*> controller, not_null<PeerData*> peer, const PeerMenuCallback &addAction, - const PeerMenuOptions &options); + PeerMenuSource source); void fill(); private: + bool showInfo(); void addPinToggle(); void addInfo(); void addNotifications(); @@ -81,7 +82,7 @@ private: not_null<Controller*> _controller; not_null<PeerData*> _peer; const PeerMenuCallback &_addAction; - const PeerMenuOptions &_options; + PeerMenuSource _source; }; @@ -142,11 +143,26 @@ Filler::Filler( not_null<Controller*> controller, not_null<PeerData*> peer, const PeerMenuCallback &addAction, - const PeerMenuOptions &options) + PeerMenuSource source) : _controller(controller) , _peer(peer) , _addAction(addAction) -, _options(options) { +, _source(source) { +} + +bool Filler::showInfo() { + if (_source == PeerMenuSource::Profile) { + return false; + } else if (_controller->historyPeer.current() != _peer) { + return true; + } else if (!Adaptive::ThreeColumn()) { + return true; + } else if ( + !Auth().data().thirdSectionInfoEnabled() && + !Auth().data().tabbedReplacedWithInfo()) { + return true; + } + return false; } void Filler::addPinToggle() { @@ -294,7 +310,7 @@ void Filler::addBlockUser(not_null<UserData*> user) { } void Filler::addUserActions(not_null<UserData*> user) { - if (!_options.fromChatsList) { + if (_source != PeerMenuSource::ChatsList) { if (user->isContact()) { _addAction( lang(lng_info_share_contact), @@ -330,7 +346,7 @@ void Filler::addUserActions(not_null<UserData*> user) { } void Filler::addChatActions(not_null<ChatData*> chat) { - if (!_options.fromChatsList) { + if (_source != PeerMenuSource::ChatsList) { if (chat->canEdit()) { _addAction( lang(lng_profile_edit_contact), @@ -360,7 +376,7 @@ void Filler::addChatActions(not_null<ChatData*> chat) { } void Filler::addChannelActions(not_null<ChannelData*> channel) { - if (!_options.fromChatsList) { + if (_source != PeerMenuSource::ChatsList) { //_addAction(manage); if (channel->canAddMembers()) { _addAction( @@ -381,7 +397,7 @@ void Filler::addChannelActions(not_null<ChannelData*> channel) { joinText, [channel] { Auth().api().joinChannel(channel); }); } - if (!_options.fromChatsList) { + if (_source != PeerMenuSource::ChatsList) { auto needReport = !channel->amCreator() && (!channel->isMegagroup() || channel->isPublic()); if (needReport) { @@ -393,14 +409,16 @@ void Filler::addChannelActions(not_null<ChannelData*> channel) { } void Filler::fill() { - if (_options.fromChatsList) { + if (_source == PeerMenuSource::ChatsList) { addPinToggle(); } - if (_options.showInfo) { + if (showInfo()) { addInfo(); } - addNotifications(); - if (_options.fromChatsList) { + if (_source != PeerMenuSource::Profile) { + addNotifications(); + } + if (_source == PeerMenuSource::ChatsList) { addSearch(); } @@ -478,8 +496,8 @@ void FillPeerMenu( not_null<Controller*> controller, not_null<PeerData*> peer, const PeerMenuCallback &callback, - const PeerMenuOptions &options) { - Filler filler(controller, peer, callback, options); + PeerMenuSource source) { + Filler filler(controller, peer, callback, source); filler.fill(); } diff --git a/Telegram/SourceFiles/window/window_peer_menu.h b/Telegram/SourceFiles/window/window_peer_menu.h index bbaebc79d7..acdc15546a 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.h +++ b/Telegram/SourceFiles/window/window_peer_menu.h @@ -24,9 +24,10 @@ namespace Window { class Controller; -struct PeerMenuOptions { - bool fromChatsList = false; - bool showInfo = false; +enum class PeerMenuSource { + ChatsList, + History, + Profile, }; using PeerMenuCallback = base::lambda<QAction*( @@ -37,7 +38,7 @@ void FillPeerMenu( not_null<Controller*> controller, not_null<PeerData*> peer, const PeerMenuCallback &addAction, - const PeerMenuOptions &options); + PeerMenuSource source); void PeerMenuDeleteContact(not_null<UserData*> user); void PeerMenuShareContactBox(not_null<UserData*> user);