From 98017cfb390dd13dd5688711f8164e1a5e9bdcdf Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Thu, 8 Oct 2020 14:38:31 +0200 Subject: [PATCH 065/124] main-toolbar: Create object containing conversation actions This creates a new object that contain the 4 groups of actions that used to be in the conversation-viewer headerbar. This allows the widgets to be moved to differen locations, e.g. to an action bar that will be added in a later commit. --- po/POTFILES.in | 2 + .../application/application-main-window.vala | 61 +++-- .../components-conversation-actions.vala | 132 ++++++++++ src/client/components/main-toolbar.vala | 96 +------- src/client/meson.build | 1 + ui/application-main-window.ui | 2 +- ui/components-conversation-actions.ui | 221 +++++++++++++++++ ui/main-toolbar.ui | 230 ------------------ ui/org.gnome.Geary.gresource.xml | 1 + 9 files changed, 405 insertions(+), 341 deletions(-) create mode 100644 src/client/components/components-conversation-actions.vala create mode 100644 ui/components-conversation-actions.ui diff --git a/po/POTFILES.in b/po/POTFILES.in index 09c3c970..7ef4e050 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -39,6 +39,7 @@ src/client/application/secret-mediator.vala src/client/client-action.vala src/client/components/client-web-view.vala src/client/components/components-attachment-pane.vala +src/client/components/components-conversation-actions.vala src/client/components/components-entry-undo.vala src/client/components/components-in-app-notification.vala src/client/components/components-info-bar-stack.vala @@ -455,6 +456,7 @@ ui/composer-widget.ui ui/components-attachment-pane.ui ui/components-attachment-pane-menus.ui ui/components-attachment-view.ui +ui/components-conversation-actions.ui ui/components-in-app-notification.ui ui/components-inspector-error-view.ui ui/components-inspector-log-view.ui diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala index 3b7c29e7..20fc3758 100644 --- a/src/client/application/application-main-window.vala +++ b/src/client/application/application-main-window.vala @@ -284,6 +284,9 @@ public class Application.MainWindow : public ConversationListView conversation_list_view { get; private set; } public ConversationViewer conversation_viewer { get; private set; } + // Actions in the Conversation HeaderBar or ActionBar + private Components.ConversationActions conversation_actions; + public Components.InfoBarStack conversation_list_info_bars { get; private set; default = new Components.InfoBarStack(PRIORITY_QUEUE); } @@ -692,10 +695,10 @@ public class Application.MainWindow : // selected model. if (this.selected_folder != null) { - this.main_toolbar.copy_folder_menu.enable_disable_folder( + this.conversation_actions.copy_folder_menu.enable_disable_folder( this.selected_folder, true ); - this.main_toolbar.move_folder_menu.enable_disable_folder( + this.conversation_actions.move_folder_menu.enable_disable_folder( this.selected_folder, true ); @@ -740,9 +743,10 @@ public class Application.MainWindow : update_conversation_actions(NONE); update_title(); - this.main_toolbar.update_trash_button( + this.conversation_actions.update_trash_button( !this.is_shift_down && this.selected_folder_supports_trash ); + this.conversation_viewer.show_loading(); this.previous_selection_was_interactive = is_interactive; @@ -779,10 +783,10 @@ public class Application.MainWindow : this.conversation_list_view.set_model(conversations_model); // disable copy/move to the new folder - this.main_toolbar.copy_folder_menu.enable_disable_folder( + this.conversation_actions.copy_folder_menu.enable_disable_folder( to_select, false ); - this.main_toolbar.move_folder_menu.enable_disable_folder( + this.conversation_actions.move_folder_menu.enable_disable_folder( to_select, false ); @@ -1090,8 +1094,8 @@ public class Application.MainWindow : foreach (var context in to_add) { this.folder_list.add_folder(context); if (context.folder.account == this.selected_account) { - this.main_toolbar.copy_folder_menu.add_folder(context.folder); - this.main_toolbar.move_folder_menu.add_folder(context.folder); + this.conversation_actions.copy_folder_menu.add_folder(context.folder); + this.conversation_actions.move_folder_menu.add_folder(context.folder); } context.folder.use_changed.connect(on_use_changed); } @@ -1111,8 +1115,8 @@ public class Application.MainWindow : folder.use_changed.disconnect(on_use_changed); if (folder.account == this.selected_account) { - this.main_toolbar.copy_folder_menu.remove_folder(folder); - this.main_toolbar.move_folder_menu.remove_folder(folder); + this.conversation_actions.copy_folder_menu.remove_folder(folder); + this.conversation_actions.move_folder_menu.remove_folder(folder); } this.folder_list.remove_folder(context); } @@ -1228,6 +1232,7 @@ public class Application.MainWindow : this.search_bar.search_text_changed.connect(on_search); this.conversation_list_box.pack_start(this.search_bar, false, false, 0); + // Folder list this.folder_list.folder_selected.connect(on_folder_selected); this.folder_list.move_conversation.connect(on_move_conversation); @@ -1261,6 +1266,16 @@ public class Application.MainWindow : this.conversation_size_group.add_widget(this.conversation_viewer); this.main_leaflet.add_with_properties(this.conversation_viewer, "name", "conversation", null); + + // Setup conversation actions + this.conversation_actions = new Components.ConversationActions(); + this.conversation_actions.move_folder_menu.folder_selected.connect(on_move_conversation); + this.conversation_actions.copy_folder_menu.folder_selected.connect(on_copy_conversation); + this.conversation_actions.bind_property("find-open", + this.conversation_viewer.conversation_find_bar, + "search-mode-enabled", + BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); + // Main toolbar this.main_toolbar = new MainToolbar(config); this.main_toolbar.add_to_size_groups(this.folder_size_group, @@ -1270,12 +1285,8 @@ public class Application.MainWindow : this.conversation_size_group); this.main_toolbar.add_to_swipe_groups(this.conversations_swipe_group, this.conversation_swipe_group); - this.main_toolbar.move_folder_menu.folder_selected.connect(on_move_conversation); - this.main_toolbar.copy_folder_menu.folder_selected.connect(on_copy_conversation); this.main_toolbar.bind_property("search-open", this.search_bar, "search-mode-enabled", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); - this.main_toolbar.bind_property("find-open", this.conversation_viewer.conversation_find_bar, - "search-mode-enabled", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); if (config.desktop_environment == UNITY) { this.main_toolbar.show_close_button = false; this.main_layout.pack_start(main_toolbar, false, true, 0); @@ -1286,6 +1297,8 @@ public class Application.MainWindow : set_titlebar(titlebar); } + this.main_toolbar.add_conversation_actions(this.conversation_actions); + this.main_layout.pack_start(this.info_bars, false, true, 0); // Status bar @@ -1462,8 +1475,8 @@ public class Application.MainWindow : private void select_account(Geary.Account? account) { if (this.selected_account != account) { if (this.selected_account != null) { - this.main_toolbar.copy_folder_menu.clear(); - this.main_toolbar.move_folder_menu.clear(); + this.conversation_actions.copy_folder_menu.clear(); + this.conversation_actions.move_folder_menu.clear(); } this.selected_account = account; @@ -1471,8 +1484,8 @@ public class Application.MainWindow : if (account != null) { foreach (Geary.Folder folder in account.list_folders()) { - this.main_toolbar.copy_folder_menu.add_folder(folder); - this.main_toolbar.move_folder_menu.add_folder(folder); + this.conversation_actions.copy_folder_menu.add_folder(folder); + this.conversation_actions.move_folder_menu.add_folder(folder); } } @@ -1494,7 +1507,7 @@ public class Application.MainWindow : // setting it again. this.conversation_list_view.select_conversations(to_select); - this.main_toolbar.selected_conversations = to_select.size; + this.conversation_actions.selected_conversations = to_select.size; if (this.selected_folder != null && !this.has_composer) { switch(to_select.size) { case 0: @@ -1707,13 +1720,13 @@ public class Application.MainWindow : bool move_enabled = ( sensitive && (selected_folder is Geary.FolderSupport.Move) ); - this.main_toolbar.move_message_button.set_sensitive(move_enabled); + this.conversation_actions.move_message_button.set_sensitive(move_enabled); get_window_action(ACTION_SHOW_MOVE_MENU).set_enabled(move_enabled); bool copy_enabled = ( sensitive && (selected_folder is Geary.FolderSupport.Copy) ); - this.main_toolbar.copy_message_button.set_sensitive(copy_enabled); + this.conversation_actions.copy_message_button.set_sensitive(copy_enabled); get_window_action(ACTION_SHOW_COPY_MENU).set_enabled(move_enabled); get_window_action(ACTION_ARCHIVE_CONVERSATION).set_enabled( @@ -1782,7 +1795,7 @@ public class Application.MainWindow : private void set_shift_key_down(bool down) { this.is_shift_down = down; - this.main_toolbar.update_trash_button( + this.conversation_actions.update_trash_button( !down && this.selected_folder_supports_trash ); } @@ -1811,7 +1824,7 @@ public class Application.MainWindow : conversations_leaflet.navigate(Hdy.NavigationDirection.FORWARD); focus = this.conversation_list_view; } else { - if (this.main_toolbar.selected_conversations == 1 && + if (this.conversation_actions.selected_conversations == 1 && this.selected_folder.properties.email_total > 0) { main_leaflet.navigate(Hdy.NavigationDirection.FORWARD); focus = this.conversation_viewer.visible_child; @@ -2215,11 +2228,11 @@ public class Application.MainWindow : } private void on_show_copy_menu() { - this.main_toolbar.copy_message_button.clicked(); + this.conversation_actions.copy_message_button.clicked(); } private void on_show_move_menu() { - this.main_toolbar.move_message_button.clicked(); + this.conversation_actions.move_message_button.clicked(); } private void on_conversation_up() { diff --git a/src/client/components/components-conversation-actions.vala b/src/client/components/components-conversation-actions.vala new file mode 100644 index 00000000..a8cdaed9 --- /dev/null +++ b/src/client/components/components-conversation-actions.vala @@ -0,0 +1,132 @@ +/* Copyright 2017 Software Freedom Conservancy Inc. + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +/** + * Container for actions for a conversation generally placed into the ActionBar or HeaderBar + * The user of the actions needs to take ownership before they can place the actions in a container + */ +public class Components.ConversationActions : GLib.Object { + public Gtk.Widget? owner { get; private set; } + // Copy and Move popovers + public FolderPopover copy_folder_menu { get; private set; default = new FolderPopover(); } + public FolderPopover move_folder_menu { get; private set; default = new FolderPopover(); } + // How many conversations are selected right now. Should automatically be updated. + public int selected_conversations { get; set; } + public bool find_open { get; set; } + + public Gtk.Box mark_copy_move_buttons { get; private set; } + public Gtk.MenuButton mark_message_button { get; private set; } + public Gtk.MenuButton copy_message_button { get; private set; } + public Gtk.MenuButton move_message_button { get; private set; } + + public Gtk.Box reply_forward_buttons { get; private set; } + + public Gtk.Box archive_trash_delete_buttons { get; private set; } + private Gtk.Button archive_button; + private Gtk.Button trash_delete_button; + + public Gtk.ToggleButton find_button { get; private set; } + + private bool show_trash_button = true; + + // Load these at construction time + private Gtk.Image trash_image = new Gtk.Image.from_icon_name("user-trash-symbolic", Gtk.IconSize.MENU); + private Gtk.Image delete_image = new Gtk.Image.from_icon_name("edit-delete-symbolic", Gtk.IconSize.MENU); + + public ConversationActions() { + Gtk.Builder builder = + new Gtk.Builder.from_resource("/org/gnome/Geary/components-conversation-actions.ui"); + // Assemble the mark menus + Gtk.Builder menu_builder = + new Gtk.Builder.from_resource("/org/gnome/Geary/main-toolbar-menus.ui"); + MenuModel mark_menu = (MenuModel) menu_builder.get_object("mark_message_menu"); + + this.mark_copy_move_buttons = (Gtk.Box) builder.get_object("mark_copy_move_buttons"); + this.mark_message_button = (Gtk.MenuButton) builder.get_object("mark_message_button"); + this.copy_message_button = (Gtk.MenuButton) builder.get_object("copy_message_button"); + this.move_message_button = (Gtk.MenuButton) builder.get_object("move_message_button"); + + this.reply_forward_buttons = (Gtk.Box) builder.get_object("reply_forward_buttons"); + + this.archive_trash_delete_buttons = (Gtk.Box) builder.get_object("archive_trash_delete_buttons"); + this.archive_button = (Gtk.Button) builder.get_object("archive_button"); + this.trash_delete_button = (Gtk.Button) builder.get_object("trash_delete_button"); + + this.find_button = (Gtk.ToggleButton) builder.get_object("find_button"); + + this.bind_property("find-open", this.find_button, "active", + BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); + this.notify["selected-conversations"].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; + } + + /** Sets the new owner and removes the previous owner and parents of the single actions */ + public void take_ownership(Gtk.Widget? new_owner) { + remove_parent(mark_copy_move_buttons); + remove_parent(reply_forward_buttons); + remove_parent(archive_trash_delete_buttons); + remove_parent(find_button); + owner = new_owner; + } + + private void remove_parent (Gtk.Widget widget) { + if (widget.parent != null) + widget.parent.remove(widget); + } + + public void update_trash_button(bool show_trash) { + this.show_trash_button = show_trash; + update_conversation_buttons(); + } + + /** Updates tooltip text depending on number of conversations selected. */ + private void update_conversation_buttons() { + this.mark_message_button.tooltip_text = ngettext( + "Mark conversation", + "Mark conversations", + this.selected_conversations + ); + this.copy_message_button.tooltip_text = ngettext( + "Add label to conversation", + "Add label to conversations", + 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 + ); + + if (this.show_trash_button) { + this.trash_delete_button.action_name = Action.Window.prefix( + Application.MainWindow.ACTION_TRASH_CONVERSATION + ); + this.trash_delete_button.image = trash_image; + this.trash_delete_button.tooltip_text = ngettext( + "Move conversation to Trash", + "Move conversations to Trash", + this.selected_conversations + ); + } else { + this.trash_delete_button.action_name = Action.Window.prefix( + Application.MainWindow.ACTION_DELETE_CONVERSATION + ); + this.trash_delete_button.image = delete_image; + this.trash_delete_button.tooltip_text = ngettext( + "Delete conversation", + "Delete conversations", + this.selected_conversations + ); + } + } +} diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala index 0ecb599a..6458b7fb 100644 --- a/src/client/components/main-toolbar.vala +++ b/src/client/components/main-toolbar.vala @@ -14,15 +14,8 @@ public class MainToolbar : Hdy.Leaflet { public string folder { get; set; } // Close button settings public bool show_close_button { get; set; default = true; } - // Search and find bar + // Search bar public bool search_open { get; set; default = false; } - public bool find_open { get; set; default = false; } - // Copy and Move popovers - public FolderPopover copy_folder_menu { get; private set; default = new FolderPopover(); } - public FolderPopover move_folder_menu { get; private set; default = new FolderPopover(); } - // How many conversations are selected right now. Should automatically be updated. - public int selected_conversations { get; set; } - [GtkChild] private Hdy.Leaflet conversations_leaflet; @@ -48,31 +41,12 @@ public class MainToolbar : Hdy.Leaflet { // Conversation header elements [GtkChild] private Gtk.HeaderBar conversation_header; - [GtkChild] - private Gtk.MenuButton mark_message_button; - [GtkChild] - public Gtk.MenuButton copy_message_button; - [GtkChild] - public Gtk.MenuButton move_message_button; - [GtkChild] - private Gtk.Button archive_button; - [GtkChild] - private Gtk.Button trash_delete_button; - [GtkChild] - private Gtk.ToggleButton find_button; [GtkChild] private Hdy.HeaderGroup header_group; Gtk.SizeGroup conversation_group; - private bool show_trash_button = true; - - // Load these at construction time - private Gtk.Image trash_image = new Gtk.Image.from_icon_name("user-trash-symbolic", Gtk.IconSize.MENU); - private Gtk.Image delete_image = new Gtk.Image.from_icon_name("edit-delete-symbolic", Gtk.IconSize.MENU); - - public MainToolbar(Application.Configuration config) { if (config.desktop_environment != UNITY) { this.bind_property("account", this.conversations_header, "title", BindingFlags.SYNC_CREATE); @@ -82,21 +56,22 @@ public class MainToolbar : Hdy.Leaflet { // Assemble the main/mark menus Gtk.Builder builder = new Gtk.Builder.from_resource("/org/gnome/Geary/main-toolbar-menus.ui"); MenuModel main_menu = (MenuModel) builder.get_object("main_menu"); - MenuModel mark_menu = (MenuModel) builder.get_object("mark_message_menu"); // Setup folder header elements this.main_menu_button.popover = new Gtk.Popover.from_model(null, main_menu); this.bind_property("search-open", this.search_conversations_button, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); + } - // Setup conversation header elements - this.notify["selected-conversations"].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; + public void add_conversation_actions(Components.ConversationActions actions) { + if (actions.owner == this) + return; - this.bind_property("find-open", this.find_button, "active", - BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); + actions.take_ownership(this); + conversation_header.pack_start(actions.mark_copy_move_buttons); + conversation_header.pack_start(actions.reply_forward_buttons); + conversation_header.pack_end(actions.find_button); + conversation_header.pack_end(actions.archive_trash_delete_buttons); } public void set_conversation_header(Gtk.HeaderBar header) { @@ -118,11 +93,6 @@ public class MainToolbar : Hdy.Leaflet { child_set(conversation_header, "name", "conversation", null); } - public void update_trash_button(bool show_trash) { - this.show_trash_button = show_trash; - update_conversation_buttons(); - } - public void add_to_size_groups(Gtk.SizeGroup folder_group, Gtk.SizeGroup folder_separator_group, Gtk.SizeGroup conversations_group, @@ -141,50 +111,4 @@ public class MainToolbar : Hdy.Leaflet { conversations_group.add_swipeable(this.conversations_leaflet); conversation_group.add_swipeable(this); } - - // Updates tooltip text depending on number of conversations selected. - private void update_conversation_buttons() { - this.mark_message_button.tooltip_text = ngettext( - "Mark conversation", - "Mark conversations", - this.selected_conversations - ); - this.copy_message_button.tooltip_text = ngettext( - "Add label to conversation", - "Add label to conversations", - 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 - ); - - if (this.show_trash_button) { - this.trash_delete_button.action_name = Action.Window.prefix( - Application.MainWindow.ACTION_TRASH_CONVERSATION - ); - this.trash_delete_button.image = trash_image; - this.trash_delete_button.tooltip_text = ngettext( - "Move conversation to Trash", - "Move conversations to Trash", - this.selected_conversations - ); - } else { - this.trash_delete_button.action_name = Action.Window.prefix( - Application.MainWindow.ACTION_DELETE_CONVERSATION - ); - this.trash_delete_button.image = delete_image; - this.trash_delete_button.tooltip_text = ngettext( - "Delete conversation", - "Delete conversations", - this.selected_conversations - ); - } - } } diff --git a/src/client/meson.build b/src/client/meson.build index 088f4e47..ed0d6b33 100644 --- a/src/client/meson.build +++ b/src/client/meson.build @@ -48,6 +48,7 @@ client_vala_sources = files( 'components/client-web-view.vala', 'components/components-attachment-pane.vala', + 'components/components-conversation-actions.vala', 'components/components-entry-undo.vala', 'components/components-info-bar-stack.vala', 'components/components-info-bar.vala', diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui index cbaacbcf..547b063f 100644 --- a/ui/application-main-window.ui +++ b/ui/application-main-window.ui @@ -111,7 +111,7 @@ True True end - 0 + 1 diff --git a/ui/components-conversation-actions.ui b/ui/components-conversation-actions.ui new file mode 100644 index 00000000..b554deda --- /dev/null +++ b/ui/components-conversation-actions.ui @@ -0,0 +1,221 @@ + + + + + + True + False + + + True + True + False + False + True + + + True + False + marker-symbolic + + + + + False + True + 0 + + + + + True + True + False + False + True + + + True + False + tag-symbolic + + + + + False + True + 1 + + + + + True + True + False + False + True + + + True + False + folder-symbolic + + + + + False + True + 2 + + + + + + True + False + + + True + True + False + False + Reply + win.reply-conversation + True + + + True + False + mail-reply-sender-symbolic + + + + + False + True + 0 + + + + + True + True + False + False + Reply All + win.reply-all-conversation + True + + + True + False + mail-reply-all-symbolic + + + + + False + True + 1 + + + + + True + True + False + False + Forward + win.forward-conversation + True + + + True + False + mail-forward-symbolic + + + + + False + True + 2 + + + + + + True + False + mail-archive-symbolic + + + True + False + + + _Archive + True + True + False + False + win.archive-conversation + archive_image + True + True + + + False + True + 0 + + + + + True + True + False + False + win.trash-conversation + True + + + True + False + user-trash-symbolic + + + + + False + True + 1 + + + + + + True + True + False + False + Toggle find bar + True + + + True + False + preferences-system-search-symbolic + + + + diff --git a/ui/main-toolbar.ui b/ui/main-toolbar.ui index 5d58af6f..64f888ee 100644 --- a/ui/main-toolbar.ui +++ b/ui/main-toolbar.ui @@ -189,236 +189,6 @@ - - - True - False - - - True - True - False - False - Reply - win.reply-conversation - True - - - True - False - mail-reply-sender-symbolic - - - - - False - True - 0 - - - - - True - True - False - False - Reply All - win.reply-all-conversation - True - - - True - False - mail-reply-all-symbolic - - - - - False - True - 1 - - - - - True - True - False - False - Forward - win.forward-conversation - True - - - True - False - mail-forward-symbolic - - - - - False - True - 2 - - - - - - - - True - False - - - True - True - False - False - True - - - True - False - marker-symbolic - - - - - False - True - 0 - - - - - True - True - False - False - True - - - True - False - tag-symbolic - - - - - False - True - 1 - - - - - True - True - False - False - True - - - True - False - folder-symbolic - - - - - False - True - 2 - - - - - - 1 - - - - - True - True - False - False - Toggle find bar - True - - - True - False - preferences-system-search-symbolic - - - - - end - 2 - - - - - True - False - - - _Archive - True - True - False - False - win.archive-conversation - archive_image - True - True - - - False - True - 0 - - - - - True - True - False - False - win.trash-conversation - True - - - True - False - user-trash-symbolic - - - - - False - True - 1 - - - - - - end - 4 - - conversation diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml index 0cdca875..481bbff4 100644 --- a/ui/org.gnome.Geary.gresource.xml +++ b/ui/org.gnome.Geary.gresource.xml @@ -14,6 +14,7 @@ components-attachment-pane.ui components-attachment-pane-menus.ui components-attachment-view.ui + components-conversation-actions.ui components-in-app-notification.ui components-inspector.ui components-inspector-error-view.ui -- 2.29.2