From 776b04ec9f73011046a16c2038c3b893d9e7eef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bellegarde?= Date: Fri, 9 Dec 2022 16:05:35 +0100 Subject: [PATCH] client: Rework headerbar buttons to fit small screens - Rework components-conversation-actions.ui - Merge copy/move popovers - Populate copy/move popover on the fly Initial workaround for #1185, #1306, #1444, #1164, #1414 TODO: move to AdwBreakPoints from libadwaita --- desktop/org.gnome.Geary.gschema.xml | 6 + .../application/application-main-window.vala | 106 +++-------------- .../components-conversation-actions.vala | 85 ++++++-------- src/client/components/folder-popover.vala | 64 +++++----- ui/components-conversation-actions.ui | 111 ++++++------------ ui/folder-popover.ui | 20 ++++ 6 files changed, 153 insertions(+), 239 deletions(-) diff --git a/desktop/org.gnome.Geary.gschema.xml b/desktop/org.gnome.Geary.gschema.xml index 6d4711cc..85742cf0 100644 --- a/desktop/org.gnome.Geary.gschema.xml +++ b/desktop/org.gnome.Geary.gschema.xml @@ -39,6 +39,12 @@ True if we should display a short preview of each message. + + false + Move messages by default + When tagging a message, move it to destination folder. + + false Use single key shortcuts diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala index d9f521c8..1a63ae4b 100644 --- a/src/client/application/application-main-window.vala +++ b/src/client/application/application-main-window.vala @@ -27,7 +27,6 @@ public class Application.MainWindow : public const string ACTION_SEARCH = "search"; public const string ACTION_SELECT_INBOX = "select-inbox"; public const string ACTION_SHOW_COPY_MENU = "show-copy-menu"; - public const string ACTION_SHOW_MOVE_MENU = "show-move-menu"; public const string ACTION_TOGGLE_JUNK = "toggle-conversation-junk"; public const string ACTION_TRASH_CONVERSATION = "trash-conversation"; public const string ACTION_ZOOM = "zoom"; @@ -56,7 +55,6 @@ public class Application.MainWindow : { ACTION_TRASH_CONVERSATION, on_trash_conversation }, { ACTION_DELETE_CONVERSATION, on_delete_conversation }, { ACTION_SHOW_COPY_MENU, on_show_copy_menu }, - { ACTION_SHOW_MOVE_MENU, on_show_move_menu }, { ACTION_CONVERSATION_UP, on_conversation_up }, { ACTION_CONVERSATION_DOWN, on_conversation_down }, // Message marking actions @@ -414,6 +412,7 @@ public class Application.MainWindow : [GtkChild] private unowned Gtk.Box conversation_list_box; [GtkChild] private unowned Gtk.Revealer conversation_list_actions_revealer; [GtkChild] private unowned Components.ConversationActions conversation_list_actions; + [GtkChild] private unowned Components.ConversationActions conversation_viewer_actions; [GtkChild] private unowned Gtk.Box conversation_viewer_box; [GtkChild] private unowned Gtk.Revealer conversation_viewer_actions_revealer; @@ -423,7 +422,6 @@ public class Application.MainWindow : [GtkChild] private unowned Components.InfoBarStack info_bars; private Components.ConversationActions[] folder_conversation_actions = {}; - private FolderPopover[] folder_popovers = {}; private Components.InfoBar offline_infobar; private Components.InfoBar cert_problem_infobar; @@ -478,12 +476,6 @@ public class Application.MainWindow : activate_action(get_window_action(ACTION_SHOW_COPY_MENU)); } - /** Keybinding signal for showing the move menu. */ - [Signal (action=true)] - public virtual signal void show_move_menu() { - activate_action(get_window_action(ACTION_SHOW_MOVE_MENU)); - } - /** Keybinding signal for archiving the current selection. */ [Signal (action=true)] public virtual signal void archive_conversations() { @@ -789,10 +781,6 @@ public class Application.MainWindow : // selected model. if (this.selected_folder != null) { - foreach (var menu in this.folder_popovers) { - menu.enable_disable_folder(this.selected_folder, true); - } - this.progress_monitor.remove(this.selected_folder.opening_monitor); this.selected_folder.properties.notify.disconnect(update_headerbar); this.selected_folder = null; @@ -862,11 +850,6 @@ public class Application.MainWindow : } this.conversation_list_view.set_monitor(this.conversations); - // disable copy/move to the new folder - foreach (var menu in this.folder_popovers) { - menu.enable_disable_folder(to_select, false); - } - yield open_conversation_monitor(this.conversations, cancellable); yield this.controller.process_pending_composers(); } @@ -1197,11 +1180,6 @@ public class Application.MainWindow : } foreach (var context in to_add) { this.folder_list.add_folder(context); - if (context.folder.account == this.selected_account) { - foreach (var menu in this.folder_popovers) { - menu.add_folder(context, map); - } - } context.folder.use_changed.connect(on_use_changed); } } @@ -1219,11 +1197,6 @@ public class Application.MainWindow : } folder.use_changed.disconnect(on_use_changed); - if (folder.account == this.selected_account) { - foreach (var menu in this.folder_popovers) { - menu.remove_folder(folder); - } - } this.folder_list.remove_folder(context); } } @@ -1415,18 +1388,20 @@ public class Application.MainWindow : this.conversation_list_actions.set_mark_inverted(); + this.conversation_headerbar.full_actions.init(this.application.config); + this.conversation_list_actions.init(this.application.config); + this.conversation_viewer_actions.init(this.application.config); + this.folder_conversation_actions = { this.conversation_headerbar.full_actions, - this.conversation_list_actions + this.conversation_list_actions, + this.conversation_viewer_actions }; - foreach (var actions in this.folder_conversation_actions) { - var move = actions.move_folder_menu; - this.folder_popovers += move; - move.folder_selected.connect(on_move_conversation); - var copy = actions.copy_folder_menu; - this.folder_popovers += copy; - copy.folder_selected.connect(on_copy_conversation); + foreach (var actions in this.folder_conversation_actions) { + var popover = actions.copy_move_popover; + popover.copy_conversation.connect(on_copy_conversation); + popover.move_conversation.connect(on_move_conversation); } } @@ -1590,40 +1565,14 @@ public class Application.MainWindow : private void select_account(Geary.Account? account) { if (this.selected_account != account) { - if (this.selected_account != null) { - foreach (var menu in this.folder_popovers) { - menu.clear(); - } - } - this.selected_account = account; this.search_bar.set_account(account); if (account != null) { - var service_provider = account.information.service_provider; - this.conversation_list_actions.service_provider = service_provider; - this.conversation_headerbar.full_actions.service_provider = service_provider; - this.conversation_headerbar.compact_actions.service_provider = service_provider; - - foreach (var menu in this.folder_popovers) { - var folders = account.list_folders(); - // Build map between path and display name for - // special directories - var map = new Gee.HashMap(); - foreach (var folder in folders) { - var context = new Application.FolderContext(folder); - if (folder.used_as == Geary.Folder.SpecialUse.NONE) - continue; - map.set( - folder.path.to_string().substring(1), - context.display_name - ); - } - foreach (var folder in folders) { - var context = new Application.FolderContext(folder); - menu.add_folder(context, map); - } - } + this.conversation_list_actions.account = account; + this.conversation_viewer_actions.account = account; + this.conversation_headerbar.full_actions.account = account; + this.conversation_headerbar.compact_actions.account = account; } update_command_actions(); @@ -1894,18 +1843,10 @@ public class Application.MainWindow : get_window_action(ACTION_REPLY_ALL_CONVERSATION).set_enabled(reply_sensitive); get_window_action(ACTION_FORWARD_CONVERSATION).set_enabled(reply_sensitive); - bool move_enabled = ( - sensitive && (this.selected_folder is Geary.FolderSupport.Move) - ); - get_window_action(ACTION_SHOW_MOVE_MENU).set_enabled(move_enabled); - foreach (var actions in this.folder_conversation_actions) { - actions.set_move_sensitive(move_enabled); - } - bool copy_enabled = ( sensitive && (this.selected_folder is Geary.FolderSupport.Copy) ); - get_window_action(ACTION_SHOW_COPY_MENU).set_enabled(move_enabled); + get_window_action(ACTION_SHOW_COPY_MENU).set_enabled(copy_enabled); foreach (var actions in this.folder_conversation_actions) { actions.set_copy_sensitive(copy_enabled); } @@ -1979,10 +1920,6 @@ public class Application.MainWindow : sensitive && (supported_operations.contains(typeof(Geary.FolderSupport.Copy))) ); - get_window_action(ACTION_SHOW_MOVE_MENU).set_enabled( - sensitive && - (supported_operations.contains(typeof(Geary.FolderSupport.Move))) - ); } } @@ -2492,17 +2429,6 @@ public class Application.MainWindow : } } - private void on_show_move_menu() { - if (this.is_conversation_list_shown && - this.conversation_list_actions_revealer.child_revealed) { - this.conversation_list_actions.show_move_menu(); - } else if (this.is_conversation_viewer_shown) { - this.conversation_headerbar.shown_actions.show_move_menu(); - } else { - error_bell(); - } - } - private void on_conversation_up() { this.conversation_list_view.scroll(Gtk.ScrollType.STEP_UP); } diff --git a/src/client/components/components-conversation-actions.vala b/src/client/components/components-conversation-actions.vala index 0483b9f3..080cb51c 100644 --- a/src/client/components/components-conversation-actions.vala +++ b/src/client/components/components-conversation-actions.vala @@ -18,22 +18,23 @@ public class Components.ConversationActions : Gtk.Box { public bool pack_justified { get; construct; } - public FolderPopover copy_folder_menu { get; private set; default = new FolderPopover(); } - - public FolderPopover move_folder_menu { get; private set; default = new FolderPopover(); } + public FolderPopover copy_move_popover { + get { + unowned var popover = this.copy_message_button.popover as FolderPopover; + return popover; + } + } public int selected_conversations { get; set; } - public Geary.ServiceProvider service_provider { get; set; } + public Geary.Account account { get; set; } [GtkChild] private unowned Gtk.Box response_buttons { get; } - [GtkChild] private unowned Gtk.Box mark_copy_move_buttons { get; } [GtkChild] private unowned Gtk.MenuButton mark_message_button { get; } [GtkChild] private unowned Gtk.MenuButton copy_message_button { get; } - [GtkChild] private unowned Gtk.MenuButton move_message_button { get; } - [GtkChild] private unowned Gtk.Box archive_trash_delete_buttons { get; } + [GtkChild] private unowned Gtk.Box action_buttons { get; } [GtkChild] private unowned Gtk.Button archive_button; [GtkChild] private unowned Gtk.Button trash_delete_button; @@ -60,8 +61,6 @@ public class Components.ConversationActions : Gtk.Box { this.notify["selected-conversations"].connect(() => update_conversation_buttons()); this.notify["service-provider"].connect(() => update_conversation_buttons()); this.mark_message_button.popover = new Gtk.Popover.from_model(null, mark_menu); - this.copy_message_button.popover = copy_folder_menu; - this.move_message_button.popover = move_folder_menu; this.mark_message_button.toggled.connect((button) => { if (button.active) @@ -69,21 +68,20 @@ public class Components.ConversationActions : Gtk.Box { }); this.response_buttons.set_visible(this.show_response_actions); - this.mark_copy_move_buttons.set_visible(this.show_conversation_actions); - this.archive_trash_delete_buttons.set_visible(this.show_conversation_actions); + this.action_buttons.set_visible(this.show_conversation_actions); if (this.pack_justified) { - this.archive_trash_delete_buttons.hexpand = true; - this.archive_trash_delete_buttons.halign = END; + this.action_buttons.hexpand = true; + this.action_buttons.halign = END; } } - public void set_move_sensitive(bool is_sensitive) { - this.move_message_button.sensitive = is_sensitive; - } - - public void show_move_menu() { - this.move_message_button.clicked(); + public void init(Application.Configuration config) { + this.copy_message_button.popover = new FolderPopover(config); + this.bind_property( + "account", this.copy_message_button.popover, + "account", BindingFlags.DEFAULT + ); } public void set_copy_sensitive(bool is_sensitive) { @@ -121,43 +119,34 @@ public class Components.ConversationActions : Gtk.Box { this.selected_conversations ); - this.move_message_button.tooltip_text = ngettext( - "Move conversation", - "Move conversations", - this.selected_conversations - ); this.archive_button.tooltip_text = ngettext( "Archive conversation", "Archive conversations", this.selected_conversations ); - var copy_icon_name = "edit-copy-symbolic"; - var move_icon_name = "edit-cut-symbolic"; - switch (this.service_provider) { - case Geary.ServiceProvider.GMAIL: - this.copy_message_button.tooltip_text = ngettext( - "Add label to conversation", - "Add label to conversations", - this.selected_conversations + if (this.account != null) { + switch (this.account.information.service_provider) { + case Geary.ServiceProvider.GMAIL: + this.copy_message_button.tooltip_text = ngettext( + "Add label to conversation", + "Add label to conversations", + this.selected_conversations + ); + this.copy_message_button.set_image( + new Gtk.Image.from_icon_name( + "tag-symbolic", Gtk.IconSize.BUTTON) ); - copy_icon_name = "tag-symbolic"; - move_icon_name = "folder-symbolic"; - break; - default: - this.copy_message_button.tooltip_text = ngettext( - "Copy conversation", - "Copy conversations", - this.selected_conversations - ); - break; + break; + default: + this.copy_message_button.tooltip_text = ngettext( + "Copy conversation", + "Copy conversations", + this.selected_conversations + ); + break; + } } - this.copy_message_button.set_image( - new Gtk.Image.from_icon_name(copy_icon_name, Gtk.IconSize.BUTTON) - ); - this.move_message_button.set_image( - new Gtk.Image.from_icon_name(move_icon_name, Gtk.IconSize.BUTTON) - ); if (this.show_trash_button) { this.trash_delete_button.action_name = Action.Window.prefix( diff --git a/src/client/components/folder-popover.vala b/src/client/components/folder-popover.vala index 90dfd81f..abbe75c9 100644 --- a/src/client/components/folder-popover.vala +++ b/src/client/components/folder-popover.vala @@ -9,12 +9,16 @@ public class FolderPopover : Gtk.Popover { [GtkChild] private unowned Gtk.SearchEntry search_entry; [GtkChild] private unowned Gtk.ListBox list_box; + [GtkChild] private unowned Gtk.Switch move_switch; + + public Geary.Account account {get; set;} private int filtered_folder_count = 0; - public signal void folder_selected(Geary.Folder folder); + public signal void copy_conversation(Geary.Folder folder); + public signal void move_conversation(Geary.Folder folder); - public FolderPopover() { + public FolderPopover(Application.Configuration config) { list_box.set_filter_func(row_filter); list_box.set_sort_func(row_sort); this.show.connect(() => search_entry.grab_focus()); @@ -22,17 +26,14 @@ public class FolderPopover : Gtk.Popover { search_entry.set_text(""); invalidate_filter(); }); + config.bind("move-messages-on-tag", this.move_switch, "active"); } - public bool has_folder(Geary.Folder folder) { - return get_row_with_folder(folder) != null; - } - - public void add_folder(Application.FolderContext context, Gee.HashMap map) { + private void add_folder(Application.FolderContext context, Gee.HashMap map) { Geary.Folder folder = context.folder; // don't allow multiples and don't allow folders that can't be opened (that means they // support almost no operations and have no content) - if (has_folder(folder) || folder.properties.is_openable.is_impossible()) + if (folder.properties.is_openable.is_impossible()) return; // also don't allow local-only or virtual folders, which also have a limited set of @@ -66,28 +67,29 @@ public class FolderPopover : Gtk.Popover { list_box.invalidate_sort(); } - public void enable_disable_folder(Geary.Folder folder, bool visible) { - Gtk.ListBoxRow row = get_row_with_folder(folder); - if (row != null) - row.visible = visible; + [GtkCallback] + private void on_map(Gtk.Widget widget) { + var folders = this.account.list_folders(); + // Build map between path and display name for + // special directories + var map = new Gee.HashMap(); + foreach (var folder in folders) { + var context = new Application.FolderContext(folder); + if (folder.used_as == Geary.Folder.SpecialUse.NONE) + continue; + map.set( + folder.path.to_string().substring(1), + context.display_name + ); + } + foreach (var folder in folders) { + var context = new Application.FolderContext(folder); + this.add_folder(context, map); + } } - public void remove_folder(Geary.Folder folder) { - Gtk.ListBoxRow row = get_row_with_folder(folder); - if (row != null) - list_box.remove(row); - } - - public Gtk.ListBoxRow? get_row_with_folder(Geary.Folder folder) { - Gtk.ListBoxRow result = null; - list_box.foreach((row) => { - if (row.get_data("folder") == folder) - result = row as Gtk.ListBoxRow; - }); - return result; - } - - public void clear() { + [GtkCallback] + private void on_unmap(Gtk.Widget widget) { list_box.foreach((row) => list_box.remove(row)); } @@ -95,7 +97,11 @@ public class FolderPopover : Gtk.Popover { private void on_row_activated(Gtk.ListBoxRow? row) { if (row != null) { Geary.Folder folder = row.get_data("folder"); - folder_selected(folder); + if (this.move_switch.active) { + move_conversation(folder); + } else { + copy_conversation(folder); + } } this.hide(); diff --git a/ui/components-conversation-actions.ui b/ui/components-conversation-actions.ui index 744a464c..5e4b02c8 100644 --- a/ui/components-conversation-actions.ui +++ b/ui/components-conversation-actions.ui @@ -79,7 +79,11 @@ - + + True + mail-archive-symbolic + + True @@ -89,25 +93,6 @@ True - True - tag-symbolic - - - - - False - False - 0 - - - - - True - False - False - True - - True folder-symbolic @@ -116,7 +101,40 @@ False False - 1 + + + + + True + False + False + win.archive-conversation + archive_image + True + True + + + False + False + + + + + True + False + False + win.trash-conversation + True + + + True + user-trash-symbolic + + + + + False + False @@ -138,57 +156,6 @@ False False - 2 - - - - - - - - True - mail-archive-symbolic - - - True - - - _Archive - True - False - False - win.archive-conversation - archive_image - True - True - - - False - False - 0 - - - - - True - False - False - win.trash-conversation - True - - - True - user-trash-symbolic - - - - - False - False - 1