Add top bar menu and notifications toggle.

This commit is contained in:
John Preston 2017-11-07 19:12:54 +04:00
parent 9743dc1ffb
commit 5f0ba48309
10 changed files with 201 additions and 70 deletions

View File

@ -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;
}
if (e->reason() == QContextMenuEvent::Mouse) {
_mouseSelection = true;
updateSelected();
}
History *history = nullptr;
auto history = [&]() -> History* {
if (_state == DefaultState) {
if (_selected) history = _selected->history();
if (_selected) {
return _selected->history();
}
} else if (_state == FilteredState || _state == SearchedState) {
if (_filteredSelected >= 0 && _filteredSelected < _filterResults.size()) {
history = _filterResults[_filteredSelected]->history();
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() {

View File

@ -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;
};

View File

@ -1812,6 +1812,9 @@ void History::setUnreadCount(int newUnreadCount) {
Notify::historyMuteUpdated(this);
}
updateChatListEntry();
Notify::peerUpdatedDelayed(
peer,
Notify::PeerUpdate::Flag::NotificationsEnabled);
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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() {

View File

@ -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();
}
if (_source != PeerMenuSource::Profile) {
addNotifications();
if (_options.fromChatsList) {
}
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();
}

View File

@ -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);