From 259ebe50fdde9b6298e0d3a05a55b3b007686059 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Thu, 21 Nov 2019 02:36:09 +1100 Subject: [PATCH] Re-implement single key shortcuts as a preference Add new `single-key-shortcuts` GSetting, Application.Configuration property and add UI for it in the Preferences window. When enabled, load in new `single-key-shortcuts.css` file that has the appropriate bindings. Update bindings to match Google's current set, and update shortcut help to match. --- desktop/org.gnome.Geary.gschema.xml | 8 ++++ .../application/application-client.vala | 47 +++++++++++++++---- .../application-configuration.vala | 7 ++- .../components-preferences-window.vala | 43 +++++++++++++++-- ui/application-main-window.ui | 3 ++ ui/gtk/help-overlay.ui | 36 ++++++++++++-- ui/org.gnome.Geary.gresource.xml | 1 + ui/single-key-shortcuts.css | 39 +++++++++++++++ 8 files changed, 166 insertions(+), 18 deletions(-) create mode 100644 ui/single-key-shortcuts.css diff --git a/desktop/org.gnome.Geary.gschema.xml b/desktop/org.gnome.Geary.gschema.xml index 9f2467b5..f0068798 100644 --- a/desktop/org.gnome.Geary.gschema.xml +++ b/desktop/org.gnome.Geary.gschema.xml @@ -63,6 +63,14 @@ True if we should display a short preview of each message. + + false + Use single key shortcuts + Enables shortcuts for email actions that do not + require pressing <Ctrl> to emulate those used by + Gmail. + + nothing Languages that shall be used in the spell checker diff --git a/src/client/application/application-client.vala b/src/client/application/application-client.vala index 88d99c5b..2eef6a7f 100644 --- a/src/client/application/application-client.vala +++ b/src/client/application/application-client.vala @@ -243,6 +243,7 @@ public class Application.Client : Gtk.Application { private File exec_dir; private string binary; private bool start_hidden = false; + private Gtk.CssProvider single_key_shortcuts = new Gtk.CssProvider(); private GLib.Cancellable controller_cancellable = new GLib.Cancellable(); private Components.Inspector? inspector = null; private Geary.Nonblocking.Mutex controller_mutex = new Geary.Nonblocking.Mutex(); @@ -427,15 +428,14 @@ public class Application.Client : Gtk.Application { provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); - provider.parsing_error.connect(on_css_parse_error); - try { - var file = GLib.File.new_for_uri( - "resource:///org/gnome/Geary/geary.css" - ); - provider.load_from_file(file); - } catch (GLib.Error error) { - warning("Could not load CSS: %s", error.message); - } + load_css(provider, + "resource:///org/gnome/Geary/geary.css"); + load_css(this.single_key_shortcuts, + "resource:///org/gnome/Geary/single-key-shortcuts.css"); + update_single_key_shortcuts(); + this.config.notify[Configuration.SINGLE_KEY_SHORTCUTS].connect( + on_single_key_shortcuts_toggled + ); MainWindow.add_accelerators(this); Composer.Widget.add_accelerators(this); @@ -980,6 +980,21 @@ public class Application.Client : Gtk.Application { set_accels_for_action("app." + action, accelerators); } + private void update_single_key_shortcuts() { + if (this.config.single_key_shortcuts) { + Gtk.StyleContext.add_provider_for_screen( + Gdk.Display.get_default().get_default_screen(), + this.single_key_shortcuts, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); + } else { + Gtk.StyleContext.remove_provider_for_screen( + Gdk.Display.get_default().get_default_screen(), + this.single_key_shortcuts + ); + } + } + private Geary.Folder? get_folder_from_action_target(GLib.Variant target) { Geary.Folder? folder = null; string id = (string) target.get_child_value(0); @@ -996,6 +1011,16 @@ public class Application.Client : Gtk.Application { return folder; } + private void load_css(Gtk.CssProvider provider, string resource_uri) { + provider.parsing_error.connect(on_css_parse_error); + try { + var file = GLib.File.new_for_uri(resource_uri); + provider.load_from_file(file); + } catch (GLib.Error error) { + warning("Could not load CSS: %s", error.message); + } + } + private void on_activate_about() { this.show_about.begin(); } @@ -1146,6 +1171,10 @@ public class Application.Client : Gtk.Application { } } + private void on_single_key_shortcuts_toggled() { + update_single_key_shortcuts(); + } + private void on_css_parse_error(Gtk.CssSection section, GLib.Error error) { uint start = section.get_start_line(); uint end = section.get_end_line(); diff --git a/src/client/application/application-configuration.vala b/src/client/application/application-configuration.vala index 051b4d7d..c8e95f83 100644 --- a/src/client/application/application-configuration.vala +++ b/src/client/application/application-configuration.vala @@ -9,7 +9,7 @@ /** * Provides properties to access application GSettings values. */ -public class Application.Configuration { +public class Application.Configuration : Geary.BaseObject { public const string ASK_OPEN_ATTACHMENT_KEY = "ask-open-attachment"; @@ -24,6 +24,7 @@ public class Application.Configuration { public const string FOLDER_LIST_PANE_POSITION_VERTICAL_KEY = "folder-list-pane-position-vertical"; public const string MESSAGES_PANE_POSITION_KEY = "messages-pane-position"; public const string SEARCH_STRATEGY_KEY = "search-strategy"; + public const string SINGLE_KEY_SHORTCUTS = "single-key-shortcuts"; public const string SPELL_CHECK_LANGUAGES = "spell-check-languages"; public const string SPELL_CHECK_VISIBLE_LANGUAGES = "spell-check-visible-languages"; public const string STARTUP_NOTIFICATIONS_KEY = "startup-notifications"; @@ -116,6 +117,8 @@ public class Application.Configuration { get { return settings.get_boolean(DISPLAY_PREVIEW_KEY); } } + public bool single_key_shortcuts { get; set; default = false; } + /** * The set of enabled spell checker languages. * @@ -216,6 +219,8 @@ public class Application.Configuration { gnome_interface = new Settings("org.gnome.desktop.interface"); Migrate.old_app_config(settings); + + this.bind(SINGLE_KEY_SHORTCUTS, this, SINGLE_KEY_SHORTCUTS); } public void bind(string key, Object object, string property, diff --git a/src/client/components/components-preferences-window.vala b/src/client/components/components-preferences-window.vala index 198395ad..9b9772fd 100644 --- a/src/client/components/components-preferences-window.vala +++ b/src/client/components/components-preferences-window.vala @@ -65,6 +65,19 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow { three_pane_view_row.activatable_widget = three_pane_view; three_pane_view_row.add_action(three_pane_view); + var single_key_shortucts = new Gtk.Switch(); + single_key_shortucts.valign = CENTER; + + var single_key_shortucts_row = new Hdy.ActionRow(); + /// Translators: Preferences label + single_key_shortucts_row.title = _("Use _single key email shortcuts"); + single_key_shortucts_row.tooltip_text = _( + "Enable keyboard shortcuts for email actions that do not require pressing " + ); + single_key_shortucts_row.use_underline = true; + single_key_shortucts_row.activatable_widget = single_key_shortucts; + single_key_shortucts_row.add_action(single_key_shortucts); + var startup_notifications = new Gtk.Switch(); startup_notifications.valign = CENTER; @@ -87,6 +100,7 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow { group.add(autoselect_row); group.add(display_preview_row); group.add(three_pane_view_row); + group.add(single_key_shortucts_row); group.add(startup_notifications_row); var page = new Hdy.PreferencesPage(); @@ -101,10 +115,31 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow { insert_action_group(Action.Window.GROUP_NAME, window_actions); Application.Configuration config = this.application.config; - config.bind(Application.Configuration.AUTOSELECT_KEY, autoselect, "state"); - config.bind(Application.Configuration.DISPLAY_PREVIEW_KEY, display_preview, "state"); - config.bind(Application.Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY, three_pane_view, "state"); - config.bind(Application.Configuration.STARTUP_NOTIFICATIONS_KEY, startup_notifications, "state"); + config.bind( + Application.Configuration.AUTOSELECT_KEY, + autoselect, + "state" + ); + config.bind( + Application.Configuration.DISPLAY_PREVIEW_KEY, + display_preview, + "state" + ); + config.bind( + Application.Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY, + three_pane_view, + "state" + ); + config.bind( + Application.Configuration.SINGLE_KEY_SHORTCUTS, + single_key_shortucts, + "state" + ); + config.bind( + Application.Configuration.STARTUP_NOTIFICATIONS_KEY, + startup_notifications, + "state" + ); this.delete_event.connect(on_delete); } diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui index c2802888..2166b836 100644 --- a/ui/application-main-window.ui +++ b/ui/application-main-window.ui @@ -450,5 +450,8 @@ Please check your login name and try again. + diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui index 4fe38dd8..08c29751 100644 --- a/ui/gtk/help-overlay.ui +++ b/ui/gtk/help-overlay.ui @@ -280,7 +280,7 @@ True Reply to all - <Shift>R + A @@ -301,21 +301,21 @@ True Mark/un-mark starred - S D + S True Archive conversation - A Y + E True Move conversation - M + V @@ -332,6 +332,34 @@ exclam + + + True + Delete conversation + numbersign + + + + + True + Find in current conversation + slash + + + + + True + Select the conversation down + J + + + + + True + Select the conversation up + K + + diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml index 0f1f8881..8ad731f0 100644 --- a/ui/org.gnome.Geary.gresource.xml +++ b/ui/org.gnome.Geary.gresource.xml @@ -45,5 +45,6 @@ signature-web-view.js upgrade_dialog.glade geary.css + single-key-shortcuts.css diff --git a/ui/single-key-shortcuts.css b/ui/single-key-shortcuts.css new file mode 100644 index 00000000..7073f754 --- /dev/null +++ b/ui/single-key-shortcuts.css @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Michael Gratton + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +/* + * These match Gmail's as of time of commit. Taken from: + * https://support.google.com/mail/answer/6594 + */ +@binding-set SingleKeyShortcuts { + bind "r" { "reply-conversation-sender" () }; + bind "a" { "reply-conversation-all" () }; + bind "f" { "forward-conversation" () }; + + bind "i" { "mark-conversations-read" (1) }; + bind "u" { "mark-conversations-read" (0) }; + bind "s" { "mark-conversations-starred" (1) }; + + bind "l" { "show-copy-menu" () }; + bind "v" { "show-move-menu" () }; + + bind "e" { "archive-conversations" () }; + /* ! */ + bind "exclam" { "junk-conversations" () }; + /* # */ + bind "numbersign" { "delete-conversations" () }; + + /* / */ + bind "slash" { "find" () }; + + bind "k" { "navigate" (step-up) }; + bind "j" { "navigate" (step-down) }; +} + +window.geary-main-window { + -gtk-key-bindings: SingleKeyShortcuts; +}