Merge branch 'mjog/1193-conversation-buttons-resize-race' into 'mainline'

Duplicate, don't re-parent, conversation actions as responsive layout changes.

Closes #1193

See merge request GNOME/geary!691
This commit is contained in:
Michael Gratton 2021-04-13 15:22:14 +00:00
commit 3af0d6286d
22 changed files with 679 additions and 557 deletions

View file

@ -29,6 +29,7 @@ variables:
libappstream-glib-devel libgee-devel libhandy1-devel libicu-devel
libpeas-devel libsecret-devel libstemmer-devel libunwind-devel
libxml2-devel libytnef-devel sqlite-devel webkitgtk4-devel
git
FEDORA_TEST_DEPS: glibc-langpack-en gnutls-utils tar Xvfb xz
# Ubuntu packages
@ -40,6 +41,7 @@ variables:
libhandy-1-dev libicu-dev libjson-glib-dev libmessaging-menu-dev
libpeas-dev libsecret-1-dev libsqlite3-dev libstemmer-dev
libunwind-dev libwebkit2gtk-4.0-dev libxml2-dev libytnef0-dev
git ca-certificates
UBUNTU_TEST_DEPS: gnutls-bin librsvg2-common locales xauth xvfb
fedora:

View file

@ -89,7 +89,7 @@ icu_uc = dependency('icu-uc', version: '>=60')
iso_codes = dependency('iso-codes')
javascriptcoregtk = dependency('javascriptcoregtk-4.0', version: '>=' + target_webkit)
json_glib = dependency('json-glib-1.0', version: '>= 1.0')
libhandy = dependency('libhandy-1', version: '>= 1.2')
libhandy = dependency('libhandy-1', version: '>= 1.2.1', required: false)
libmath = cc.find_library('m')
libpeas = dependency('libpeas-1.0', version: '>= 1.24.0')
libpeas_gtk = dependency('libpeas-gtk-1.0', version: '>= 1.24.0')
@ -138,6 +138,26 @@ libstemmer = declare_dependency(
],
)
# Required until libhandy 1.2.1 is GA
libhandy_vapi = ''
if not libhandy.found()
libhandy_project = subproject(
'libhandy',
default_options: [
'examples=false',
'package_subdir=geary',
'tests=false',
]
)
libhandy = declare_dependency(
dependencies: [
libhandy_project.get_variable('libhandy_dep'),
libhandy_project.get_variable('libhandy_vapi')
]
)
libhandy_vapi = meson.build_root() / 'subprojects' / 'libhandy' / 'src'
endif
# Optional dependencies
appstream_util = find_program('appstream-util', required: false)
desktop_file_validate = find_program('desktop-file-validate', required: false)

View file

