[geary/gnumdk/stable: 21/21] components: Rework Folder Popover




commit 94337634e8853f5e31db9ef77d5feedd8dba8d73
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       | 39 +++++++++++++--
 .../components-conversation-actions.vala           | 36 ++++++++++++--
 src/client/components/folder-popover-row.vala      | 32 ++++++++++++
 src/client/components/folder-popover.vala          | 58 ++++++++++++++--------
 .../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                               |  5 +-
 ui/geary.css                                       | 14 ++++--
 ui/org.gnome.Geary.gresource.xml                   |  1 +
 12 files changed, 230 insertions(+), 37 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 41b4493ff..4270a6004 100644
--- a/src/client/application/application-main-window.vala
+++ b/src/client/application/application-main-window.vala
@@ -1168,11 +1168,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);
@@ -1561,9 +1573,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.conversation_headerbar.full_actions.service_provider = service_provider;
+                this.conversation_headerbar.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);
                     }
                 }
             }
@@ -2408,7 +2439,7 @@ public class Application.MainWindow :
             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();
+            this.conversation_headerbar.shown_actions.show_copy_menu();
         } else {
             error_bell();
         }
diff --git a/src/client/components/components-conversation-actions.vala 
b/src/client/components/components-conversation-actions.vala
index 8030c424b..7adb6afc3 100644
--- a/src/client/components/components-conversation-actions.vala
+++ b/src/client/components/components-conversation-actions.vala
@@ -24,6 +24,8 @@ public class Components.ConversationActions : Gtk.Box {
 
     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 +58,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;
@@ -110,11 +113,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",
@@ -126,6 +125,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..90dfd81f0 100644
--- a/src/client/components/folder-popover.vala
+++ b/src/client/components/folder-popover.vala
@@ -28,7 +28,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 +40,36 @@ public class FolderPopover : Gtk.Popover {
         if (folder.properties.is_local_only || folder.properties.is_virtual)
             return;
 
-        list_box.add(build_row(folder));
+        // Moving mails to Drafts folder not supported
+        switch (folder.account.information.service_provider) {
+        case Geary.ServiceProvider.GMAIL:
+            if (folder.used_as == Geary.Folder.SpecialUse.DRAFTS)
+                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 +91,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 +127,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 +138,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 ef8e7d641..eeabedbb9 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -68,6 +68,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..881c8a5fb 100644
--- a/ui/folder-popover.ui
+++ b/ui/folder-popover.ui
@@ -29,14 +29,15 @@
         </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">
                 <property name="visible">True</property>
+                <property name="valign">start</property>
                 <property name="activate_on_single_click">True</property>
                 <signal name="row_activated" handler="on_row_activated" swapped="no"/>
                 <style>
diff --git a/ui/geary.css b/ui/geary.css
index 84533f5ff..309b756bb 100644
--- a/ui/geary.css
+++ b/ui/geary.css
@@ -68,12 +68,20 @@ revealer components-conversation-actions {
 
 /* FolderPopover */
 
+.geary-folder-popover-list {
+    border: 1px solid @borders;
+    border-radius: 3px;
+}
+
 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:last-child {
+  border-bottom: none;
+}
+
 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 d25e3b596..a486d1fa8 100644
--- a/ui/org.gnome.Geary.gresource.xml
+++ b/ui/org.gnome.Geary.gresource.xml
@@ -43,6 +43,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]