[geary/gnumdk/rework-move-button] components: Rework Folder Popover




commit a61fdf0788678f978acb18f24dfdd453627f7000
Author: Cédric Bellegarde <cedric bellegarde adishatz org>
Date:   Mon Jul 18 13:54:39 2022 +0200

    components: Rework Folder Popover
    
    - Do not use tags for service providers not using this metaphor
    - Do not show folders with a dedicated button: Trash, Archive, ...
    - Do not show folders as an IMAP path but as a human readable path (>INBOX>Folder vs Boîte de 
reception/Folder)

 .../application/application-folder-context.vala    | 13 +++-
 .../application/application-main-window.vala       | 37 ++++++++++-
 .../components-conversation-actions.vala           | 44 ++++++++++---
 src/client/components/folder-popover-row.vala      | 32 ++++++++++
 src/client/components/folder-popover.vala          | 73 +++++++++++++++-------
 .../folder-list/folder-list-account-branch.vala    | 13 +++-
 src/client/meson.build                             |  1 +
 src/client/util/util-gtk.vala                      |  9 +++
 ui/folder-popover-row.ui                           | 46 ++++++++++++++
 ui/folder-popover.ui                               |  4 +-
 ui/geary.css                                       |  4 +-
 ui/org.gnome.Geary.gresource.xml                   |  1 +
 12 files changed, 238 insertions(+), 39 deletions(-)
---
diff --git a/src/client/application/application-folder-context.vala 
b/src/client/application/application-folder-context.vala
index 4ed47cf56..1a16385b9 100644
--- a/src/client/application/application-folder-context.vala
+++ b/src/client/application/application-folder-context.vala
@@ -46,6 +46,17 @@ public class Application.FolderContext : Geary.BaseObject,
         return this.folder.path.compare_to(other.folder.path);
     }
 
+    private string get_default_icon_name() {
+        var service_provider = this.folder.account.information.service_provider;
+
+        switch (service_provider) {
+        case Geary.ServiceProvider.GMAIL:
+            return "tag-symbolic";
+        default:
+            return "folder-symbolic";
+        }
+    }
+
     private void update() {
         this.display_name = Util.I18n.to_folder_display_name(this.folder);
 
@@ -88,7 +99,7 @@ public class Application.FolderContext : Geary.BaseObject,
             break;
 
         default:
-            this.icon_name = "tag-symbolic";
+            this.icon_name = get_default_icon_name();
             break;
         }
 
