[gnome-shell/eos3.8: 31/255] userMenu: Implement the new user menu, based on our design specs
- From: Matthew Leeds <mwleeds src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/eos3.8: 31/255] userMenu: Implement the new user menu, based on our design specs
- Date: Wed, 10 Jun 2020 19:00:33 +0000 (UTC)
commit 51d93bd6535187cff837e14b4ef8b16ad48d59da
Author: Mario Sanchez Prada <mario endlessm com>
Date: Wed Feb 14 11:15:02 2018 +0000
userMenu: Implement the new user menu, based on our design specs
This is a fresh implementation from scratch based on the Endless
design specs from T20327, T20485 and T20800, which includes all
the additions incorporated since EOS 3.2 squashed together.
* 2020-03-13:
+ Rebase conflicts, remove deprecated actor property
+ Squash with 6920c53b8
+ Squash with fb9909df8
https://phabricator.endlessm.com/T20327
https://phabricator.endlessm.com/T20485
https://phabricator.endlessm.com/T20800
data/gnome-shell-theme.gresource.xml | 3 +
data/theme/endless-help-symbolic.svg | 1 +
data/theme/feedback-symbolic.svg | 12 ++
data/theme/gnome-shell-sass/_endless.scss | 42 +++++++
data/theme/system-logout.png | Bin 0 -> 18189 bytes
js/js-resources.gresource.xml | 1 +
js/ui/panel.js | 47 +++++---
js/ui/popupMenu.js | 4 +-
js/ui/sessionMode.js | 3 +-
js/ui/userMenu.js | 187 ++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
11 files changed, 284 insertions(+), 17 deletions(-)
---
diff --git a/data/gnome-shell-theme.gresource.xml b/data/gnome-shell-theme.gresource.xml
index b239a8e2a4..1d08658b87 100644
--- a/data/gnome-shell-theme.gresource.xml
+++ b/data/gnome-shell-theme.gresource.xml
@@ -39,8 +39,11 @@
<file>corner-ripple-tl.png</file>
<file>corner-ripple-tr.png</file>
<file>endless-button-symbolic.svg</file>
+ <file>endless-help-symbolic.svg</file>
+ <file>feedback-symbolic.svg</file>
<file>hot-corner-symbolic.svg</file>
<file>hot-corner-rtl-symbolic.svg</file>
<file>mini-icon-active-indicator.png</file>
+ <file>system-logout.png</file>
</gresource>
</gresources>
diff --git a/data/theme/endless-help-symbolic.svg b/data/theme/endless-help-symbolic.svg
new file mode 100755
index 0000000000..cf88058f39
--- /dev/null
+++ b/data/theme/endless-help-symbolic.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>Asset 4</title><rect width="16"
height="16" style="opacity:0.020000020042061806;isolation:isolate"/><path
d="M12,1.529H4a2.889,2.889,0,0,0-3,2.88v5.24a2.889,2.889,0,0,0,3,2.88H5.475l2.463,2.463,2.587-2.463H12a2.889,2.889,0,0,0,3-2.88V4.409A2.889,2.889,0,0,0,12,1.529ZM7.949,3.417c1.619,0,2.429.97,2.429,1.969a2.138,2.138,0,0,1-.97,1.8l-.38.279a1.154,1.154,0,0,0-.589.97H7.249A2.069,2.069,0,0,1,7.209,8a1.721,1.721,0,0,1,.76-1.409l.51-.38a.82.82,0,0,0,.359-.7.792.792,0,0,0-.889-.77.914.914,0,0,0-.919.939c0,.069,0,.126,0,.173L5.629,5.782c-.006-.071-.009-.141-.009-.206A2.159,2.159,0,0,1,7.949,3.417Zm.8,6.477a.865.865,0,1,1-.87-.869A.868.868,0,0,1,8.748,9.894Z"
style="fill:#bebebe"/></svg>
\ No newline at end of file
diff --git a/data/theme/feedback-symbolic.svg b/data/theme/feedback-symbolic.svg
new file mode 100644
index 0000000000..2df92d0f20
--- /dev/null
+++ b/data/theme/feedback-symbolic.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="12px" height="18px" viewBox="-0.5 0.5 12 18" enable-background="new -0.5 0.5 12 18"
xml:space="preserve">
+<g id="Captions">
+</g>
+<path
d="M9.5,11.5h-7l-3-3v3v5c0,1.105,0.895,2,2,2h8c1.105,0,2-0.895,2-2v-3C11.5,12.395,10.605,11.5,9.5,11.5z
M9.5,16.5h-8v-1h8
+ V16.5z M9.5,14.5h-8v-1h8V14.5z"/>
+<path d="M9.5,0.5h-8c-1.105,0-2,0.895-2,2v3c0,1.105,0.895,2,2,2h7l3,3v-3v-5C11.5,1.395,10.605,0.5,9.5,0.5z
M9.5,5.5h-8v-1h8V5.5z
+ M9.5,3.5h-8v-1h8V3.5z"/>
+</svg>
diff --git a/data/theme/gnome-shell-sass/_endless.scss b/data/theme/gnome-shell-sass/_endless.scss
index fe0fd940ee..c7bf1aabba 100644
--- a/data/theme/gnome-shell-sass/_endless.scss
+++ b/data/theme/gnome-shell-sass/_endless.scss
@@ -95,6 +95,11 @@
-arrow-background-color: #000000;
}
+popup-separator-menu-item {
+ margin: 12px 0;
+ padding: 0;
+}
+
// Apps Icon Bar
#appIconBar {
@@ -215,6 +220,43 @@
}
}
+// User Menu
+
+.user-menu-button-icon {
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-radius: 17px;
+ background-size: 34px;
+ padding: 0px;
+
+ &:hover {
+ border-radius: 18px;
+ background-size: 36px;
+ }
+}
+
+.user-menu-avatar {
+ width: 60px;
+ height: 60px;
+ background-size: contain;
+ background-color: rgba(50, 50, 50, 0.80);
+ border-radius: 30px;
+ border: 1px solid #000;
+
+ &:hover {
+ border: 1px solid #555;
+ }
+}
+
+.user-menu-name {
+ text-align: center;
+ font-weight: bold;
+ color: white;
+}
+
+.user-menu-items {
+ margin: 6px 0px;
+}
+
// Endless Button
%endless-button-hover {
diff --git a/data/theme/system-logout.png b/data/theme/system-logout.png
new file mode 100644
index 0000000000..e6de3e64ed
Binary files /dev/null and b/data/theme/system-logout.png differ
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index e2ef9f48de..1baea14d28 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -147,6 +147,7 @@
<file>ui/forceAppExitDialog.js</file>
<file>ui/hotCorner.js</file>
<file>ui/sideComponent.js</file>
+ <file>ui/userMenu.js</file>
<file>ui/workspaceMonitor.js</file>
</gresource>
</gresources>
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 218506d960..d387d123a6 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -21,9 +21,6 @@ var APP_MENU_ICON_MARGIN = 0;
var BUTTON_DND_ACTIVATION_TIMEOUT = 250;
-const SETTINGS_TEXT = _('All Settingsā¦');
-const CONTROL_CENTER_LAUNCHER = "gnome-control-center.desktop";
-
// To make sure the panel corners blend nicely with the panel,
// we draw background and borders the same way, e.g. drawing
// them as filled shapes from the outside inwards instead of
@@ -768,17 +765,6 @@ class AggregateMenu extends PanelMenu.Button {
if (!userMode)
this._indicators.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
- let gicon = new Gio.ThemedIcon({ name: 'applications-system-symbolic' });
- this.menu.addAction(SETTINGS_TEXT, () => {
- this.menu.close(BoxPointer.PopupAnimation.NONE);
- Main.overview.hide();
-
- let app = Shell.AppSystem.get_default().lookup_app(CONTROL_CENTER_LAUNCHER);
- let context = new AppActivation.AppActivationContext(app);
- context.activate();
- }, gicon);
-
- this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
if (this._network)
this.menu.addMenuItem(this._network.menu);
@@ -800,6 +786,38 @@ class AggregateMenu extends PanelMenu.Button {
}
});
+var UserMenu = GObject.registerClass(
+class UserMenu extends PanelMenu.Button {
+ _init() {
+ super._init(0.0, C_("User menu", "User Menu"), false);
+
+ this.accessible_role = Atk.Role.MENU;
+
+ let menuLayout = new AggregateLayout();
+ this.menu.box.set_layout_manager(menuLayout);
+ this.menu.actor.add_style_class_name('aggregate-menu');
+
+ this._userMenu = new imports.ui.userMenu.UserMenu();
+ this.add_child(this._userMenu.panelBox);
+ this.menu.addMenuItem(this._userMenu.menu);
+ this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+
+ let systemIndicator = new imports.ui.status.system.Indicator();
+ this.menu.addMenuItem(systemIndicator.menu);
+
+ menuLayout.addSizeChild(systemIndicator.menu.actor);
+
+ // We need to monitor the session to know when to show the button
+ Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
+ this._sessionUpdated();
+ }
+
+ _sessionUpdated() {
+ this.visible = !Main.sessionMode.isGreeter;
+ this.setSensitive(!Main.sessionMode.isLocked);
+ }
+});
+
var PowerMenu = GObject.registerClass(
class PopoverMenu extends PanelMenu.SingleIconButton {
_init() {
@@ -838,6 +856,7 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator,
'hotCorner': imports.ui.hotCorner.HotCorner,
'powerMenu': PowerMenu,
+ 'userMenu': UserMenu,
};
var Panel = GObject.registerClass(
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index 5bb4680eea..20ab2db52e 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -541,7 +541,7 @@ var PopupMenuBase = class {
return menuItem;
}
- addSettingsAction(title, desktopFile) {
+ addSettingsAction(title, desktopFile, icon) {
let menuItem = this.addAction(title, () => {
let app = Shell.AppSystem.get_default().lookup_app(desktopFile);
@@ -552,7 +552,7 @@ var PopupMenuBase = class {
Main.overview.hide();
app.activate();
- });
+ }, icon);
menuItem.visible = Main.sessionMode.allowSettings;
this._settingsActions[desktopFile] = menuItem;
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
index 4cc4be895f..d24ab760cb 100644
--- a/js/ui/sessionMode.js
+++ b/js/ui/sessionMode.js
@@ -89,7 +89,8 @@ const _modes = {
panel: {
left: ['endlessButton', 'appIcons'],
center: [],
- right: ['dwellClick', 'a11y', 'keyboard', 'aggregateMenu', 'dateMenu', 'hotCorner'],
+ right: ['dwellClick', 'a11y', 'keyboard', 'aggregateMenu', 'dateMenu',
+ 'userMenu', 'hotCorner'],
},
},
};
diff --git a/js/ui/userMenu.js b/js/ui/userMenu.js
new file mode 100644
index 0000000000..a3d35ebbdd
--- /dev/null
+++ b/js/ui/userMenu.js
@@ -0,0 +1,187 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+/* exported UserMenu */
+
+const { AccountsService, Clutter, GLib,
+ Gio, Pango, Shell, St } = imports.gi;
+
+const AppActivation = imports.ui.appActivation;
+const BoxPointer = imports.ui.boxpointer;
+const Main = imports.ui.main;
+const PopupMenu = imports.ui.popupMenu;
+const UserWidget = imports.ui.userWidget;
+
+const USER_ICON_SIZE = 34;
+
+const ONLINE_ACCOUNTS_TEXT = _('Social Accounts');
+const ONLINE_ACCOUNTS_PANEL_LAUNCHER = 'gnome-online-accounts-panel.desktop';
+
+const SETTINGS_TEXT = _('Settings');
+const SETTINGS_LAUNCHER = 'gnome-control-center.desktop';
+
+const USER_ACCOUNTS_PANEL_LAUNCHER = 'gnome-user-accounts-panel.desktop';
+
+const FEEDBACK_TEXT = _('Give Us Feedback');
+const FEEDBACK_LAUNCHER = "eos-link-feedback.desktop";
+
+const HELP_CENTER_TEXT = _('Help');
+const HELP_CENTER_LAUNCHER = 'org.gnome.Yelp.desktop';
+
+const UserAccountSection = class extends PopupMenu.PopupMenuSection {
+ constructor(user) {
+ super();
+
+ // User account's icon
+ this.userIconItem = new PopupMenu.PopupBaseMenuItem({
+ reactive: false,
+ can_focus: false,
+ });
+ this.userIconItem.set({
+ x_align: Clutter.ActorAlign.CENTER,
+ x_expand: true,
+ });
+
+ this._user = user;
+ this._avatar = new UserWidget.Avatar(this._user, {
+ reactive: true,
+ styleClass: 'user-menu-avatar',
+ });
+ this._avatar.x_align = Clutter.ActorAlign.CENTER;
+
+ let iconButton = new St.Button({ child: this._avatar });
+ this.userIconItem.add_child(iconButton);
+
+ iconButton.connect('clicked', () => {
+ if (Main.sessionMode.allowSettings)
+ this.userIconItem.activate(null);
+ });
+
+ this.userIconItem.connect('notify::sensitive', () => {
+ this._avatar.setSensitive(this.userIconItem.getSensitive);
+ });
+ this.addMenuItem(this.userIconItem);
+
+ // User account's name
+ this.userLabelItem = new PopupMenu.PopupBaseMenuItem({
+ reactive: false,
+ can_focus: false,
+ });
+ this._label = new St.Label({ style_class: 'user-menu-name' });
+ this._label.clutter_text.set({
+ x_align: Clutter.ActorAlign.CENTER,
+ x_expand: true,
+ ellipsize: Pango.EllipsizeMode.NONE,
+ line_wrap: true,
+ });
+ this.userLabelItem.add_child(this._label);
+ this.addMenuItem(this.userLabelItem);
+
+ // We need to monitor the session to know when to enable the user avatar
+ Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
+ this._sessionUpdated();
+ }
+
+ _sessionUpdated() {
+ this.userIconItem.setSensitive(Main.sessionMode.allowSettings);
+ }
+
+ update() {
+ this._avatar.update();
+
+ if (this._user.is_loaded)
+ this._label.set_text(this._user.get_real_name());
+ else
+ this._label.set_text('');
+ }
+};
+
+var UserMenu = class {
+ constructor() {
+ this._userManager = AccountsService.UserManager.get_default();
+ this._user = this._userManager.get_user(GLib.get_user_name());
+
+ this._user.connect('notify::is-loaded', this._updateUser.bind(this));
+ this._user.connect('changed', this._updateUser.bind(this));
+
+ this._createPanelIcon();
+ this._createPopupMenu();
+
+ this._updateUser();
+ }
+
+ _createPanelIcon() {
+ this.panelBox = new St.BoxLayout({
+ x_align: Clutter.ActorAlign.CENTER,
+ y_align: Clutter.ActorAlign.CENTER,
+ });
+ this._panelAvatar = new UserWidget.Avatar(this._user, {
+ iconSize: USER_ICON_SIZE,
+ styleClass: 'user-menu-button-icon',
+ reactive: true,
+ });
+ this.panelBox.add_actor(this._panelAvatar);
+ }
+
+ _createPopupMenu() {
+ this.menu = new PopupMenu.PopupMenuSection();
+
+ this._accountSection = new UserAccountSection(this._user);
+ this._accountSection.userIconItem.connect('activate', () => {
+ this._launchApplication(USER_ACCOUNTS_PANEL_LAUNCHER);
+ });
+
+ this.menu.addMenuItem(this._accountSection);
+ this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+
+ let menuItemsSection = new PopupMenu.PopupMenuSection();
+ menuItemsSection.box.style_class = 'user-menu-items';
+
+ // Control Center
+ let gicon = new Gio.ThemedIcon({ name: 'applications-system-symbolic' });
+ this._settingsItem = menuItemsSection.addAction(SETTINGS_TEXT, () => {
+ this._launchApplication(SETTINGS_LAUNCHER);
+ }, gicon);
+
+ // Social
+ gicon = new Gio.ThemedIcon({ name: 'user-available-symbolic' });
+ menuItemsSection.addSettingsAction(ONLINE_ACCOUNTS_TEXT, ONLINE_ACCOUNTS_PANEL_LAUNCHER, gicon);
+
+ // Feedback
+ let iconFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/feedback-symbolic.svg');
+ gicon = new Gio.FileIcon({ file: iconFile });
+ menuItemsSection.addAction(FEEDBACK_TEXT, () => {
+ this._launchApplication(FEEDBACK_LAUNCHER);
+ }, gicon);
+ this.menu.addMenuItem(menuItemsSection);
+
+ // Help center
+ iconFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/endless-help-symbolic.svg');
+ gicon = new Gio.FileIcon({ file: iconFile });
+ menuItemsSection.addAction(HELP_CENTER_TEXT, () => {
+ this._launchApplication(HELP_CENTER_LAUNCHER);
+ }, gicon);
+ this.menu.addMenuItem(menuItemsSection);
+
+ // We need to monitor the session to know when to show/hide the settings item
+ Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
+ this._sessionUpdated();
+ }
+
+ _launchApplication(launcherName) {
+ this.menu.close(BoxPointer.PopupAnimation.NONE);
+ Main.overview.hide();
+
+ let app = Shell.AppSystem.get_default().lookup_app(launcherName);
+ let context = new AppActivation.AppActivationContext(app);
+ context.activate();
+ }
+
+ _updateUser() {
+ this._panelAvatar.update();
+ this._accountSection.update();
+ }
+
+ _sessionUpdated() {
+ this._settingsItem.visible = Main.sessionMode.allowSettings;
+ }
+};
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bae933a610..2d39b74683 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -101,3 +101,4 @@ js/ui/appIconBar.js
js/ui/endlessButton.js
js/ui/forceAppExitDialog.js
js/ui/hotCorner.js
+js/ui/userMenu.js
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]