@ -78,6 +78,24 @@
"/share"
]
},
{
"name": "libhandy",
"buildsystem": "meson",
"config-opts": [
"-Dglade_catalog=disabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/libhandy.git",
"branch": "master"
}
],
"cleanup": [
"/bin",
"/share"
]
},
{
"name": "libical",
"buildsystem": "cmake-ninja",

View file

@ -111,6 +111,19 @@ modules:
- /bin
- /share
# Geary dependency
- name: libhandy
buildsystem: meson
config-opts:
- "-Dglade_catalog=disabled"
sources:
- type: git
url: "https://gitlab.gnome.org/GNOME/libhandy.git"
branch: master
cleanup:
- /bin
- /share
# EDS dependency
- name: libical
buildsystem: cmake-ninja

View file

@ -38,12 +38,12 @@ 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
src/client/components/components-info-bar.vala
src/client/components/components-inspector.vala
src/client/components/components-main-toolbar.vala
src/client/components/components-placeholder-pane.vala
src/client/components/components-preferences-window.vala
src/client/components/components-problem-report-info-bar.vala
@ -54,7 +54,6 @@ src/client/components/components-web-view.vala
src/client/components/count-badge.vala
src/client/components/folder-popover.vala
src/client/components/icon-factory.vala
src/client/components/main-toolbar.vala
src/client/components/monitored-progress-bar.vala
src/client/components/monitored-spinner.vala
src/client/components/status-bar.vala
@ -458,13 +457,13 @@ 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
ui/components-inspector-log-view.ui
ui/components-inspector.ui
ui/components-main-toolbar.ui
ui/components-main-toolbar-menus.ui
ui/components-placeholder-pane.ui
ui/conversation-contact-popover.ui
ui/conversation-email.ui
@ -476,7 +475,5 @@ ui/conversation-viewer.ui
ui/find_bar.glade
ui/folder-popover.ui
ui/gtk/help-overlay.ui
ui/main-toolbar.ui
ui/main-toolbar-menus.ui
ui/password-dialog.glade
ui/problem-details-dialog.ui

View file

@ -71,10 +71,17 @@ public class Application.MainWindow :
{ ACTION_ZOOM, on_zoom, "s" },
};
private const int STATUS_BAR_HEIGHT = 18;
private const int UPDATE_UI_INTERVAL = 60;
private const int MIN_CONVERSATION_COUNT = 50;
// Handy leaflet children names
private const string INNER_LEAFLET = "inner_leaflet";
private const string FOLDER_LIST = "folder_list";
private const string CONVERSATION_LIST = "conversation_list";
private const string CONVERSATION_VIEWER = "conversation_viewer";
private const int STATUS_BAR_HEIGHT = 18;
private const int UPDATE_UI_INTERVAL = 60;
private const int MIN_CONVERSATION_COUNT = 50;
static construct {
// Set up default keybindings
@ -255,7 +262,19 @@ public class Application.MainWindow :
}
private enum ConversationCount { NONE, SINGLE, MULTIPLE; }
private enum ConversationCount {
NONE, SINGLE, MULTIPLE;
public static ConversationCount for_size(int size) {
return (
size == 0
? NONE
: size == 1
? SINGLE
: MULTIPLE
);
}
}
/** Returns the window's associated client application instance. */
@ -275,6 +294,41 @@ public class Application.MainWindow :
get; private set; default = null;
}
/** Specifies if the conversation list is currently displayed. */
public bool is_folder_list_shown {
get {
return (
(!this.outer_leaflet.folded ||
this.outer_leaflet.visible_child_name == INNER_LEAFLET) &&
(!this.inner_leaflet.folded ||
this.inner_leaflet.visible_child_name == FOLDER_LIST)
);
}
}
/** Specifies if the conversation list is currently displayed. */
public bool is_conversation_list_shown {
get {
return (
(!this.outer_leaflet.folded ||
this.outer_leaflet.visible_child_name == INNER_LEAFLET) &&
(!this.inner_leaflet.folded ||
this.inner_leaflet.visible_child_name == CONVERSATION_LIST)
);
}
}
/** Specifies if the conversation viewer is currently displayed. */
public bool is_conversation_viewer_shown {
get {
return (
(!this.outer_leaflet.folded ||
this.outer_leaflet.visible_child_name == CONVERSATION_VIEWER) &&
!this.has_composer
);
}
}
/** The attachment manager for this window. */
public AttachmentManager attachments { get; private set; }
@ -302,14 +356,11 @@ public class Application.MainWindow :
// Widget descendants
public FolderList.Tree folder_list { get; private set; default = new FolderList.Tree(); }
public MainToolbar main_toolbar { get; private set; }
public Components.MainToolbar main_toolbar { get; private set; }
public SearchBar search_bar { get; private set; }
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);
}
@ -342,14 +393,23 @@ 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;
// Folds the inner leaftlet and conversation viewer
[GtkChild] private unowned Hdy.Leaflet outer_leaflet;
// Folds the folder list and the conversation list
[GtkChild] private unowned Hdy.Leaflet inner_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 Gtk.SizeGroup folder_size_group;
[GtkChild] private unowned Gtk.SizeGroup folder_separator_size_group;
[GtkChild] private unowned Gtk.SizeGroup conversations_size_group;
@ -360,7 +420,8 @@ public class Application.MainWindow :
[GtkChild] private unowned Gtk.Overlay overlay;
private Components.ConversationActionBar action_bar;
private Components.ConversationActions[] folder_conversation_actions = {};
private FolderPopover[] folder_popovers = {};
private Components.InfoBarStack info_bars =
new Components.InfoBarStack(SINGLE);
@ -712,12 +773,9 @@ public class Application.MainWindow :
// selected model.
if (this.selected_folder != null) {
this.conversation_actions.copy_folder_menu.enable_disable_folder(
this.selected_folder, true
);
this.conversation_actions.move_folder_menu.enable_disable_folder(
this.selected_folder, true
);
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);
@ -758,11 +816,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;
@ -800,12 +856,9 @@ public class Application.MainWindow :
this.conversation_list_view.set_model(conversations_model);
// disable copy/move to the new folder
this.conversation_actions.copy_folder_menu.enable_disable_folder(
to_select, false
);
this.conversation_actions.move_folder_menu.enable_disable_folder(
to_select, false
);
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();
@ -893,11 +946,11 @@ public class Application.MainWindow :
/** Shows the appopriate window menu, if any. */
public void show_window_menu() {
if (this.main_leaflet.folded) {
this.main_leaflet.navigate(Hdy.NavigationDirection.BACK);
if (this.outer_leaflet.folded) {
this.outer_leaflet.navigate(Hdy.NavigationDirection.BACK);
}
if (this.conversations_leaflet.folded) {
this.conversations_leaflet.navigate(Hdy.NavigationDirection.BACK);
if (this.inner_leaflet.folded) {
this.inner_leaflet.navigate(Hdy.NavigationDirection.BACK);
}
this.main_toolbar.show_main_menu();
}
@ -949,7 +1002,7 @@ public class Application.MainWindow :
this.conversation_viewer.do_compose(composer);
}
// Show the correct leaflet
this.main_leaflet.set_visible_child_name("conversation");
this.outer_leaflet.set_visible_child_name(CONVERSATION_VIEWER);
}
}
@ -1120,8 +1173,9 @@ public class Application.MainWindow :
foreach (var context in to_add) {
this.folder_list.add_folder(context);
if (context.folder.account == this.selected_account) {
this.conversation_actions.copy_folder_menu.add_folder(context.folder);
this.conversation_actions.move_folder_menu.add_folder(context.folder);
foreach (var menu in this.folder_popovers) {
menu.add_folder(context.folder);
}
}
context.folder.use_changed.connect(on_use_changed);
}
@ -1141,8 +1195,9 @@ public class Application.MainWindow :
folder.use_changed.disconnect(on_use_changed);
if (folder.account == this.selected_account) {
this.conversation_actions.copy_folder_menu.remove_folder(folder);
this.conversation_actions.move_folder_menu.remove_folder(folder);
foreach (var menu in this.folder_popovers) {
menu.remove_folder(folder);
}
}
this.folder_list.remove_folder(context);
}
@ -1292,18 +1347,8 @@ public class Application.MainWindow :
this.conversation_size_group.add_widget(this.conversation_viewer);
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 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,
@ -1311,8 +1356,24 @@ 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
);
this.main_toolbar.notify["shown-actions"].connect(
() => {
this.conversation_viewer_actions_revealer.reveal_child = (
this.main_toolbar.shown_actions ==
this.main_toolbar.compact_actions
);
}
);
if (config.desktop_environment == UNITY) {
this.main_toolbar.show_close_button = false;
this.main_layout.pack_start(main_toolbar, false, true, 0);
@ -1320,8 +1381,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
@ -1332,11 +1391,20 @@ public class Application.MainWindow :
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);
this.folder_conversation_actions = {
this.main_toolbar.full_actions,
this.main_toolbar.compact_actions,
this.conversation_list_actions
};
foreach (var actions in 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);
}
}
/** {@inheritDoc} */
@ -1504,17 +1572,19 @@ public class Application.MainWindow :
private void select_account(Geary.Account? account) {
if (this.selected_account != account) {
if (this.selected_account != null) {
this.conversation_actions.copy_folder_menu.clear();
this.conversation_actions.move_folder_menu.clear();
foreach (var menu in this.folder_popovers) {
menu.clear();
}
}
this.selected_account = account;
this.search_bar.set_account(account);
if (account != null) {
foreach (Geary.Folder folder in account.list_folders()) {
this.conversation_actions.copy_folder_menu.add_folder(folder);
this.conversation_actions.move_folder_menu.add_folder(folder);
foreach (var menu in this.folder_popovers) {
foreach (var folder in account.list_folders()) {
menu.add_folder(folder);
}
}
}
@ -1536,7 +1606,10 @@ 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.full_actions.selected_conversations = to_select.size;
this.main_toolbar.compact_actions.selected_conversations = to_select.size;
if (this.selected_folder != null && !this.has_composer) {
switch(to_select.size) {
case 0:
@ -1749,14 +1822,18 @@ public class Application.MainWindow :
bool move_enabled = (
sensitive && (selected_folder is Geary.FolderSupport.Move)
);
this.conversation_actions.move_message_button.set_sensitive(move_enabled);
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 && (selected_folder is Geary.FolderSupport.Copy)
);
this.conversation_actions.copy_message_button.set_sensitive(copy_enabled);
get_window_action(ACTION_SHOW_COPY_MENU).set_enabled(move_enabled);
foreach (var actions in this.folder_conversation_actions) {
actions.set_copy_sensitive(copy_enabled);
}
get_window_action(ACTION_ARCHIVE_CONVERSATION).set_enabled(
sensitive && (selected_folder is Geary.FolderSupport.Archive)
@ -1769,19 +1846,35 @@ public class Application.MainWindow :
);
this.update_context_dependent_actions.begin(sensitive);
update_conversation_list_actions_revealer(count);
}
private void update_conversation_list_actions_revealer(ConversationCount count) {
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 = (
this.outer_leaflet.folded
);
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.full_actions.update_trash_button(show_trash);
this.main_toolbar.compact_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();
@ -1835,9 +1928,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) {
@ -1856,17 +1947,17 @@ public class Application.MainWindow :
private void focus_next_pane() {
var focus = get_focus();
if (main_leaflet.folded) {
if (main_leaflet.visible_child_name == "conversations") {
if (conversations_leaflet.folded &&
conversations_leaflet.visible_child_name == "folder" ||
if (this.outer_leaflet.folded) {
if (this.outer_leaflet.visible_child_name == INNER_LEAFLET) {
if (this.inner_leaflet.folded &&
this.inner_leaflet.visible_child_name == FOLDER_LIST ||
focus == this.folder_list) {
conversations_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
this.inner_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);
this.outer_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
focus = this.conversation_viewer.visible_child;
}
}
@ -1894,11 +1985,11 @@ public class Application.MainWindow :
private void focus_previous_pane() {
var focus = get_focus();
if (main_leaflet.folded) {
if (main_leaflet.visible_child_name == "conversations") {
if (conversations_leaflet.folded) {
if (conversations_leaflet.visible_child_name == "conversations") {
conversations_leaflet.navigate(Hdy.NavigationDirection.BACK);
if (this.outer_leaflet.folded) {
if (this.outer_leaflet.visible_child_name == INNER_LEAFLET) {
if (this.inner_leaflet.folded) {
if (this.inner_leaflet.visible_child_name == CONVERSATION_LIST) {
this.inner_leaflet.navigate(Hdy.NavigationDirection.BACK);
focus = this.folder_list;
}
} else {
@ -1908,7 +1999,7 @@ public class Application.MainWindow :
focus = this.conversation_list_view;
}
} else {
main_leaflet.navigate(Hdy.NavigationDirection.BACK);
this.outer_leaflet.navigate(Hdy.NavigationDirection.BACK);
focus = this.conversation_list_view;
}
} else if (focus != null) {
@ -2012,14 +2103,16 @@ public class Application.MainWindow :
}
[GtkCallback]
private void on_main_leaflet_visible_child_changed() {
if (main_leaflet.child_transition_running)
return;
if (main_leaflet.visible_child_name == "conversations" && main_leaflet.folded)
if (this.conversation_viewer.current_composer != null) {
this.conversation_viewer.current_composer.activate_close_action();
}
private void on_outer_leaflet_changed() {
int selected = this.conversation_list_view.get_selected().size;
update_conversation_list_actions_revealer(
ConversationCount.for_size(selected)
);
if (this.has_composer &&
this.outer_leaflet.folded &&
(this.is_folder_list_shown || this.is_conversation_list_shown)) {
close_composer(false, false);
}
}
private void on_offline_infobar_response() {
@ -2229,8 +2322,9 @@ public class Application.MainWindow :
private void on_conversation_activated(Geary.App.Conversation activated, bool single) {
if (single) {
if (main_leaflet.folded)
if (this.outer_leaflet.folded) {
focus_next_pane();
}
} else if (this.selected_folder != null) {
if (this.selected_folder.used_as != DRAFTS) {
this.application.new_window.begin(
@ -2295,11 +2389,25 @@ public class Application.MainWindow :
}
private void on_show_copy_menu() {
this.conversation_actions.copy_message_button.clicked();
if (this.is_conversation_list_shown &&
this.conversation_list_actions_revealer.child_revealed) {
this.conversation_list_actions.show_copy_menu();
} else if (this.is_conversation_viewer_shown) {
this.main_toolbar.shown_actions.show_copy_menu();
} else {
this.error_bell();
}
}
private void on_show_move_menu() {
this.conversation_actions.move_message_button.clicked();
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.main_toolbar.shown_actions.show_move_menu();
} else {
this.error_bell();
}
}
private void on_conversation_up() {

View file

@ -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);
}
});
}
}

View file

@ -1,34 +1,39 @@
/* Copyright 2017 Software Freedom Conservancy Inc.
/*
* Copyright © 2017 Software Freedom Conservancy Inc.
* Copyright © 2021 Michael Gratton <mike@vee.net>
*
* 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 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(); }
// 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 +41,49 @@ 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/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;
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);
if (this.pack_justified) {
this.archive_trash_delete_buttons.hexpand = true;
this.archive_trash_delete_buttons.halign = END;
}
}
/** 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;
public void set_move_sensitive(bool is_sensitive) {
this.move_message_button.sensitive = is_sensitive;
}
private void remove_parent (Gtk.Widget widget) {
if (widget.parent != null)
widget.parent.remove(widget);
public void show_move_menu() {
this.move_message_button.clicked();
}
public void set_copy_sensitive(bool is_sensitive) {
this.copy_message_button.sensitive = is_sensitive;
}
public void show_copy_menu() {
this.copy_message_button.clicked();
}
public void update_trash_button(bool show_trash) {

View file

@ -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);
}
});
}
}
}

View file

@ -1,23 +1,39 @@
/* Copyright 2017 Software Freedom Conservancy Inc.
/*
* Copyright © 2017 Software Freedom Conservancy Inc.
* Copyright © 2021 Michael Gratton <mike@vee.net>
*
* 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.
*/
// Draws the main toolbar.
[GtkTemplate (ui = "/org/gnome/Geary/main-toolbar.ui")]
public class 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
/**
* The toolbar for the main window.
*
* @see Application.MainWindow
*/
[GtkTemplate (ui = "/org/gnome/Geary/components-main-toolbar.ui")]
public class Components.MainToolbar : Hdy.Leaflet {
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 Components.ConversationActionBar conversation_viewer_action_bar;
public bool find_open { get; set; default = false; }
public ConversationActions shown_actions {
get {
return (ConversationActions) this.actions_squeezer.visible_child;
}
}
[GtkChild] public unowned ConversationActions full_actions;
[GtkChild] public unowned ConversationActions compact_actions;
[GtkChild] private unowned Hdy.Leaflet conversations_leaflet;
@ -27,36 +43,47 @@ public class 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 Components.ConversationHeaderBar conversation_header;
// Conversation viewer header elements
[GtkChild] private unowned Hdy.HeaderBar conversation_header;
[GtkChild] private unowned Hdy.Squeezer actions_squeezer;
[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,
Components.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/main-toolbar-menus.ui");
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
);
this.actions_squeezer.notify["visible-child"].connect_after(
() => { notify_property("shown-actions"); }
);
}
public void set_conversation_header(Hdy.HeaderBar header) {
@ -97,10 +124,6 @@ public class MainToolbar : Hdy.Leaflet {
conversation_group.add_swipeable(this);
}
public void add_conversation_actions(Components.ConversationActions actions) {
conversation_header.add_conversation_actions(actions);
}
public void show_main_menu() {
this.main_menu_button.clicked();
}

View file

@ -27,14 +27,14 @@ public class Composer.Box : Gtk.Frame, Container {
/** {@inheritDoc} */
internal Widget composer { get; set; }
private MainToolbar main_toolbar { get; private set; }
private Components.MainToolbar main_toolbar { get; private set; }
/** Emitted when the container is closed. */
public signal void vanished();
public Box(Widget composer, MainToolbar main_toolbar) {
public Box(Widget composer, Components.MainToolbar main_toolbar) {
this.composer = composer;
this.composer.set_mode(PANED);

View file

@ -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',
@ -57,6 +55,7 @@ client_vala_sources = files(
'components/components-inspector-error-view.vala',
'components/components-inspector-log-view.vala',
'components/components-inspector-system-view.vala',
'components/components-main-toolbar.vala',
'components/components-placeholder-pane.vala',
'components/components-preferences-window.vala',
'components/components-problem-report-info-bar.vala',
@ -67,7 +66,6 @@ client_vala_sources = files(
'components/count-badge.vala',
'components/folder-popover.vala',
'components/icon-factory.vala',
'components/main-toolbar.vala',
'components/monitored-progress-bar.vala',
'components/monitored-spinner.vala',
'components/status-bar.vala',

View file

@ -139,6 +139,9 @@ valadoc_vapi_dirs = [
vapi_dir,
meson.current_build_dir()
]
if libhandy_vapi != ''
valadoc_vapi_dirs += libhandy_vapi
endif
# Hopefully Meson will get baked-in valadoc support, so we don't have
# to resort to these kinds of hacks any more. See
@ -147,7 +150,11 @@ valadoc_vapi_dirs = [
valadoc_dep_args = []
foreach dep : valadoc_dependencies
valadoc_dep_args += '--pkg'
valadoc_dep_args += dep.name()
if dep != libhandy
valadoc_dep_args += dep.name()
else
valadoc_dep_args += 'libhandy-1'
endif
endforeach
valadoc_dep_args += [ '--pkg', 'icu-uc' ]
valadoc_dep_args += [ '--pkg', 'libstemmer' ]

View file

@ -0,0 +1,5 @@
[wrap-git]
directory = libhandy
url = https://gitlab.gnome.org/GNOME/libhandy.git
revision = 1.2.1

View file

@ -18,14 +18,14 @@
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyLeaflet" id="main_leaflet">
<object class="HdyLeaflet" id="outer_leaflet">
<property name="visible">True</property>
<property name="can_swipe_back">True</property>
<property name="transition_type">over</property>
<signal name="notify::visible-child" handler="on_main_leaflet_visible_child_changed" swapped="no"/>
<signal name="notify::child-transition-running" handler="on_main_leaflet_visible_child_changed" swapped="no"/>
<signal name="notify::folded" handler="on_outer_leaflet_changed" swapped="no"/>
<signal name="notify::visible-child" handler="on_outer_leaflet_changed" swapped="no"/>
<child>
<object class="HdyLeaflet" id="conversations_leaflet">
<object class="HdyLeaflet" id="inner_leaflet">
<property name="visible">True</property>
<property name="hexpand_set">True</property>
<property name="can_swipe_back">True</property>
@ -57,7 +57,7 @@
</child>
</object>
<packing>
<property name="name">folder</property>
<property name="name">folder_list</property>
</packing>
</child>
<child>
@ -98,14 +98,36 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRevealer" id="conversation_list_actions_revealer">
<property name="visible">True</property>
<property name="reveal-child">False</property>
<property name="transition_type">slide-up</property>
<child>
<object class="ComponentsConversationActions" id="conversation_list_actions">
<property name="visible">True</property>
<property name="show_conversation_actions">True</property>
<property name="show_response_actions">False</property>
<property name="pack_justified">True</property>
<property name="hexpand">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="name">conversations</property>
<property name="name">conversation_list</property>
</packing>
</child>
</object>
<packing>
<property name="name">conversations</property>
<property name="name">inner_leaflet</property>
</packing>
</child>
<child>
@ -125,8 +147,17 @@
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="ComponentsConversationActionBar" id="conversation_viewer_action_bar">
<object class="GtkRevealer" id="conversation_viewer_actions_revealer">
<property name="visible">True</property>
<property name="reveal-child">False</property>
<property name="transition_type">slide-up</property>
<child>
<object class="ComponentsConversationActions" id="conversation_viewer_actions">
<property name="visible">True</property>
<property name="show_conversation_actions">True</property>
<property name="show_response_actions">False</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
@ -134,7 +165,7 @@
</child>
</object>
<packing>
<property name="name">conversation</property>
<property name="name">conversation_viewer</property>
</packing>
</child>
</object>
@ -191,12 +222,12 @@
</object>
<object class="HdySwipeGroup" id="conversations_swipe_group">
<swipeables>
<swipeable name="conversations_leaflet"/>
<swipeable name="inner_leaflet"/>
</swipeables>
</object>
<object class="HdySwipeGroup" id="conversation_swipe_group">
<swipeables>
<swipeable name="main_leaflet"/>
<swipeable name="outer_leaflet"/>
</swipeables>
</object>
</interface>

View file

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkImage" id="archive_image">
<property name="visible">True</property>
<property name="icon_name">mail-archive-symbolic</property>
</object>
<template class="ComponentsConversationActionBar" parent="GtkRevealer">
<property name="visible">True</property>
<property name="transition_type">slide-up</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
</object>
</child>
<child>
<object class="GtkBox" id="action_box">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="margin_start">6</property>
<property name="margin_end">6</property>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -1,200 +1,201 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkBox" id="mark_copy_move_buttons">
<requires lib="gtk+" version="3.20"/>
<template class="ComponentsConversationActions" parent="GtkBox">
<property name="orientation">horizontal</property>
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<object class="GtkBox" id="response_buttons">
<property name="visible">True</property>
<child>
<object class="GtkMenuButton" id="mark_message_button">
<object class="GtkButton" id="reply_sender_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Reply</property>
<property name="action_name">win.reply-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="reply_sender_image">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="mark_message_image">
<property name="visible">True</property>
<property name="icon_name">marker-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
<property name="icon_name">mail-reply-sender-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="copy_message_button">
<object class="GtkButton" id="reply_all_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Reply All</property>
<property name="action_name">win.reply-all-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="reply_all_image">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="copy_message_image">
<property name="visible">True</property>
<property name="icon_name">tag-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
<property name="icon_name">mail-reply-all-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="move_message_button">
<object class="GtkButton" id="forward_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Forward</property>
<property name="action_name">win.forward-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="forward_image">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="move_message_image">
<property name="visible">True</property>
<property name="icon_name">folder-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
<property name="icon_name">mail-forward-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<style>
<class name="raised"/>
<class name="linked"/>
<class name="raised"/>
<class name="linked"/>
</style>
</object>
<object class="GtkBox" id="reply_forward_buttons">
</object>
</child>
<child>
<object class="GtkBox" id="mark_copy_move_buttons">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="reply_sender_button">
<object class="GtkMenuButton" id="mark_message_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="mark_message_image">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Reply</property>
<property name="action_name">win.reply-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="reply_sender_image">
<property name="visible">True</property>
<property name="icon_name">mail-reply-sender-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
<property name="icon_name">marker-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="reply_all_button">
<object class="GtkMenuButton" id="copy_message_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="copy_message_image">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Reply All</property>
<property name="action_name">win.reply-all-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="reply_all_image">
<property name="visible">True</property>
<property name="icon_name">mail-reply-all-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
<property name="icon_name">tag-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="forward_button">
<object class="GtkMenuButton" id="move_message_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="move_message_image">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Forward</property>
<property name="action_name">win.forward-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="forward_image">
<property name="visible">True</property>
<property name="icon_name">mail-forward-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
<property name="icon_name">folder-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<style>
<class name="raised"/>
<class name="linked"/>
<class name="raised"/>
<class name="linked"/>
</style>
</object>
<object class="GtkImage" id="archive_image">
</object>
</child>
<child>
<object class="GtkImage" id="archive_image">
<property name="visible">True</property>
<property name="icon_name">mail-archive-symbolic</property>
</object>
<object class="GtkBox" id="archive_trash_delete_buttons">
</object>
<object class="GtkBox" id="archive_trash_delete_buttons">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="archive_button">
<property name="label" translatable="yes">_Archive</property>
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="action_name">win.archive-conversation</property>
<property name="image">archive_image</property>
<property name="use_underline">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
<object class="GtkButton" id="archive_button">
<property name="label" translatable="yes">_Archive</property>
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="action_name">win.archive-conversation</property>
<property name="image">archive_image</property>
<property name="use_underline">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="trash_delete_button">
<object class="GtkButton" id="trash_delete_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="action_name">win.trash-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="trash_delete_image">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="action_name">win.trash-conversation</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="trash_delete_image">
<property name="visible">True</property>
<property name="icon_name">user-trash-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
<property name="icon_name">user-trash-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="raised"/>
<class name="linked"/>
<class name="raised"/>
<class name="linked"/>
</style>
</object>
<object class="GtkToggleButton" id="find_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Toggle find bar</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="find_image">
<property name="visible">True</property>
<property name="icon_name">preferences-system-search-symbolic</property>
</object>
</child>
</object>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
</template>
</interface>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="ComponentsConversationHeaderBar" parent="HdyHeaderBar">
<property name="visible">True</property>
<property name="hexpand">True</property>
<signal name="notify::parent" handler="update_action_bar" swapped="no"/>
<child>
<object class="GtkButton" id="conversation_back">
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="use-underline">True</property>
<property name="visible" bind-property="folded" bind-source="ComponentsConversationHeaderBar" bind-flags="sync-create"/>
<property name="action_name">win.navigation-back</property>
<style>
<class name="image-button"/>
</style>
<child internal-child="accessible">
<object class="AtkObject" id="a11y-conversation-back">
<property name="accessible-name" translatable="yes">Back</property>
</object>
</child>
<child>
<object class="GtkImage" id="conversation_back_image">
<property name="visible">True</property>
<property name="icon_name">go-previous-symbolic</property>
<property name="icon_size">1</property>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -2,11 +2,7 @@
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkImage" id="archive_image">
<property name="visible">True</property>
<property name="icon_name">mail-archive-symbolic</property>
</object>
<template class="MainToolbar" parent="HdyLeaflet">
<template class="ComponentsMainToolbar" parent="HdyLeaflet">
<property name="visible">True</property>
<property name="can_swipe_back">True</property>
<property name="transition_type">over</property>
@ -19,7 +15,7 @@
<child>
<object class="HdyHeaderBar" id="folder_header">
<property name="visible">True</property>
<property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
<property name="show_close_button" bind-source="ComponentsMainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
<property name="title">Mail</property>
<child>
<object class="GtkMenuButton" id="main_menu_button">
@ -60,7 +56,7 @@
<object class="HdyHeaderBar" id="conversations_header">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
<property name="show_close_button" bind-source="ComponentsMainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
<child>
<object class="GtkButton" id="conversations_back">
<property name="receives_default">False</property>
@ -102,7 +98,7 @@
</object>
</child>
<child>
<object class="GtkToggleButton" id="search_conversations_button">
<object class="GtkToggleButton" id="search_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
@ -143,9 +139,73 @@
</packing>
</child>
<child>
<object class="ComponentsConversationHeaderBar" id="conversation_header">
<property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
<property name="folded" bind-source="MainToolbar" bind-property="folded" bind-flags="sync-create"/>
<object class="HdyHeaderBar" id="conversation_header">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="show_close_button" bind-source="ComponentsMainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
<child>
<object class="GtkButton" id="conversation_back">
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="use-underline">True</property>
<property name="visible" bind-source="ComponentsMainToolbar" bind-property="folded" bind-flags="sync-create"/>
<property name="action_name">win.navigation-back</property>
<style>
<class name="image-button"/>
</style>
<child internal-child="accessible">
<object class="AtkObject" id="a11y-conversation-back">
<property name="accessible-name" translatable="yes">Back</property>
</object>
</child>
<child>
<object class="GtkImage" id="conversation_back_image">
<property name="visible">True</property>
<property name="icon_name">go-previous-symbolic</property>
<property name="icon_size">1</property>
</object>
</child>
</object>
</child>
<child type="title">
<object class="HdySqueezer" id="actions_squeezer">
<property name="visible">True</property>
<property name="hexpand">True</property>
<child>
<object class="ComponentsConversationActions" id="full_actions">
<property name="visible">True</property>
<property name="show_conversation_actions">True</property>
<property name="show_response_actions">True</property>
</object>
</child>
<child>
<object class="ComponentsConversationActions" id="compact_actions">
<property name="visible">True</property>
<property name="show_conversation_actions">False</property>
<property name="show_response_actions">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToggleButton" id="find_button">
<property name="visible">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Toggle find bar</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage" id="find_image">
<property name="visible">True</property>
<property name="icon_name">preferences-system-search-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="name">conversation</property>
@ -160,7 +220,7 @@
</headerbars>
</object>
<object class="HdyHeaderGroup" id="header_group">
<property name="decorate-all" bind-source="MainToolbar" bind-property="folded" bind-flags="sync-create"/>
<property name="decorate-all" bind-source="ComponentsMainToolbar" bind-property="folded" bind-flags="sync-create"/>
<headerbars>
<headerbar name="conversations_header_group"/>
<headerbar name="conversation_header"/>

View file

@ -18,6 +18,10 @@
min-width: 250px;
}
geary-conversation-list revealer {
margin: 6px;
}
.geary-conversation-frame > border {
border-left-width: 0;
border-top-width: 0;
@ -56,6 +60,12 @@ infobar flowboxchild {
padding: 0px;
}
revealer components-conversation-actions {
border: solid @borders;
border-top-width: 1px;
padding: 6px;
}
/* FolderPopover */
row.geary-folder-popover-list-row {

View file

@ -12,8 +12,6 @@
<file compressed="true" preprocess="xml-stripblanks">components-attachment-pane.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-attachment-pane-menus.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-attachment-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-conversation-header-bar.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-conversation-action-bar.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-conversation-actions.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-in-app-notification.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-info-bar.ui</file>
@ -21,6 +19,8 @@
<file compressed="true" preprocess="xml-stripblanks">components-inspector-error-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-inspector-log-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-inspector-system-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-main-toolbar.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-main-toolbar-menus.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components-placeholder-pane.ui</file>
<file compressed="true" preprocess="xml-stripblanks">composer-editor.ui</file>
<file compressed="true" preprocess="xml-stripblanks">composer-editor-menus.ui</file>
@ -41,8 +41,6 @@
<file compressed="true" preprocess="xml-stripblanks">find_bar.glade</file>
<file compressed="true" preprocess="xml-stripblanks">folder-popover.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
<file compressed="true" preprocess="xml-stripblanks">main-toolbar.ui</file>
<file compressed="true" preprocess="xml-stripblanks">main-toolbar-menus.ui</file>
<file compressed="true" preprocess="xml-stripblanks">password-dialog.glade</file>
<file compressed="true" preprocess="xml-stripblanks">problem-details-dialog.ui</file>
<file compressed="true">signature-web-view.js</file>