diff --git a/po/POTFILES.in b/po/POTFILES.in index 8d6c52b2..d8301ec4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -38,7 +38,6 @@ src/client/application/secret-mediator.vala src/client/client-action.vala src/client/components/components-attachment-pane.vala src/client/components/components-conversation-actions.vala -src/client/components/components-conversation-action-bar.vala src/client/components/components-entry-undo.vala src/client/components/components-in-app-notification.vala src/client/components/components-info-bar-stack.vala @@ -458,8 +457,6 @@ ui/components-attachment-pane.ui ui/components-attachment-pane-menus.ui ui/components-attachment-view.ui ui/components-conversation-actions.ui -ui/components-conversation-action-bar.ui -ui/components-conversation-header-bar.ui ui/components-in-app-notification.ui ui/components-info-bar.ui ui/components-inspector-error-view.ui diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala index 76e0c898..d47a1569 100644 --- a/src/client/application/application-main-window.vala +++ b/src/client/application/application-main-window.vala @@ -307,9 +307,6 @@ 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); } @@ -344,12 +341,18 @@ public class Application.MainWindow : [GtkChild] private unowned Gtk.Box main_layout; [GtkChild] private unowned Hdy.Leaflet main_leaflet; [GtkChild] private unowned Hdy.Leaflet conversations_leaflet; + [GtkChild] private unowned Gtk.Box folder_box; [GtkChild] private unowned Gtk.ScrolledWindow folder_list_scrolled; + [GtkChild] private unowned Gtk.Box conversation_list_box; [GtkChild] private unowned Gtk.ScrolledWindow conversation_list_scrolled; + [GtkChild] private unowned Gtk.Revealer conversation_list_actions_revealer; + [GtkChild] private unowned Components.ConversationActions conversation_list_actions; + [GtkChild] private unowned Gtk.Box conversation_viewer_box; - [GtkChild] private unowned Components.ConversationActionBar conversation_viewer_action_bar; + [GtkChild] private unowned Gtk.Revealer conversation_viewer_actions_revealer; + [GtkChild] private unowned Components.ConversationActions conversation_viewer_actions; [GtkChild] private unowned Gtk.SizeGroup folder_size_group; [GtkChild] private unowned Gtk.SizeGroup folder_separator_size_group; [GtkChild] private unowned Gtk.SizeGroup conversations_size_group; @@ -360,8 +363,6 @@ public class Application.MainWindow : [GtkChild] private unowned Gtk.Overlay overlay; - private Components.ConversationActionBar action_bar; - private Components.InfoBarStack info_bars = new Components.InfoBarStack(SINGLE); @@ -758,11 +759,9 @@ public class Application.MainWindow : this.folder_list.deselect_folder(); } - update_conversation_actions(NONE); update_title(); - this.conversation_actions.update_trash_button( - !this.is_shift_down && this.selected_folder_supports_trash - ); + update_conversation_actions(NONE); + update_trash_action(); this.conversation_viewer.show_loading(); this.previous_selection_was_interactive = is_interactive; @@ -1293,19 +1292,8 @@ public class Application.MainWindow : this.conversation_viewer_box.add(this.conversation_viewer); - // 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 Components.MainToolbar( - config, conversation_viewer_action_bar - ); + this.main_toolbar = new Components.MainToolbar(config); this.main_toolbar.add_to_size_groups(this.folder_size_group, this.folder_separator_size_group, this.conversations_size_group, @@ -1313,8 +1301,16 @@ 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.bind_property("search-open", this.search_bar, "search-mode-enabled", - BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); + this.main_toolbar.bind_property( + "search-open", + this.search_bar, "search-mode-enabled", + SYNC_CREATE | BIDIRECTIONAL + ); + this.main_toolbar.bind_property( + "find-open", + this.conversation_viewer.conversation_find_bar, "search-mode-enabled", + SYNC_CREATE | BIDIRECTIONAL + ); if (config.desktop_environment == UNITY) { this.main_toolbar.show_close_button = false; this.main_layout.pack_start(main_toolbar, false, true, 0); @@ -1322,8 +1318,6 @@ public class Application.MainWindow : this.main_layout.pack_start(main_toolbar, false, true, 0); } - this.main_toolbar.add_conversation_actions(this.conversation_actions); - this.main_layout.pack_start(this.info_bars, false, true, 0); // Status bar @@ -1333,12 +1327,6 @@ public class Application.MainWindow : this.spinner.set_progress_monitor(progress_monitor); this.status_bar.add(this.spinner); this.status_bar.show_all(); - - // Action bar - this.action_bar = new Components.ConversationActionBar(); - this.conversation_list_box.add_with_properties(action_bar, - "pack-type", Gtk.PackType.END, - "position", 0); } /** {@inheritDoc} */ @@ -1538,7 +1526,9 @@ public class Application.MainWindow : // setting it again. this.conversation_list_view.select_conversations(to_select); - this.conversation_actions.selected_conversations = to_select.size; + this.conversation_list_actions.selected_conversations = to_select.size; + this.main_toolbar.conversation_actions.selected_conversations = to_select.size; + if (this.selected_folder != null && !this.has_composer) { switch(to_select.size) { case 0: @@ -1772,18 +1762,27 @@ public class Application.MainWindow : this.update_context_dependent_actions.begin(sensitive); switch (count) { - case NONE: - conversation_actions.take_ownership(null); - break; - case SINGLE: - this.main_toolbar.add_conversation_actions(this.conversation_actions); - break; - case MULTIPLE: - this.action_bar.add_conversation_actions(this.conversation_actions); - break; + case NONE: + this.conversation_list_actions_revealer.reveal_child = false; + break; + case SINGLE: + this.conversation_list_actions_revealer.reveal_child = false; + break; + case MULTIPLE: + this.conversation_list_actions_revealer.reveal_child = true; + break; } } + private void update_trash_action() { + var show_trash = ( + !this.is_shift_down && + this.selected_folder_supports_trash + ); + this.conversation_list_actions.update_trash_button(show_trash); + this.main_toolbar.conversation_actions.update_trash_button(show_trash); + } + private async void update_context_dependent_actions(bool sensitive) { // Cancel any existing update that is running this.action_update_cancellable.cancel(); @@ -1837,9 +1836,7 @@ public class Application.MainWindow : private void set_shift_key_down(bool down) { this.is_shift_down = down; - this.conversation_actions.update_trash_button( - !down && this.selected_folder_supports_trash - ); + update_trash_action(); } private inline void check_shift_event(Gdk.EventKey event) { @@ -1866,7 +1863,7 @@ public class Application.MainWindow : conversations_leaflet.navigate(Hdy.NavigationDirection.FORWARD); focus = this.conversation_list_view; } else { - if (this.conversation_actions.selected_conversations == 1 && + if (this.conversation_list_view.get_selected().size == 1 && this.selected_folder.properties.email_total > 0) { main_leaflet.navigate(Hdy.NavigationDirection.FORWARD); focus = this.conversation_viewer.visible_child; diff --git a/src/client/components/components-conversation-action-bar.vala b/src/client/components/components-conversation-action-bar.vala deleted file mode 100644 index 4b4cfacc..00000000 --- a/src/client/components/components-conversation-action-bar.vala +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright © 2016 Software Freedom Conservancy Inc. - * Copyright © 2020 Purism SPC - * - * This software is licensed under the GNU Lesser General Public License - * (version 2.1 or later). See the COPYING file in this distribution. - */ - -// Draws the conversation action bar. -[GtkTemplate (ui = "/org/gnome/Geary/components-conversation-action-bar.ui")] -public class Components.ConversationActionBar : Gtk.Revealer { - - - [GtkChild] public unowned Gtk.Box action_box { get; } - - private ulong owner_notify; - - - /** - * This takes ownership of the ConversationActions and places some of - * the buttons into the ActionBar. - */ - public void add_conversation_actions(Components.ConversationActions actions) { - if (actions.owner == this) - return; - - actions.take_ownership(this); - action_box.pack_start(actions.mark_copy_move_buttons, false, false); - action_box.pack_end(actions.archive_trash_delete_buttons, false, false); - reveal_child = true; - this.owner_notify = actions.notify["owner"].connect(() => { - if (actions.owner != this) { - reveal_child = false; - actions.disconnect (this.owner_notify); - } - }); - } -} diff --git a/src/client/components/components-conversation-actions.vala b/src/client/components/components-conversation-actions.vala index 91b1268c..51e6a145 100644 --- a/src/client/components/components-conversation-actions.vala +++ b/src/client/components/components-conversation-actions.vala @@ -1,34 +1,37 @@ -/* Copyright 2017 Software Freedom Conservancy Inc. +/* + * Copyright © 2017 Software Freedom Conservancy Inc. + * Copyright © 2021 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. + * (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 + * A container of conversation-related actions. */ -public class Components.ConversationActions : GLib.Object { - public Gtk.Widget? owner { get; private set; } - // Copy and Move popovers +[GtkTemplate (ui = "/org/gnome/Geary/components-conversation-actions.ui")] +public class Components.ConversationActions : Gtk.Box { + + public bool show_conversation_actions { get; construct; } + + public bool show_response_actions { get; construct; } + 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; } + [GtkChild] private unowned Gtk.Box response_buttons { get; } - public Gtk.Box reply_forward_buttons { get; private set; } + [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; } - 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; } + [GtkChild] private unowned Gtk.Box archive_trash_delete_buttons { get; } + [GtkChild] private unowned Gtk.Button archive_button; + [GtkChild] private unowned Gtk.Button trash_delete_button; private bool show_trash_button = true; @@ -36,47 +39,29 @@ public class Components.ConversationActions : GLib.Object { 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"); + static construct { + set_css_name("components-conversation-actions"); + } + + // GObject style constuction to support loading via GTK Builder files + construct { + // Assemble the mark menus - Gtk.Builder menu_builder = - new Gtk.Builder.from_resource("/org/gnome/Geary/components-main-toolbar-menus.ui"); - MenuModel mark_menu = (MenuModel) menu_builder.get_object("mark_message_menu"); + Gtk.Builder menu_builder = new Gtk.Builder.from_resource( + "/org/gnome/Geary/components-main-toolbar-menus.ui" + ); + GLib.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); + 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); } public void update_trash_button(bool show_trash) { diff --git a/src/client/components/components-conversation-header-bar.vala b/src/client/components/components-conversation-header-bar.vala deleted file mode 100644 index 202cf7c4..00000000 --- a/src/client/components/components-conversation-header-bar.vala +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright © 2020 Purism SPC - * - * This software is licensed under the GNU Lesser General Public License - * (version 2.1 or later). See the COPYING file in this distribution. - */ - -[GtkTemplate (ui = "/org/gnome/Geary/components-conversation-header-bar.ui")] -public class Components.ConversationHeaderBar : Hdy.HeaderBar { - public Components.ConversationActionBar action_bar { get; set; } - public bool folded { get; set; } - - private ulong owner_notify; - private Gtk.Widget? reply_forward_buttons; - private Gtk.Widget? archive_trash_delete_buttons; - - public ConversationHeaderBar() { - } - - public override void size_allocate(Gtk.Allocation allocation) { - update_action_bar(); - base.size_allocate(allocation); - } - - [GtkCallback] - private void update_action_bar () { - /* Only show the action_bar when the conversation_header is shown */ - if (parent == null) - action_bar.reveal_child = false; - else if (reply_forward_buttons != null && archive_trash_delete_buttons != null) - if (action_bar.reveal_child && get_allocated_width() > 600) { - action_bar.reveal_child = false; - remove_action_parent(); - pack_start(reply_forward_buttons); - pack_end(archive_trash_delete_buttons); - } else if (!action_bar.reveal_child && get_allocated_width() < 600) { - remove_action_parent(); - action_bar.action_box.pack_start(reply_forward_buttons, false, false); - action_bar.action_box.pack_end(archive_trash_delete_buttons, false, false); - action_bar.reveal_child = true; - } - } - - private void remove_action_parent() { - if (reply_forward_buttons != null && reply_forward_buttons.parent != null) - reply_forward_buttons.parent.remove(reply_forward_buttons); - if (archive_trash_delete_buttons != null && archive_trash_delete_buttons.parent != null) - archive_trash_delete_buttons.parent.remove(archive_trash_delete_buttons); - } - - public void add_conversation_actions(Components.ConversationActions actions) { - if (actions.owner != this) { - actions.take_ownership(this); - pack_start(actions.mark_copy_move_buttons); - pack_end(actions.find_button); - - reply_forward_buttons = actions.reply_forward_buttons; - archive_trash_delete_buttons = actions.archive_trash_delete_buttons; - action_bar.reveal_child = get_allocated_width() > 600; - update_action_bar(); - this.owner_notify = actions.notify["owner"].connect(() => { - if (actions.owner != this) { - action_bar.reveal_child = false; - reply_forward_buttons = null; - archive_trash_delete_buttons = null; - actions.disconnect (this.owner_notify); - } - }); - } - } -} diff --git a/src/client/components/components-main-toolbar.vala b/src/client/components/components-main-toolbar.vala index 32ad5eea..1edf9d4f 100644 --- a/src/client/components/components-main-toolbar.vala +++ b/src/client/components/components-main-toolbar.vala @@ -14,20 +14,18 @@ [GtkTemplate (ui = "/org/gnome/Geary/components-main-toolbar.ui")] public class Components.MainToolbar : Hdy.Leaflet { - // How wide the left pane should be. Auto-synced with our settings - public int left_pane_width { get; set; } - // Used to form the title of the folder header public string account { get; set; } + public string folder { get; set; } - // Close button settings public bool show_close_button { get; set; default = true; } - // Search bar public bool search_open { get; set; default = false; } - private ConversationActionBar conversation_viewer_action_bar; + public bool find_open { get; set; default = false; } + + [GtkChild] public unowned ConversationActions conversation_actions; [GtkChild] private unowned Hdy.Leaflet conversations_leaflet; @@ -37,36 +35,42 @@ public class Components.MainToolbar : Hdy.Leaflet { [GtkChild] private unowned Gtk.Separator folder_separator; - // Conversations header elements + // Conversation list header elements [GtkChild] private unowned Hdy.HeaderBar conversations_header; - [GtkChild] private unowned Gtk.ToggleButton search_conversations_button; + [GtkChild] private unowned Gtk.ToggleButton search_button; [GtkChild] private unowned Gtk.Separator conversations_separator; - // Conversation header elements - [GtkChild] private unowned ConversationHeaderBar conversation_header; + // Conversation viewer header elements + [GtkChild] private unowned Hdy.HeaderBar conversation_header; + [GtkChild] private unowned Gtk.ToggleButton find_button; [GtkChild] private unowned Hdy.HeaderGroup header_group; - Gtk.SizeGroup conversation_group; + private Gtk.SizeGroup conversation_group; - public MainToolbar(Application.Configuration config, - ConversationActionBar action_bar) { + + public MainToolbar(Application.Configuration config) { if (config.desktop_environment != UNITY) { this.bind_property("account", this.conversations_header, "title", BindingFlags.SYNC_CREATE); this.bind_property("folder", this.conversations_header, "subtitle", BindingFlags.SYNC_CREATE); } - this.conversation_viewer_action_bar = action_bar; - this.conversation_header.action_bar = action_bar; // Assemble the main/mark menus Gtk.Builder builder = new Gtk.Builder.from_resource("/org/gnome/Geary/components-main-toolbar-menus.ui"); MenuModel main_menu = (MenuModel) builder.get_object("main_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); + this.bind_property( + "search-open", + this.search_button, "active", + SYNC_CREATE | BIDIRECTIONAL + ); + this.bind_property( + "find-open", + this.find_button, "active", + SYNC_CREATE | BIDIRECTIONAL + ); } public void set_conversation_header(Hdy.HeaderBar header) { @@ -107,10 +111,6 @@ public class Components.MainToolbar : Hdy.Leaflet { conversation_group.add_swipeable(this); } - public void add_conversation_actions(ConversationActions actions) { - conversation_header.add_conversation_actions(actions); - } - public void show_main_menu() { this.main_menu_button.clicked(); } diff --git a/src/client/meson.build b/src/client/meson.build index 7262580b..ff3c8a6d 100644 --- a/src/client/meson.build +++ b/src/client/meson.build @@ -47,8 +47,6 @@ client_vala_sources = files( 'components/components-attachment-pane.vala', 'components/components-conversation-actions.vala', - 'components/components-conversation-action-bar.vala', - 'components/components-conversation-header-bar.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 d54d365a..371accea 100644 --- a/ui/application-main-window.ui +++ b/ui/application-main-window.ui @@ -98,6 +98,27 @@ 1 + + + True + True + slide-up + + + True + True + False + True + + + + + False + False + end + 0 + + conversations @@ -125,8 +146,18 @@ True vertical - + True + True + slide-up + + + True + False + True + True + + end diff --git a/ui/components-conversation-action-bar.ui b/ui/components-conversation-action-bar.ui deleted file mode 100644 index 74daca48..00000000 --- a/ui/components-conversation-action-bar.ui +++ /dev/null @@ -1,34 +0,0 @@ - - - - - True - mail-archive-symbolic - - - diff --git a/ui/components-conversation-actions.ui b/ui/components-conversation-actions.ui index f1423bdf..a64dfbd8 100644 --- a/ui/components-conversation-actions.ui +++ b/ui/components-conversation-actions.ui @@ -1,200 +1,213 @@ - - + + diff --git a/ui/components-conversation-header-bar.ui b/ui/components-conversation-header-bar.ui deleted file mode 100644 index 965f1262..00000000 --- a/ui/components-conversation-header-bar.ui +++ /dev/null @@ -1,33 +0,0 @@ - - - - - diff --git a/ui/components-main-toolbar.ui b/ui/components-main-toolbar.ui index 95c80838..00104224 100644 --- a/ui/components-main-toolbar.ui +++ b/ui/components-main-toolbar.ui @@ -2,10 +2,6 @@ - - True - mail-archive-symbolic -