diff --git a/src/client/application/application-main-window.vala 
b/src/client/application/application-main-window.vala
index 8e969d108..2e77c08d7 100644
--- a/src/client/application/application-main-window.vala
+++ b/src/client/application/application-main-window.vala
@@ -1177,11 +1177,23 @@ public class Application.MainWindow :
 
     /** Adds a folder to the window. */
     private void add_folders(Gee.Collection<FolderContext> to_add) {
+        // Build map between path and display name for
+        // special directories
+        var map = new Gee.HashMap<string,string>();
+        foreach (var context in to_add) {
+            var folder = context.folder;
+            if (folder.used_as == Geary.Folder.SpecialUse.NONE)
+                continue;
+            map.set(
+                folder.path.to_string().substring(1),
+                context.display_name
+            );
+        }
         foreach (var context in to_add) {
             this.folder_list.add_folder(context);
             if (context.folder.account == this.selected_account) {
                 foreach (var menu in this.folder_popovers) {
-                    menu.add_folder(context.folder);
+                    menu.add_folder(context, map);
                 }
             }
             context.folder.use_changed.connect(on_use_changed);
@@ -1587,9 +1599,28 @@ public class Application.MainWindow :
             this.search_bar.set_account(account);
 
             if (account != null) {
+                var service_provider = account.information.service_provider;
+                this.conversation_list_actions.service_provider = service_provider;
+                this.main_toolbar.full_actions.service_provider = service_provider;
+                this.main_toolbar.compact_actions.service_provider = service_provider;
+
                 foreach (var menu in this.folder_popovers) {
-                    foreach (var folder in account.list_folders()) {
-                        menu.add_folder(folder);
+                    var folders = account.list_folders();
+                    // Build map between path and display name for
+                    // special directories
+                    var map = new Gee.HashMap<string,string>();
+                    foreach (var folder in folders) {
+                        var context = new Application.FolderContext(folder);
+                        if (folder.used_as == Geary.Folder.SpecialUse.NONE)
+                            continue;
+                        map.set(
+                            folder.path.to_string().substring(1),
+                            context.display_name
+                        );
+                    }
+                    foreach (var folder in folders) {
+                        var context = new Application.FolderContext(folder);
+                        menu.add_folder(context, map);
                     }
                 }
             }
diff --git a/src/client/components/components-conversation-actions.vala 
b/src/client/components/components-conversation-actions.vala
index f7df39fb9..8b416d63c 100644
--- a/src/client/components/components-conversation-actions.vala
+++ b/src/client/components/components-conversation-actions.vala
@@ -18,12 +18,18 @@ public class Components.ConversationActions : Gtk.Box {
 
     public bool pack_justified { get; construct; }
 
-    public FolderPopover copy_folder_menu { get; private set; default = new FolderPopover(); }
+    public FolderPopover copy_folder_menu {
+        get; private set; default = new FolderPopover(FolderPopover.FolderType.TAG);
+    }
 
-    public FolderPopover move_folder_menu { get; private set; default = new FolderPopover(); }
+    public FolderPopover move_folder_menu {
+        get; private set; default = new FolderPopover(FolderPopover.FolderType.DEFAULT);
+    }
 
     public int selected_conversations { get; set; }
 
+    public Geary.ServiceProvider service_provider { get; set; }
+
     [GtkChild] private unowned Gtk.Box response_buttons { get; }
 
     [GtkChild] private unowned Gtk.Box mark_copy_move_buttons { get; }
@@ -56,6 +62,7 @@ public class Components.ConversationActions : Gtk.Box {
         );
 
         this.notify["selected-conversations"].connect(() => update_conversation_buttons());
+        this.notify["service-provider"].connect(() => update_conversation_buttons());
         this.mark_message_button.popover = new Gtk.Popover.from_model(null, mark_menu);
         this.copy_message_button.popover = copy_folder_menu;
         this.move_message_button.popover = move_folder_menu;
@@ -98,11 +105,7 @@ public class Components.ConversationActions : Gtk.Box {
             "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",
@@ -114,6 +117,33 @@ public class Components.ConversationActions : Gtk.Box {
             this.selected_conversations
             );
 
+        var copy_icon_name = "edit-copy-symbolic";
+        var move_icon_name = "edit-cut-symbolic";
+        switch (this.service_provider) {
+        case Geary.ServiceProvider.GMAIL:
+            this.copy_message_button.tooltip_text = ngettext(
+                "Add label to conversation",
+                "Add label to conversations",
+                this.selected_conversations
+                );
+            copy_icon_name = "tag-symbolic";
+            move_icon_name = "folder-symbolic";
+            break;
+        default:
+            this.copy_message_button.tooltip_text = ngettext(
+                "Copy conversation",
+                "Copy conversations",
+                this.selected_conversations
+                );
+            break;
+        }
+        this.copy_message_button.set_image(
+            new Gtk.Image.from_icon_name(copy_icon_name, Gtk.IconSize.BUTTON)
+        );
+        this.move_message_button.set_image(
+            new Gtk.Image.from_icon_name(move_icon_name, Gtk.IconSize.BUTTON)
+        );
+
         if (this.show_trash_button) {
             this.trash_delete_button.action_name = Action.Window.prefix(
                 Application.MainWindow.ACTION_TRASH_CONVERSATION
diff --git a/src/client/components/folder-popover-row.vala b/src/client/components/folder-popover-row.vala
new file mode 100644
index 000000000..98033bcdf
--- /dev/null
+++ b/src/client/components/folder-popover-row.vala
@@ -0,0 +1,32 @@
+/* Copyright 2022 Cédric Bellegarde <cedric bellegarde adishatz org>
+ *
+ * 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/folder-popover-row.ui")]
+public class FolderPopoverRow : Gtk.ListBoxRow {
+
+    [GtkChild] private unowned Gtk.Image image;
+    [GtkChild] private unowned Gtk.Label label;
+
+    public FolderPopoverRow(Application.FolderContext context, Gee.HashMap<string,string> map) {
+        string[] as_array = context.folder.path.as_array();
+
+        if (map.has_key(as_array[0])) {
+            as_array[0] = map[as_array[0]];
+        }
+
+        var i = 0;
+        foreach (string name in as_array) {
+            as_array[i] = GLib.Markup.escape_text(name);
+            i += 1;
+        }
+
+        this.set_data("folder", context.folder);
+        this.image.icon_name = context.icon_name;
+
+        this.label.set_markup(string.joinv("<span alpha='30%'> / </span>", as_array));
+        this.label.query_tooltip.connect(Util.Gtk.query_tooltip_label);
+    }
+}
diff --git a/src/client/components/folder-popover.vala b/src/client/components/folder-popover.vala
index faba1df2b..e05ac98fa 100644
--- a/src/client/components/folder-popover.vala
+++ b/src/client/components/folder-popover.vala
@@ -7,14 +7,25 @@
 [GtkTemplate (ui = "/org/gnome/Geary/folder-popover.ui")]
 public class FolderPopover : Gtk.Popover {
 
+    public enum FolderType {
+
+        /** Standard folder. */
+        DEFAULT,
+
+        /** Tag folder. */
+        TAG,
+    }
+
     [GtkChild] private unowned Gtk.SearchEntry search_entry;
     [GtkChild] private unowned Gtk.ListBox list_box;
 
+    private FolderType folder_type;
     private int filtered_folder_count = 0;
 
     public signal void folder_selected(Geary.Folder folder);
 
-    public FolderPopover() {
+    public FolderPopover(FolderType folder_type) {
+        this.folder_type = folder_type;
         list_box.set_filter_func(row_filter);
         list_box.set_sort_func(row_sort);
         this.show.connect(() => search_entry.grab_focus());
@@ -28,7 +39,8 @@ public class FolderPopover : Gtk.Popover {
         return get_row_with_folder(folder) != null;
     }
 
-    public void add_folder(Geary.Folder folder) {
+    public void add_folder(Application.FolderContext context, Gee.HashMap<string,string> map) {
+        Geary.Folder folder = context.folder;
         // don't allow multiples and don't allow folders that can't be opened (that means they
         // support almost no operations and have no content)
         if (has_folder(folder) || folder.properties.is_openable.is_impossible())
@@ -39,14 +51,38 @@ public class FolderPopover : Gtk.Popover {
         if (folder.properties.is_local_only || folder.properties.is_virtual)
             return;
 
-        list_box.add(build_row(folder));
+        // Ignore special directories for this providers, not supported
+        if (this.folder_type == FolderType.TAG) {
+            switch (folder.account.information.service_provider) {
+            case Geary.ServiceProvider.GMAIL:
+                if (folder.used_as != Geary.Folder.SpecialUse.NONE)
+                    return;
+                break;
+            default:
+                break;
+            }
+        }
+
+        // Ignore special directories already having a dedicated button
+        switch (folder.used_as) {
+        case Geary.Folder.SpecialUse.ARCHIVE:
+        case Geary.Folder.SpecialUse.TRASH:
+        case Geary.Folder.SpecialUse.JUNK:
+            return;
+        default:
+            break;
+        }
+
+        var row = new FolderPopoverRow(context, map);
+        row.show();
+        list_box.add(row);
         list_box.invalidate_sort();
     }
 
-    public void enable_disable_folder(Geary.Folder folder, bool sensitive) {
+    public void enable_disable_folder(Geary.Folder folder, bool visible) {
         Gtk.ListBoxRow row = get_row_with_folder(folder);
         if (row != null)
-            row.sensitive = sensitive;
+            row.visible = visible;
     }
 
     public void remove_folder(Geary.Folder folder) {
@@ -68,20 +104,6 @@ public class FolderPopover : Gtk.Popover {
         list_box.foreach((row) => list_box.remove(row));
     }
 
-    private Gtk.ListBoxRow build_row(Geary.Folder folder) {
-        Gtk.ListBoxRow row = new Gtk.ListBoxRow();
-        row.get_style_context().add_class("geary-folder-popover-list-row");
-        row.set_data("folder", folder);
-
-        Gtk.Label label = new Gtk.Label(folder.path.to_string());
-        label.set_halign(Gtk.Align.START);
-        row.add(label);
-
-        row.show_all();
-
-        return row;
-    }
-
     [GtkCallback]
     private void on_row_activated(Gtk.ListBoxRow? row) {
         if (row != null) {
@@ -118,8 +140,8 @@ public class FolderPopover : Gtk.Popover {
     }
 
     private bool row_filter(Gtk.ListBoxRow row) {
-        Gtk.Label label = row.get_child() as Gtk.Label;
-        if (label.label.down().contains(search_entry.text.down())) {
+        Geary.Folder folder = row.get_data<Geary.Folder>("folder");
+        if (folder.path.to_string().down().contains(search_entry.text.down())) {
             filtered_folder_count++;
             return true;
         }
@@ -129,6 +151,13 @@ public class FolderPopover : Gtk.Popover {
     private int row_sort(Gtk.ListBoxRow row1, Gtk.ListBoxRow row2) {
         Geary.Folder folder1 = row1.get_data<Geary.Folder>("folder");
         Geary.Folder folder2 = row2.get_data<Geary.Folder>("folder");
-        return folder1.path.compare_to(folder2.path);
+        if (folder1.used_as != Geary.Folder.SpecialUse.NONE &&
+                folder2.used_as == Geary.Folder.SpecialUse.NONE)
+            return -1;
+        else if (folder1.used_as == Geary.Folder.SpecialUse.NONE &&
+                folder2.used_as != Geary.Folder.SpecialUse.NONE)
+            return 1;
+        else
+            return folder1.path.compare_to(folder2.path);
     }
 }
diff --git a/src/client/folder-list/folder-list-account-branch.vala 
b/src/client/folder-list/folder-list-account-branch.vala
index 4e67a1948..ffb576a96 100644
--- a/src/client/folder-list/folder-list-account-branch.vala
+++ b/src/client/folder-list/folder-list-account-branch.vala
@@ -43,7 +43,18 @@ public class FolderList.AccountBranch : Sidebar.Branch {
         // Translators: The name of the folder group containing
         // folders created by people (as opposed to special-use
         // folders)
-        user_folder_group = new SpecialGrouping(2, _("Labels"), "tag-symbolic");
+        string name, icon_name;
+        switch (account.information.service_provider) {
+        case Geary.ServiceProvider.GMAIL:
+            name = _("Labels");
+            icon_name = "tag-symbolic";
+            break;
+        default:
+            name = _("Folders");
+            icon_name = "folder-symbolic";
+            break;
+        }
+        user_folder_group = new SpecialGrouping(2, name, icon_name);
         folder_entries = new Gee.HashMap<Geary.FolderPath, FolderEntry>();
 
         this.display_name = account.information.display_name;
diff --git a/src/client/meson.build b/src/client/meson.build
index 715358320..982590c54 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -65,6 +65,7 @@ client_vala_sources = files(
   'components/components-web-view.vala',
   'components/count-badge.vala',
   'components/folder-popover.vala',
+  'components/folder-popover-row.vala',
   'components/icon-factory.vala',
   'components/monitored-progress-bar.vala',
   'components/monitored-spinner.vala',
diff --git a/src/client/util/util-gtk.vala b/src/client/util/util-gtk.vala
index 09d59e816..63e27e136 100644
--- a/src/client/util/util-gtk.vala
+++ b/src/client/util/util-gtk.vala
@@ -227,4 +227,13 @@ namespace Util.Gtk {
         };
     }
 
+    /* Connect this to Gtk.Widget.query_tooltip signal, will only show tooltip if label ellipsized */
+    public bool query_tooltip_label(global::Gtk.Widget widget, int x, int y, bool keyboard, 
global::Gtk.Tooltip tooltip) {
+        global::Gtk.Label label = widget as global::Gtk.Label;
+        if (label.get_layout().is_ellipsized()) {
+            tooltip.set_markup(label.label);
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/ui/folder-popover-row.ui b/ui/folder-popover-row.ui
new file mode 100644
index 000000000..b7a9309e0
--- /dev/null
+++ b/ui/folder-popover-row.ui
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.14"/>
+  <template class="FolderPopoverRow" parent="GtkListBoxRow">
+    <child>
+      <object class="GtkBox" id="container">
+        <property name="visible">True</property>
+        <property name="margin_start">6</property>
+        <property name="margin_end">6</property>
+        <property name="margin_top">6</property>
+        <property name="margin_bottom">6</property>
+        <property name="orientation">horizontal</property>
+        <property name="spacing">10</property>
+        <child>
+          <object class="GtkImage" id="image">
+            <property name="visible">True</property>
+            <property name="halign">start</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label">
+            <property name="visible">True</property>
+            <property name="halign">start</property>
+            <property name="hexpand">True</property>
+            <property name="has_tooltip">True</property>
+            <property name="ellipsize">end</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <style>
+      <class name="geary-folder-popover-list-row"/>
+    </style>
+  </template>
+</interface>
diff --git a/ui/folder-popover.ui b/ui/folder-popover.ui
index 473d3dc34..894924d8a 100644
--- a/ui/folder-popover.ui
+++ b/ui/folder-popover.ui
@@ -29,10 +29,10 @@
         </child>
         <child>
           <object class="GtkScrolledWindow" id="scrolled">
-            <property name="min_content_width">200</property>
+            <property name="width-request">300</property>
             <property name="min_content_height">320</property>
             <property name="visible">True</property>
-            <property name="shadow_type">in</property>
+            <property name="shadow_type">none</property>
             <property name="hscrollbar_policy">never</property>
             <child>
               <object class="GtkListBox" id="list_box">
diff --git a/ui/geary.css b/ui/geary.css
index 84533f5ff..29f765bd1 100644
--- a/ui/geary.css
+++ b/ui/geary.css
@@ -70,9 +70,7 @@ revealer components-conversation-actions {
 
 row.geary-folder-popover-list-row {
   padding: 6px;
-  border-color: @borders;
-  border-style: groove;
-  border-bottom-width: 1px;
+  border-bottom: 1px solid @borders;
 }
 row.geary-folder-popover-list-row > label {
   color: @theme_text_color;
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
index 57b977a35..3af61ca76 100644
--- a/ui/org.gnome.Geary.gresource.xml
+++ b/ui/org.gnome.Geary.gresource.xml
@@ -40,6 +40,7 @@
     <file compressed="true">conversation-web-view.js</file>
     <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">folder-popover-row.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">password-dialog.glade</file>
     <file compressed="true" preprocess="xml-stripblanks">problem-details-dialog.ui</file>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]