mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-19 01:48:09 +00:00
Add top bar menu and notifications toggle.
This commit is contained in:
parent
9743dc1ffb
commit
5f0ba48309
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
@ -1812,6 +1812,9 @@ void History::setUnreadCount(int newUnreadCount) {
|
||||
Notify::historyMuteUpdated(this);
|
||||
}
|
||||
updateChatListEntry();
|
||||
Notify::peerUpdatedDelayed(
|
||||
peer,
|
||||
Notify::PeerUpdate::Flag::NotificationsEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user