Added files
This commit is contained in:
		@@ -0,0 +1,235 @@
 | 
			
		||||
From 3b6dd303323cfc5b7bebe5b1d88170f1030f2de2 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 5 Sep 2020 14:13:01 +1000
 | 
			
		||||
Subject: [PATCH 001/124] Geary.Db.Context: Update access to
 | 
			
		||||
 DatabaseConnections
 | 
			
		||||
 | 
			
		||||
Ensure internal code can access a DatabaseConnection from context
 | 
			
		||||
objects to get access to connection-specific code, but make the
 | 
			
		||||
polymorphic context accessors internal so transactions can't access
 | 
			
		||||
them.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/db/db-connection.vala             |  5 +++--
 | 
			
		||||
 src/engine/db/db-context.vala                |  8 ++++----
 | 
			
		||||
 src/engine/db/db-database-connection.vala    |  8 ++++----
 | 
			
		||||
 src/engine/db/db-database.vala               |  8 ++++----
 | 
			
		||||
 src/engine/db/db-result.vala                 |  8 ++++----
 | 
			
		||||
 src/engine/db/db-statement.vala              | 19 ++++++++++++-------
 | 
			
		||||
 src/engine/db/db-transaction-connection.vala | 11 +----------
 | 
			
		||||
 src/engine/imap-db/imap-db-attachment.vala   |  2 +-
 | 
			
		||||
 8 files changed, 33 insertions(+), 36 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/db/db-connection.vala b/src/engine/db/db-connection.vala
 | 
			
		||||
index 4f0859e1..ebce27dc 100644
 | 
			
		||||
--- a/src/engine/db/db-connection.vala
 | 
			
		||||
+++ b/src/engine/db/db-connection.vala
 | 
			
		||||
@@ -18,7 +18,7 @@
 | 
			
		||||
  * A connection will be automatically closed when its last reference
 | 
			
		||||
  * is dropped.
 | 
			
		||||
  */
 | 
			
		||||
-public interface Geary.Db.Connection : Context {
 | 
			
		||||
+public interface Geary.Db.Connection : BaseObject {
 | 
			
		||||
 
 | 
			
		||||
     private const string PRAGMA_FOREIGN_KEYS = "foreign_keys";
 | 
			
		||||
     private const string PRAGMA_RECURSIVE_TRIGGERS = "recursive_triggers";
 | 
			
		||||
@@ -278,7 +278,8 @@ public interface Geary.Db.Connection : Context {
 | 
			
		||||
      *
 | 
			
		||||
      * @see exec
 | 
			
		||||
      */
 | 
			
		||||
-    public abstract Result query(string sql, GLib.Cancellable? cancellable = null)
 | 
			
		||||
+    public abstract Result query(string sql,
 | 
			
		||||
+                                 GLib.Cancellable? cancellable = null)
 | 
			
		||||
         throws GLib.Error;
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
diff --git a/src/engine/db/db-context.vala b/src/engine/db/db-context.vala
 | 
			
		||||
index 9bbb8503..a59f6c4c 100644
 | 
			
		||||
--- a/src/engine/db/db-context.vala
 | 
			
		||||
+++ b/src/engine/db/db-context.vala
 | 
			
		||||
@@ -37,19 +37,19 @@ public abstract class Geary.Db.Context : BaseObject, Logging.Source {
 | 
			
		||||
     private weak Logging.Source? _logging_parent = null;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-    public virtual Database? get_database() {
 | 
			
		||||
+    internal virtual Database? get_database() {
 | 
			
		||||
         return get_connection() != null ? get_connection().database : null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public virtual Connection? get_connection() {
 | 
			
		||||
+    internal virtual DatabaseConnection? get_connection() {
 | 
			
		||||
         return get_statement() != null ? get_statement().connection : null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public virtual Statement? get_statement() {
 | 
			
		||||
+    internal virtual Statement? get_statement() {
 | 
			
		||||
         return get_result() != null ? get_result().statement : null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public virtual Result? get_result() {
 | 
			
		||||
+    internal virtual Result? get_result() {
 | 
			
		||||
         return null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/engine/db/db-database-connection.vala b/src/engine/db/db-database-connection.vala
 | 
			
		||||
index 4e7ceb78..dd311bea 100644
 | 
			
		||||
--- a/src/engine/db/db-database-connection.vala
 | 
			
		||||
+++ b/src/engine/db/db-database-connection.vala
 | 
			
		||||
@@ -255,13 +255,13 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
         return yield job.wait_for_completion_async();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public override Connection? get_connection() {
 | 
			
		||||
-        return this;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public override Logging.State to_logging_state() {
 | 
			
		||||
         return new Logging.State(this, "%u", this.cx_number);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    internal override DatabaseConnection? get_connection() {
 | 
			
		||||
+        return this;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/engine/db/db-database.vala b/src/engine/db/db-database.vala
 | 
			
		||||
index 592bd306..a807e7ba 100644
 | 
			
		||||
--- a/src/engine/db/db-database.vala
 | 
			
		||||
+++ b/src/engine/db/db-database.vala
 | 
			
		||||
@@ -358,10 +358,6 @@ public class Geary.Db.Database : Context {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-    public override Database? get_database() {
 | 
			
		||||
-        return this;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public override Logging.State to_logging_state() {
 | 
			
		||||
         return new Logging.State(
 | 
			
		||||
@@ -386,6 +382,10 @@ public class Geary.Db.Database : Context {
 | 
			
		||||
         this.thread_pool.add(new_job);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    internal override Database? get_database() {
 | 
			
		||||
+        return this;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     /**
 | 
			
		||||
      * Hook for subclasses to modify a new SQLite connection before use.
 | 
			
		||||
      *
 | 
			
		||||
diff --git a/src/engine/db/db-result.vala b/src/engine/db/db-result.vala
 | 
			
		||||
index 1ec3ed55..64c78756 100644
 | 
			
		||||
--- a/src/engine/db/db-result.vala
 | 
			
		||||
+++ b/src/engine/db/db-result.vala
 | 
			
		||||
@@ -294,15 +294,15 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
         return column;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public override Result? get_result() {
 | 
			
		||||
-        return this;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public override Logging.State to_logging_state() {
 | 
			
		||||
         return new Logging.State(this, this.finished ? "finished" : "not finished");
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    internal override Result? get_result() {
 | 
			
		||||
+        return this;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     [PrintfFormat]
 | 
			
		||||
     private void log_result(string fmt, ...) {
 | 
			
		||||
         if (Db.Context.enable_sql_logging) {
 | 
			
		||||
diff --git a/src/engine/db/db-statement.vala b/src/engine/db/db-statement.vala
 | 
			
		||||
index 0a36dfb1..088b882b 100644
 | 
			
		||||
--- a/src/engine/db/db-statement.vala
 | 
			
		||||
+++ b/src/engine/db/db-statement.vala
 | 
			
		||||
@@ -13,7 +13,7 @@ public class Geary.Db.Statement : Context {
 | 
			
		||||
         get { return this.stmt.sql(); }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public Connection connection { get; private set; }
 | 
			
		||||
+    internal DatabaseConnection connection { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
     internal Sqlite.Statement stmt;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,9 +36,14 @@ public class Geary.Db.Statement : Context {
 | 
			
		||||
 
 | 
			
		||||
     private Gee.HashSet<Memory.Buffer> held_buffers = new Gee.HashSet<Memory.Buffer>();
 | 
			
		||||
 
 | 
			
		||||
-    internal Statement(Connection connection, string sql) throws DatabaseError {
 | 
			
		||||
+    internal Statement(DatabaseConnection connection, string sql)
 | 
			
		||||
+        throws DatabaseError {
 | 
			
		||||
         this.connection = connection;
 | 
			
		||||
-        throw_on_error("Statement.ctor", connection.db.prepare_v2(sql, -1, out stmt, null), sql);
 | 
			
		||||
+        throw_on_error(
 | 
			
		||||
+            "Statement.ctor",
 | 
			
		||||
+            connection.db.prepare_v2(sql, -1, out stmt, null),
 | 
			
		||||
+            sql
 | 
			
		||||
+        );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** Returns SQL for the statement with bound parameters expanded. */
 | 
			
		||||
@@ -271,13 +276,13 @@ public class Geary.Db.Statement : Context {
 | 
			
		||||
         return this;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public override Statement? get_statement() {
 | 
			
		||||
-        return this;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public override Logging.State to_logging_state() {
 | 
			
		||||
         return new Logging.State(this, this.sql);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    internal override Statement? get_statement() {
 | 
			
		||||
+        return this;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/engine/db/db-transaction-connection.vala b/src/engine/db/db-transaction-connection.vala
 | 
			
		||||
index 48244dbc..ebdd18b4 100644
 | 
			
		||||
--- a/src/engine/db/db-transaction-connection.vala
 | 
			
		||||
+++ b/src/engine/db/db-transaction-connection.vala
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
 /**
 | 
			
		||||
  * A connection to the database for transactions.
 | 
			
		||||
  */
 | 
			
		||||
-internal class Geary.Db.TransactionConnection : Context, Connection {
 | 
			
		||||
+internal class Geary.Db.TransactionConnection : BaseObject, Connection {
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
@@ -54,13 +54,4 @@ internal class Geary.Db.TransactionConnection : Context, Connection {
 | 
			
		||||
         this.db_cx.exec_file(file, cancellable);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public override Connection? get_connection() {
 | 
			
		||||
-        return this;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    public override Logging.State to_logging_state() {
 | 
			
		||||
-        return new Logging.State(this, "");
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/engine/imap-db/imap-db-attachment.vala b/src/engine/imap-db/imap-db-attachment.vala
 | 
			
		||||
index d8e8f9db..fa94b630 100644
 | 
			
		||||
--- a/src/engine/imap-db/imap-db-attachment.vala
 | 
			
		||||
+++ b/src/engine/imap-db/imap-db-attachment.vala
 | 
			
		||||
@@ -245,7 +245,7 @@ private class Geary.ImapDB.Attachment : Geary.Attachment {
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         // Ensure they're dead, Jim.
 | 
			
		||||
-        Db.Statement stmt = new Db.Statement(cx, """
 | 
			
		||||
+        Db.Statement stmt = cx.prepare("""
 | 
			
		||||
             DELETE FROM MessageAttachmentTable WHERE message_id = ?
 | 
			
		||||
         """);
 | 
			
		||||
         stmt.bind_rowid(0, message_id);
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
From e6fd0fe1742bd2143c1fa16fa30e82a5ea7996ed Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Thu, 23 Apr 2020 10:11:06 +0200
 | 
			
		||||
Subject: [PATCH 1/8] accounts-editor: Wrap the welcome panel labels
 | 
			
		||||
 | 
			
		||||
This helps the accounts editor fit in narrow screens.
 | 
			
		||||
---
 | 
			
		||||
 ui/accounts_editor_list_pane.ui | 4 ++++
 | 
			
		||||
 1 file changed, 4 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/accounts_editor_list_pane.ui b/ui/accounts_editor_list_pane.ui
 | 
			
		||||
index 59f8c632..a40604e3 100644
 | 
			
		||||
--- a/ui/accounts_editor_list_pane.ui
 | 
			
		||||
+++ b/ui/accounts_editor_list_pane.ui
 | 
			
		||||
@@ -60,6 +60,8 @@
 | 
			
		||||
                         <property name="halign">start</property>
 | 
			
		||||
                         <property name="valign">start</property>
 | 
			
		||||
                         <property name="label" translatable="yes">To get started, select an email provider below.</property>
 | 
			
		||||
+                        <property name="xalign">0</property>
 | 
			
		||||
+                        <property name="wrap">True</property>
 | 
			
		||||
                       </object>
 | 
			
		||||
                       <packing>
 | 
			
		||||
                         <property name="left_attach">1</property>
 | 
			
		||||
@@ -73,6 +75,8 @@
 | 
			
		||||
                         <property name="halign">start</property>
 | 
			
		||||
                         <property name="valign">end</property>
 | 
			
		||||
                         <property name="label" translatable="yes">Welcome to Geary</property>
 | 
			
		||||
+                        <property name="xalign">0</property>
 | 
			
		||||
+                        <property name="wrap">True</property>
 | 
			
		||||
                         <attributes>
 | 
			
		||||
                           <attribute name="weight" value="bold"/>
 | 
			
		||||
                         </attributes>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
From c0a89a86e48667b17dcae934e5f3b15a2475abf3 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Thu, 22 Oct 2020 15:47:09 +0200
 | 
			
		||||
Subject: [PATCH 1/2] conversation-email-row: use is-expanded to add/remove css
 | 
			
		||||
 class
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../conversation-viewer/conversation-list-box.vala   | 12 +++++++++---
 | 
			
		||||
 1 file changed, 9 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-list-box.vala b/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
index 3eb8240b..f860a2df 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
@@ -284,6 +284,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
             }
 | 
			
		||||
             protected set {
 | 
			
		||||
                 this._is_expanded = value;
 | 
			
		||||
+                notify_property("is-expanded");
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
         private bool _is_expanded = false;
 | 
			
		||||
@@ -301,6 +302,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
         protected ConversationRow(Geary.Email? email) {
 | 
			
		||||
             base_ref();
 | 
			
		||||
             this.email = email;
 | 
			
		||||
+            notify["is-expanded"].connect(update_css_class);
 | 
			
		||||
             show();
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +327,13 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
             this.size_allocate.connect(on_size_allocate);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
+        private void update_css_class() {
 | 
			
		||||
+            if (this.is_expanded)
 | 
			
		||||
+                get_style_context().add_class(EXPANDED_CLASS);
 | 
			
		||||
+            else
 | 
			
		||||
+                get_style_context().remove_class(EXPANDED_CLASS);
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
         protected inline void set_style_context_class(string class_name, bool value) {
 | 
			
		||||
             if (value) {
 | 
			
		||||
                 get_style_context().add_class(class_name);
 | 
			
		||||
@@ -392,10 +401,8 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
 
 | 
			
		||||
         private inline void update_row_expansion() {
 | 
			
		||||
             if (this.is_expanded || this.is_pinned) {
 | 
			
		||||
-                get_style_context().add_class(EXPANDED_CLASS);
 | 
			
		||||
                 this.view.expand_email();
 | 
			
		||||
             } else {
 | 
			
		||||
-                get_style_context().remove_class(EXPANDED_CLASS);
 | 
			
		||||
                 this.view.collapse_email();
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
@@ -436,7 +443,6 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
             base(view.referred);
 | 
			
		||||
             this.view = view;
 | 
			
		||||
             this.is_expanded = true;
 | 
			
		||||
-            get_style_context().add_class(EXPANDED_CLASS);
 | 
			
		||||
             add(this.view);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
From 0923de098f2e9ae6a94c5bb82e26b7d80c5181dc Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Fri, 9 Oct 2020 15:55:57 +0200
 | 
			
		||||
Subject: [PATCH 1/6] main-window: remove shadow from folder/conversation list
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 ui/application-main-window.ui | 4 ++--
 | 
			
		||||
 1 file changed, 2 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
 | 
			
		||||
index 547b063f..c55e42ab 100644
 | 
			
		||||
--- a/ui/application-main-window.ui
 | 
			
		||||
+++ b/ui/application-main-window.ui
 | 
			
		||||
@@ -49,7 +49,7 @@
 | 
			
		||||
                             <property name="can_focus">False</property>
 | 
			
		||||
                             <property name="vexpand">True</property>
 | 
			
		||||
                             <property name="label_xalign">0</property>
 | 
			
		||||
-                            <property name="shadow_type">in</property>
 | 
			
		||||
+                            <property name="shadow_type">none</property>
 | 
			
		||||
                             <child>
 | 
			
		||||
                               <object class="GtkScrolledWindow" id="folder_list_scrolled">
 | 
			
		||||
                                 <property name="width_request">100</property>
 | 
			
		||||
@@ -95,7 +95,7 @@
 | 
			
		||||
                             <property name="visible">True</property>
 | 
			
		||||
                             <property name="can_focus">False</property>
 | 
			
		||||
                             <property name="label_xalign">0</property>
 | 
			
		||||
-                            <property name="shadow_type">in</property>
 | 
			
		||||
+                            <property name="shadow_type">none</property>
 | 
			
		||||
                             <child>
 | 
			
		||||
                               <object class="GtkScrolledWindow" id="conversation_list_scrolled">
 | 
			
		||||
                                 <property name="width_request">250</property>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
From a1d31847b115e8ac81520226ff121fabc1f2e2ef Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 5 Sep 2020 14:15:28 +1000
 | 
			
		||||
Subject: [PATCH 002/124] Geary.Db.Result: Log large elapsed query times as a
 | 
			
		||||
 warning
 | 
			
		||||
 | 
			
		||||
Help ensure that long-running queries get some visibility during
 | 
			
		||||
development.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/db/db-result.vala | 19 ++++++++++++++++---
 | 
			
		||||
 1 file changed, 16 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/db/db-result.vala b/src/engine/db/db-result.vala
 | 
			
		||||
index 64c78756..300d3afa 100644
 | 
			
		||||
--- a/src/engine/db/db-result.vala
 | 
			
		||||
+++ b/src/engine/db/db-result.vala
 | 
			
		||||
@@ -38,10 +38,23 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
         check_cancelled("Result.next", cancellable);
 | 
			
		||||
 
 | 
			
		||||
         if (!finished) {
 | 
			
		||||
-            Timer timer = new Timer();
 | 
			
		||||
+            var timer = new GLib.Timer();
 | 
			
		||||
             finished = throw_on_error("Result.next", statement.stmt.step(), statement.sql) != Sqlite.ROW;
 | 
			
		||||
-            if (timer.elapsed() > 1.0)
 | 
			
		||||
-                debug("\n\nDB QUERY STEP \"%s\"\nelapsed=%lf\n\n", statement.sql, timer.elapsed());
 | 
			
		||||
+            var elapsed = timer.elapsed();
 | 
			
		||||
+            var threshold = (get_connection().busy_timeout * 1000.0) / 2.0;
 | 
			
		||||
+            if (threshold > 0 && elapsed > threshold) {
 | 
			
		||||
+                warning(
 | 
			
		||||
+                    "Step for \"%s\" took elapsed time: %lfs (>50%)",
 | 
			
		||||
+                    statement.sql,
 | 
			
		||||
+                    elapsed
 | 
			
		||||
+                );
 | 
			
		||||
+            } else if (elapsed > 1.0) {
 | 
			
		||||
+                debug(
 | 
			
		||||
+                    "Step for \"%s\" took elapsed time: %lfs (>1s)",
 | 
			
		||||
+                    statement.sql,
 | 
			
		||||
+                    elapsed
 | 
			
		||||
+                );
 | 
			
		||||
+            }
 | 
			
		||||
 
 | 
			
		||||
             log_result(finished ? "NO ROW" : "ROW");
 | 
			
		||||
         }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
From c128b1be5f571315ae8a0f34cd9d00fd20c30cdc Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Mon, 27 Apr 2020 10:42:16 +0200
 | 
			
		||||
Subject: [PATCH 2/8] accounts-editor-add-pane: Drop the useless shadow
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 ui/accounts_editor_add_pane.ui | 1 -
 | 
			
		||||
 1 file changed, 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/accounts_editor_add_pane.ui b/ui/accounts_editor_add_pane.ui
 | 
			
		||||
index 0c01a4c1..336b73ea 100644
 | 
			
		||||
--- a/ui/accounts_editor_add_pane.ui
 | 
			
		||||
+++ b/ui/accounts_editor_add_pane.ui
 | 
			
		||||
@@ -89,7 +89,6 @@
 | 
			
		||||
         <property name="vexpand">True</property>
 | 
			
		||||
         <property name="vadjustment">pane_adjustment</property>
 | 
			
		||||
         <property name="hscrollbar_policy">never</property>
 | 
			
		||||
-        <property name="shadow_type">in</property>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkViewport">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,235 @@
 | 
			
		||||
From 51da28b7c0ec32883b923f82b3d85ba4285dc623 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Fri, 23 Oct 2020 13:05:19 +0200
 | 
			
		||||
Subject: [PATCH 2/2] conversation-list-box: remove shadow and make the rows
 | 
			
		||||
 rounded
 | 
			
		||||
 | 
			
		||||
This also makes the expander row look like in HdyExpander row.
 | 
			
		||||
---
 | 
			
		||||
 .../conversation-list-box.vala                | 56 +++++++++++++++++
 | 
			
		||||
 .../conversation-web-view.vala                | 26 ++++++++
 | 
			
		||||
 ui/geary.css                                  | 61 ++++++++++++-------
 | 
			
		||||
 3 files changed, 120 insertions(+), 23 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-list-box.vala b/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
index f860a2df..f94ddea9 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
@@ -332,6 +332,33 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
                 get_style_context().add_class(EXPANDED_CLASS);
 | 
			
		||||
             else
 | 
			
		||||
                 get_style_context().remove_class(EXPANDED_CLASS);
 | 
			
		||||
+
 | 
			
		||||
+            update_previous_sibling_css_class();
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+        // This is mostly taken form libhandy HdyExpanderRow
 | 
			
		||||
+        private Gtk.Widget? get_previous_sibling() {
 | 
			
		||||
+            if (this.parent is Gtk.Container) {
 | 
			
		||||
+                var siblings = this.parent.get_children();
 | 
			
		||||
+                unowned List<weak Gtk.Widget> l;
 | 
			
		||||
+                for (l = siblings; l != null && l.next != null && l.next.data != this; l = l.next);
 | 
			
		||||
+
 | 
			
		||||
+                if (l != null && l.next != null && l.next.data == this) {
 | 
			
		||||
+                    return l.data;
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+
 | 
			
		||||
+            return null;
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+        private void update_previous_sibling_css_class() {
 | 
			
		||||
+            var previous_sibling = get_previous_sibling();
 | 
			
		||||
+            if (previous_sibling != null) {
 | 
			
		||||
+                if (this.is_expanded)
 | 
			
		||||
+                    previous_sibling.get_style_context().add_class("geary-expanded-previous-sibling");
 | 
			
		||||
+                else
 | 
			
		||||
+                    previous_sibling.get_style_context().remove_class("geary-expanded-previous-sibling");
 | 
			
		||||
+            }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         protected inline void set_style_context_class(string class_name, bool value) {
 | 
			
		||||
@@ -675,9 +702,14 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
 
 | 
			
		||||
         this.selection_mode = NONE;
 | 
			
		||||
 
 | 
			
		||||
+        get_style_context().add_class("content");
 | 
			
		||||
         get_style_context().add_class("background");
 | 
			
		||||
         get_style_context().add_class("conversation-listbox");
 | 
			
		||||
 
 | 
			
		||||
+        /* we need to update the previous sibling style class when rows are added or removed */
 | 
			
		||||
+        add.connect(update_previous_sibling_css_class);
 | 
			
		||||
+        remove.connect(update_previous_sibling_css_class);
 | 
			
		||||
+
 | 
			
		||||
         set_adjustment(adjustment);
 | 
			
		||||
         set_sort_func(ConversationListBox.on_sort);
 | 
			
		||||
 
 | 
			
		||||
@@ -703,6 +735,30 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
         base.destroy();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    // For some reason insert doesn't emit the add event
 | 
			
		||||
+    public new void insert(Gtk.Widget child, int position) {
 | 
			
		||||
+      base.insert(child, position);
 | 
			
		||||
+      update_previous_sibling_css_class();
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    // This is mostly taken form libhandy HdyExpanderRow
 | 
			
		||||
+    private void update_previous_sibling_css_class() {
 | 
			
		||||
+        var siblings = this.get_children();
 | 
			
		||||
+        unowned List<weak Gtk.Widget> l;
 | 
			
		||||
+        for (l = siblings; l != null && l.next != null && l.next.data != this; l = l.next) {
 | 
			
		||||
+            if (l != null && l.next != null) {
 | 
			
		||||
+                var row = l.next.data as ConversationRow;
 | 
			
		||||
+                if (row != null) {
 | 
			
		||||
+                    if (row.is_expanded) {
 | 
			
		||||
+                        l.data.get_style_context().add_class("geary-expanded-previous-sibling");
 | 
			
		||||
+                    } else {
 | 
			
		||||
+                        l.data.get_style_context().remove_class("geary-expanded-previous-sibling");
 | 
			
		||||
+                    }
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     public async void load_conversation(Gee.Collection<Geary.EmailIdentifier> scroll_to,
 | 
			
		||||
                                         Geary.SearchQuery? query)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-web-view.vala b/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
index a1ba21a6..ad11415e 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
@@ -197,6 +197,32 @@ public class ConversationWebView : Components.WebView {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+    // Clip round bottom corner
 | 
			
		||||
+    // This is based on 
 | 
			
		||||
+    // https://gitlab.gnome.org/GNOME/gnome-weather/-/commit/9b6336454cc90669d1ee8387bdfc6627e3659e83 
 | 
			
		||||
+    public override bool draw(Cairo.Context cr) {
 | 
			
		||||
+        var frameWidth = this.get_allocated_width();
 | 
			
		||||
+        var frameHeight = this.get_allocated_height();
 | 
			
		||||
+        var borderRadius = 8;
 | 
			
		||||
+
 | 
			
		||||
+        var arc0 = 0.0;
 | 
			
		||||
+        var arc1 = Math.PI * 0.5;
 | 
			
		||||
+        var arc2 = Math.PI;
 | 
			
		||||
+
 | 
			
		||||
+        cr.new_sub_path();
 | 
			
		||||
+        cr.line_to(frameWidth, 0);
 | 
			
		||||
+        cr.arc(frameWidth - borderRadius, frameHeight - borderRadius, borderRadius, arc0, arc1);
 | 
			
		||||
+        cr.arc(borderRadius, frameHeight - borderRadius, borderRadius, arc1, arc2);
 | 
			
		||||
+        cr.line_to(0, 0);
 | 
			
		||||
+        cr.close_path();
 | 
			
		||||
+
 | 
			
		||||
+        cr.clip();
 | 
			
		||||
+        cr.fill();
 | 
			
		||||
+        base.draw(cr);
 | 
			
		||||
+
 | 
			
		||||
+        return Gdk.EVENT_PROPAGATE;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     public override void get_preferred_height(out int minimum_height,
 | 
			
		||||
                                               out int natural_height) {
 | 
			
		||||
         // XXX clamp height to something not too outrageous so we
 | 
			
		||||
diff --git a/ui/geary.css b/ui/geary.css
 | 
			
		||||
index 2d1d48c3..78ade7c0 100644
 | 
			
		||||
--- a/ui/geary.css
 | 
			
		||||
+++ b/ui/geary.css
 | 
			
		||||
@@ -77,39 +77,44 @@ row.geary-folder-popover-list-row > label {
 | 
			
		||||
 /* ConversationListBox */
 | 
			
		||||
 
 | 
			
		||||
 .conversation-listbox {
 | 
			
		||||
-  padding: 0 12px;
 | 
			
		||||
+  padding: 12px;
 | 
			
		||||
 }
 | 
			
		||||
+
 | 
			
		||||
 .conversation-listbox > row {
 | 
			
		||||
-  margin: 0;
 | 
			
		||||
-  border: 1px solid @borders;
 | 
			
		||||
-  border-bottom-width: 0;
 | 
			
		||||
   padding: 0;
 | 
			
		||||
-  box-shadow: 0 4px 8px 1px rgba(0,0,0,0.4);
 | 
			
		||||
-}
 | 
			
		||||
-.conversation-listbox > row > box {
 | 
			
		||||
-  background: @theme_base_color;
 | 
			
		||||
-  transition: background 0.25s;
 | 
			
		||||
-}
 | 
			
		||||
-.conversation-listbox > row:hover > box {
 | 
			
		||||
-  background: shade(@theme_base_color, 0.96);
 | 
			
		||||
-}
 | 
			
		||||
-.conversation-listbox > row.geary-expanded {
 | 
			
		||||
-  margin-bottom: 6px;
 | 
			
		||||
-  border-bottom-width: 1px;
 | 
			
		||||
 }
 | 
			
		||||
+
 | 
			
		||||
 .conversation-listbox *.geary-matched *.geary-match {
 | 
			
		||||
   color: @theme_selected_fg_color;
 | 
			
		||||
   background: @theme_selected_bg_color;
 | 
			
		||||
-;}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 .conversation-listbox > row.geary-loading {
 | 
			
		||||
   border-top-width: 0px;
 | 
			
		||||
   padding: 6px;
 | 
			
		||||
 }
 | 
			
		||||
-.conversation-listbox > row:first-child:not(.geary-loading) {
 | 
			
		||||
-  margin-top: 12px;
 | 
			
		||||
+
 | 
			
		||||
+.conversation-listbox.content > row:last-child,
 | 
			
		||||
+.conversation-listbox.content > row.geary-expanded-previous-sibling,
 | 
			
		||||
+.conversation-listbox.content > row.geary-expanded {
 | 
			
		||||
+  border-width: 1px;
 | 
			
		||||
 }
 | 
			
		||||
-.conversation-listbox > row:last-child {
 | 
			
		||||
-  margin-bottom: 12px;
 | 
			
		||||
+
 | 
			
		||||
+.geary-expanded, .geary-expanded + row {
 | 
			
		||||
+  border-top-left-radius: 8px;
 | 
			
		||||
+  -gtk-outline-top-left-radius: 7px;
 | 
			
		||||
+  border-top-right-radius: 8px;
 | 
			
		||||
+  -gtk-outline-top-right-radius: 7px;
 | 
			
		||||
+  margin-top: 6px;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+.geary-expanded,
 | 
			
		||||
+.geary-expanded-previous-sibling {
 | 
			
		||||
+  border-bottom-left-radius: 8px;
 | 
			
		||||
+  -gtk-outline-bottom-left-radius: 7px;
 | 
			
		||||
+  border-bottom-right-radius: 8px;
 | 
			
		||||
+  -gtk-outline-bottom-right-radius: 7px;
 | 
			
		||||
+  margin-bottom: 6px
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* ConversationEmail */
 | 
			
		||||
@@ -119,6 +124,14 @@ row.geary-folder-popover-list-row > label {
 | 
			
		||||
   transition: border 0.25s;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+.geary-expanded > .geary_email grid.geary-message-summary,
 | 
			
		||||
+.geary-expanded + row > .geary_email grid.geary-message-summary {
 | 
			
		||||
+  border-top-left-radius: 8px;
 | 
			
		||||
+  -gtk-outline-top-left-radius: 7px;
 | 
			
		||||
+  border-top-right-radius: 8px;
 | 
			
		||||
+  -gtk-outline-top-right-radius: 7px;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* ConversationMessage */
 | 
			
		||||
 
 | 
			
		||||
 .geary-message infobar box {
 | 
			
		||||
@@ -198,8 +211,10 @@ grid.geary-message-summary {
 | 
			
		||||
 /* Composer */
 | 
			
		||||
 
 | 
			
		||||
 .geary-composer-embed headerbar {
 | 
			
		||||
-  border-top: 1px solid @borders;
 | 
			
		||||
-  border-radius: 0px;
 | 
			
		||||
+  border-top-left-radius: 8px;
 | 
			
		||||
+  -gtk-outline-top-left-radius: 7px;
 | 
			
		||||
+  border-top-right-radius: 8px;
 | 
			
		||||
+  -gtk-outline-top-right-radius: 7px;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 .geary-attachments-box > box > box {
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,258 @@
 | 
			
		||||
From 40824723c63d869535f89e628289fdb46cbf9c49 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Fri, 9 Oct 2020 17:20:31 +0200
 | 
			
		||||
Subject: [PATCH 2/6] conversation-viewer: move actions to the bottom when they
 | 
			
		||||
 don't fit
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../application/application-main-window.vala  |  8 ++-
 | 
			
		||||
 .../components-conversation-action-bar.vala   | 12 ++--
 | 
			
		||||
 src/client/components/main-toolbar.vala       | 63 +++++++++++++++----
 | 
			
		||||
 .../conversation-viewer.vala                  |  1 -
 | 
			
		||||
 ui/application-main-window.ui                 | 18 ++++++
 | 
			
		||||
 ui/components-conversation-action-bar.ui      | 21 ++++++-
 | 
			
		||||
 6 files changed, 100 insertions(+), 23 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 90d5b249..19f04492 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -334,6 +334,10 @@ public class Application.MainWindow :
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.ScrolledWindow conversation_list_scrolled;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
+    private Gtk.Box conversation_viewer_box;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Components.ConversationActionBar conversation_viewer_action_bar;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
     private Gtk.SizeGroup folder_size_group;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.SizeGroup folder_separator_size_group;
 | 
			
		||||
@@ -1266,7 +1270,7 @@ public class Application.MainWindow :
 | 
			
		||||
 
 | 
			
		||||
         this.conversation_viewer.hexpand = true;
 | 
			
		||||
         this.conversation_size_group.add_widget(this.conversation_viewer);
 | 
			
		||||
-        this.main_leaflet.add_with_properties(this.conversation_viewer, "name", "conversation", null);
 | 
			
		||||
+        this.conversation_viewer_box.add(this.conversation_viewer);
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
         // Setup conversation actions
 | 
			
		||||
@@ -1279,7 +1283,7 @@ public class Application.MainWindow :
 | 
			
		||||
                                                 BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
 | 
			
		||||
 
 | 
			
		||||
         // Main toolbar
 | 
			
		||||
-        this.main_toolbar = new MainToolbar(config);
 | 
			
		||||
+        this.main_toolbar = new MainToolbar(config, conversation_viewer_action_bar);
 | 
			
		||||
         this.main_toolbar.add_to_size_groups(this.folder_size_group,
 | 
			
		||||
                                              this.folder_separator_size_group,
 | 
			
		||||
                                              this.conversations_size_group,
 | 
			
		||||
diff --git a/src/client/components/components-conversation-action-bar.vala b/src/client/components/components-conversation-action-bar.vala
 | 
			
		||||
index cb574521..cd868b21 100644
 | 
			
		||||
--- a/src/client/components/components-conversation-action-bar.vala
 | 
			
		||||
+++ b/src/client/components/components-conversation-action-bar.vala
 | 
			
		||||
@@ -12,7 +12,7 @@ public class Components.ConversationActionBar : Gtk.Revealer {
 | 
			
		||||
     private ulong owner_notify;
 | 
			
		||||
 
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
-    private Gtk.Box action_box;
 | 
			
		||||
+    public Gtk.Box action_box;
 | 
			
		||||
 
 | 
			
		||||
     public ConversationActionBar() {
 | 
			
		||||
     }
 | 
			
		||||
@@ -23,17 +23,17 @@ public class Components.ConversationActionBar : Gtk.Revealer {
 | 
			
		||||
      */
 | 
			
		||||
     public void add_conversation_actions(Components.ConversationActions actions) {
 | 
			
		||||
         if (actions.owner == this)
 | 
			
		||||
-          return;
 | 
			
		||||
+            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);
 | 
			
		||||
-           }
 | 
			
		||||
+            if (actions.owner != this) {
 | 
			
		||||
+                reveal_child = false;
 | 
			
		||||
+                actions.disconnect (this.owner_notify);
 | 
			
		||||
+            }
 | 
			
		||||
         });
 | 
			
		||||
     }
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index 6458b7fb..f216238a 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -17,6 +17,11 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
     // Search bar
 | 
			
		||||
     public bool search_open { get; set; default = false; }
 | 
			
		||||
 
 | 
			
		||||
+    private ulong owner_notify;
 | 
			
		||||
+    private Gtk.Widget? reply_forward_buttons;
 | 
			
		||||
+    private Gtk.Widget? archive_trash_delete_buttons;
 | 
			
		||||
+    private Components.ConversationActionBar conversation_viewer_action_bar;
 | 
			
		||||
+
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Hdy.Leaflet conversations_leaflet;
 | 
			
		||||
 
 | 
			
		||||
@@ -47,11 +52,14 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
 
 | 
			
		||||
     Gtk.SizeGroup conversation_group;
 | 
			
		||||
 
 | 
			
		||||
-    public MainToolbar(Application.Configuration config) {
 | 
			
		||||
+    public MainToolbar(Application.Configuration config,
 | 
			
		||||
+                       Components.ConversationActionBar action_bar) {
 | 
			
		||||
         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;
 | 
			
		||||
+        conversation_header.size_allocate.connect(on_size_allocate);
 | 
			
		||||
 
 | 
			
		||||
         // Assemble the main/mark menus
 | 
			
		||||
         Gtk.Builder builder = new Gtk.Builder.from_resource("/org/gnome/Geary/main-toolbar-menus.ui");
 | 
			
		||||
@@ -63,17 +71,6 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
             BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public void add_conversation_actions(Components.ConversationActions actions) {
 | 
			
		||||
-        if (actions.owner == this)
 | 
			
		||||
-          return;
 | 
			
		||||
-
 | 
			
		||||
-        actions.take_ownership(this);
 | 
			
		||||
-        conversation_header.pack_start(actions.mark_copy_move_buttons);
 | 
			
		||||
-        conversation_header.pack_start(actions.reply_forward_buttons);
 | 
			
		||||
-        conversation_header.pack_end(actions.find_button);
 | 
			
		||||
-        conversation_header.pack_end(actions.archive_trash_delete_buttons);
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     public void set_conversation_header(Gtk.HeaderBar header) {
 | 
			
		||||
         remove(conversation_header);
 | 
			
		||||
         this.header_group.add_gtk_header_bar(header);
 | 
			
		||||
@@ -111,4 +108,46 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
         conversations_group.add_swipeable(this.conversations_leaflet);
 | 
			
		||||
         conversation_group.add_swipeable(this);
 | 
			
		||||
     }
 | 
			
		||||
+
 | 
			
		||||
+    private void on_size_allocate() {
 | 
			
		||||
+        if (reply_forward_buttons != null && archive_trash_delete_buttons != null)
 | 
			
		||||
+            if (conversation_viewer_action_bar.reveal_child && get_allocated_width() > 600) {
 | 
			
		||||
+                conversation_viewer_action_bar.reveal_child = false;
 | 
			
		||||
+                remove_action_parent();
 | 
			
		||||
+                conversation_header.pack_start(reply_forward_buttons);
 | 
			
		||||
+                conversation_header.pack_end(archive_trash_delete_buttons);
 | 
			
		||||
+            } else if (!conversation_viewer_action_bar.reveal_child && get_allocated_width() < 600) {
 | 
			
		||||
+                remove_action_parent();
 | 
			
		||||
+                conversation_viewer_action_bar.action_box.pack_start(reply_forward_buttons, false, false);
 | 
			
		||||
+                conversation_viewer_action_bar.action_box.pack_end(archive_trash_delete_buttons, false, false);
 | 
			
		||||
+                conversation_viewer_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);
 | 
			
		||||
+            conversation_header.pack_start(actions.mark_copy_move_buttons);
 | 
			
		||||
+            conversation_header.pack_end(actions.find_button);
 | 
			
		||||
+
 | 
			
		||||
+            reply_forward_buttons = actions.reply_forward_buttons;
 | 
			
		||||
+            archive_trash_delete_buttons = actions.archive_trash_delete_buttons;
 | 
			
		||||
+            on_size_allocate();
 | 
			
		||||
+            this.owner_notify = actions.notify["owner"].connect(() => {
 | 
			
		||||
+                if (actions.owner != this) {
 | 
			
		||||
+                    conversation_viewer_action_bar.reveal_child = false;
 | 
			
		||||
+                    reply_forward_buttons = null;
 | 
			
		||||
+                    archive_trash_delete_buttons = null;
 | 
			
		||||
+                    actions.disconnect (this.owner_notify);
 | 
			
		||||
+                }
 | 
			
		||||
+            });
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-viewer.vala b/src/client/conversation-viewer/conversation-viewer.vala
 | 
			
		||||
index a5098764..74706f8c 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-viewer.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-viewer.vala
 | 
			
		||||
@@ -532,5 +532,4 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
-
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
 | 
			
		||||
index c55e42ab..1b41310d 100644
 | 
			
		||||
--- a/ui/application-main-window.ui
 | 
			
		||||
+++ b/ui/application-main-window.ui
 | 
			
		||||
@@ -137,6 +137,24 @@
 | 
			
		||||
                     <property name="navigatable">False</property>
 | 
			
		||||
                   </packing>
 | 
			
		||||
                 </child>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkBox" id="conversation_viewer_box">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">False</property>
 | 
			
		||||
+                    <property name="orientation">vertical</property>
 | 
			
		||||
+                    <child>
 | 
			
		||||
+                      <object class="ComponentsConversationActionBar" id="conversation_viewer_action_bar">
 | 
			
		||||
+                        <property name="visible">True</property>
 | 
			
		||||
+                      </object>
 | 
			
		||||
+                      <packing>
 | 
			
		||||
+                        <property name="pack_type">end</property>
 | 
			
		||||
+                      </packing>
 | 
			
		||||
+                    </child>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                  <packing>
 | 
			
		||||
+                    <property name="name">conversation</property>
 | 
			
		||||
+                  </packing>
 | 
			
		||||
+                </child>
 | 
			
		||||
               </object>
 | 
			
		||||
               <packing>
 | 
			
		||||
                 <property name="expand">True</property>
 | 
			
		||||
diff --git a/ui/components-conversation-action-bar.ui b/ui/components-conversation-action-bar.ui
 | 
			
		||||
index ae49683f..6fc03f44 100644
 | 
			
		||||
--- a/ui/components-conversation-action-bar.ui
 | 
			
		||||
+++ b/ui/components-conversation-action-bar.ui
 | 
			
		||||
@@ -11,11 +11,28 @@
 | 
			
		||||
     <property name="can_focus">False</property>
 | 
			
		||||
     <property name="transition_type">slide-up</property>
 | 
			
		||||
     <child>
 | 
			
		||||
-      <object class="GtkBox" id="action_box">
 | 
			
		||||
+      <object class="GtkBox">
 | 
			
		||||
         <property name="visible">True</property>
 | 
			
		||||
         <property name="can_focus">False</property>
 | 
			
		||||
         <property name="hexpand">True</property>
 | 
			
		||||
-        <property name="margin">6</property>
 | 
			
		||||
+        <property name="orientation">vertical</property>
 | 
			
		||||
+        <child>
 | 
			
		||||
+          <object class="GtkSeparator">
 | 
			
		||||
+            <property name="visible">True</property>
 | 
			
		||||
+            <property name="can_focus">False</property>
 | 
			
		||||
+          </object>
 | 
			
		||||
+        </child>
 | 
			
		||||
+        <child>
 | 
			
		||||
+          <object class="GtkBox" id="action_box">
 | 
			
		||||
+            <property name="visible">True</property>
 | 
			
		||||
+            <property name="can_focus">False</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>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,102 @@
 | 
			
		||||
From 485868d570ef95283c541a1a180fca88fec7a9ef Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Tue, 8 Sep 2020 08:34:23 +1000
 | 
			
		||||
Subject: [PATCH 003/124] Geary.Db.DatabaseConnection: Check elapsed time for
 | 
			
		||||
 exec statements
 | 
			
		||||
 | 
			
		||||
Re-work elapsed timer to be usable in other context objects, use it
 | 
			
		||||
for timing exec query execution.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/db/db-context.vala             | 13 +++++++++++++
 | 
			
		||||
 src/engine/db/db-database-connection.vala |  9 ++++++---
 | 
			
		||||
 src/engine/db/db-result.vala              | 23 +++++------------------
 | 
			
		||||
 3 files changed, 24 insertions(+), 21 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/db/db-context.vala b/src/engine/db/db-context.vala
 | 
			
		||||
index a59f6c4c..6713f6c8 100644
 | 
			
		||||
--- a/src/engine/db/db-context.vala
 | 
			
		||||
+++ b/src/engine/db/db-context.vala
 | 
			
		||||
@@ -61,6 +61,19 @@ public abstract class Geary.Db.Context : BaseObject, Logging.Source {
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public abstract Logging.State to_logging_state();
 | 
			
		||||
 
 | 
			
		||||
+
 | 
			
		||||
+    protected inline void check_elapsed(string message,
 | 
			
		||||
+                                        GLib.Timer timer)
 | 
			
		||||
+        throws DatabaseError {
 | 
			
		||||
+        var elapsed = timer.elapsed();
 | 
			
		||||
+        var threshold = (get_connection().busy_timeout * 1000.0) / 2.0;
 | 
			
		||||
+        if (threshold > 0 && elapsed > threshold) {
 | 
			
		||||
+            warning("%s: elapsed time: %lfs (>50%)", message, elapsed);
 | 
			
		||||
+        } else if (elapsed > 1.0) {
 | 
			
		||||
+            debug("%s: elapsed time: %lfs (>1s)", message, elapsed);
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     protected inline int throw_on_error(string? method, int result, string? raw = null) throws DatabaseError {
 | 
			
		||||
         return Db.throw_on_error(this, method, result, raw);
 | 
			
		||||
     }
 | 
			
		||||
diff --git a/src/engine/db/db-database-connection.vala b/src/engine/db/db-database-connection.vala
 | 
			
		||||
index dd311bea..d58911e4 100644
 | 
			
		||||
--- a/src/engine/db/db-database-connection.vala
 | 
			
		||||
+++ b/src/engine/db/db-database-connection.vala
 | 
			
		||||
@@ -137,7 +137,9 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         check_cancelled("Connection.exec", cancellable);
 | 
			
		||||
-        throw_on_error("Connection.exec", db.exec(sql), sql);
 | 
			
		||||
+        var timer = new GLib.Timer();
 | 
			
		||||
+        throw_on_error("Connection.exec_file", this.db.exec(sql), sql);
 | 
			
		||||
+        check_elapsed("Query \"%s\"".printf(sql), timer);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
@@ -147,8 +149,9 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
 
 | 
			
		||||
         string sql;
 | 
			
		||||
         FileUtils.get_contents(file.get_path(), out sql);
 | 
			
		||||
-
 | 
			
		||||
-        exec(sql, cancellable);
 | 
			
		||||
+        var timer = new GLib.Timer();
 | 
			
		||||
+        throw_on_error("Connection.exec_file", this.db.exec(sql), sql);
 | 
			
		||||
+        check_elapsed(file.get_path(), timer);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
diff --git a/src/engine/db/db-result.vala b/src/engine/db/db-result.vala
 | 
			
		||||
index 300d3afa..b5382179 100644
 | 
			
		||||
--- a/src/engine/db/db-result.vala
 | 
			
		||||
+++ b/src/engine/db/db-result.vala
 | 
			
		||||
@@ -39,24 +39,11 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
 
 | 
			
		||||
         if (!finished) {
 | 
			
		||||
             var timer = new GLib.Timer();
 | 
			
		||||
-            finished = throw_on_error("Result.next", statement.stmt.step(), statement.sql) != Sqlite.ROW;
 | 
			
		||||
-            var elapsed = timer.elapsed();
 | 
			
		||||
-            var threshold = (get_connection().busy_timeout * 1000.0) / 2.0;
 | 
			
		||||
-            if (threshold > 0 && elapsed > threshold) {
 | 
			
		||||
-                warning(
 | 
			
		||||
-                    "Step for \"%s\" took elapsed time: %lfs (>50%)",
 | 
			
		||||
-                    statement.sql,
 | 
			
		||||
-                    elapsed
 | 
			
		||||
-                );
 | 
			
		||||
-            } else if (elapsed > 1.0) {
 | 
			
		||||
-                debug(
 | 
			
		||||
-                    "Step for \"%s\" took elapsed time: %lfs (>1s)",
 | 
			
		||||
-                    statement.sql,
 | 
			
		||||
-                    elapsed
 | 
			
		||||
-                );
 | 
			
		||||
-            }
 | 
			
		||||
-
 | 
			
		||||
-            log_result(finished ? "NO ROW" : "ROW");
 | 
			
		||||
+            this.finished = throw_on_error(
 | 
			
		||||
+                "Result.next", statement.stmt.step(), statement.sql
 | 
			
		||||
+            ) != Sqlite.ROW;
 | 
			
		||||
+            check_elapsed("Result.next", timer);
 | 
			
		||||
+            log_result(this.finished ? "NO ROW" : "ROW");
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         return !finished;
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
From bab1759af038ecf08658b3664bf74428f47559e9 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Mon, 27 Apr 2020 10:43:07 +0200
 | 
			
		||||
Subject: [PATCH 3/8] accounts-editor-add-pane: Reduce the minimum entry width
 | 
			
		||||
 | 
			
		||||
This will help the pane fit in narrower widths.
 | 
			
		||||
---
 | 
			
		||||
 src/client/accounts/accounts-editor-add-pane.vala | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/accounts/accounts-editor-add-pane.vala b/src/client/accounts/accounts-editor-add-pane.vala
 | 
			
		||||
index a4a333cd..468e348f 100644
 | 
			
		||||
--- a/src/client/accounts/accounts-editor-add-pane.vala
 | 
			
		||||
+++ b/src/client/accounts/accounts-editor-add-pane.vala
 | 
			
		||||
@@ -526,7 +526,7 @@ private abstract class Accounts.EntryRow : AddPaneRow<Gtk.Entry> {
 | 
			
		||||
 
 | 
			
		||||
         this.value.text = initial_value ?? "";
 | 
			
		||||
         this.value.placeholder_text = placeholder ?? "";
 | 
			
		||||
-        this.value.width_chars = 32;
 | 
			
		||||
+        this.value.width_chars = 16;
 | 
			
		||||
 
 | 
			
		||||
         this.undo = new Components.EntryUndo(this.value);
 | 
			
		||||
     }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
From ee3e56aa1f3a71457b43a79b233ba3200e4e78d2 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Mon, 12 Oct 2020 16:35:22 +0200
 | 
			
		||||
Subject: [PATCH 3/6] conversation-viewer: allow one email per line
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 ui/conversation-message.ui | 6 ------
 | 
			
		||||
 1 file changed, 6 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/conversation-message.ui b/ui/conversation-message.ui
 | 
			
		||||
index 95560939..d68817b2 100644
 | 
			
		||||
--- a/ui/conversation-message.ui
 | 
			
		||||
+++ b/ui/conversation-message.ui
 | 
			
		||||
@@ -157,7 +157,6 @@
 | 
			
		||||
                                 <property name="valign">baseline</property>
 | 
			
		||||
                                 <property name="hexpand">True</property>
 | 
			
		||||
                                 <property name="column_spacing">2</property>
 | 
			
		||||
-                                <property name="min_children_per_line">1</property>
 | 
			
		||||
                                 <property name="max_children_per_line">4</property>
 | 
			
		||||
                                 <property name="selection_mode">none</property>
 | 
			
		||||
                                 <signal name="child-activated" handler="on_address_box_child_activated" swapped="no"/>
 | 
			
		||||
@@ -218,7 +217,6 @@
 | 
			
		||||
                                 <property name="valign">start</property>
 | 
			
		||||
                                 <property name="hexpand">True</property>
 | 
			
		||||
                                 <property name="column_spacing">2</property>
 | 
			
		||||
-                                <property name="min_children_per_line">2</property>
 | 
			
		||||
                                 <property name="max_children_per_line">4</property>
 | 
			
		||||
                                 <property name="selection_mode">none</property>
 | 
			
		||||
                                 <signal name="child-activated" handler="on_address_box_child_activated" swapped="no"/>
 | 
			
		||||
@@ -263,7 +261,6 @@
 | 
			
		||||
                                 <property name="valign">start</property>
 | 
			
		||||
                                 <property name="hexpand">True</property>
 | 
			
		||||
                                 <property name="column_spacing">2</property>
 | 
			
		||||
-                                <property name="min_children_per_line">2</property>
 | 
			
		||||
                                 <property name="max_children_per_line">4</property>
 | 
			
		||||
                                 <property name="selection_mode">none</property>
 | 
			
		||||
                                 <signal name="child-activated" handler="on_address_box_child_activated" swapped="no"/>
 | 
			
		||||
@@ -328,7 +325,6 @@
 | 
			
		||||
                                 <property name="valign">start</property>
 | 
			
		||||
                                 <property name="hexpand">True</property>
 | 
			
		||||
                                 <property name="column_spacing">2</property>
 | 
			
		||||
-                                <property name="min_children_per_line">2</property>
 | 
			
		||||
                                 <property name="max_children_per_line">4</property>
 | 
			
		||||
                                 <property name="selection_mode">none</property>
 | 
			
		||||
                                 <signal name="child-activated" handler="on_address_box_child_activated" swapped="no"/>
 | 
			
		||||
@@ -373,7 +369,6 @@
 | 
			
		||||
                                 <property name="valign">start</property>
 | 
			
		||||
                                 <property name="hexpand">True</property>
 | 
			
		||||
                                 <property name="column_spacing">2</property>
 | 
			
		||||
-                                <property name="min_children_per_line">2</property>
 | 
			
		||||
                                 <property name="max_children_per_line">4</property>
 | 
			
		||||
                                 <property name="selection_mode">none</property>
 | 
			
		||||
                                 <signal name="child-activated" handler="on_address_box_child_activated" swapped="no"/>
 | 
			
		||||
@@ -418,7 +413,6 @@
 | 
			
		||||
                                 <property name="valign">start</property>
 | 
			
		||||
                                 <property name="hexpand">True</property>
 | 
			
		||||
                                 <property name="column_spacing">2</property>
 | 
			
		||||
-                                <property name="min_children_per_line">2</property>
 | 
			
		||||
                                 <property name="max_children_per_line">4</property>
 | 
			
		||||
                                 <property name="selection_mode">none</property>
 | 
			
		||||
                                 <signal name="child-activated" handler="on_address_box_child_activated" swapped="no"/>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
From 0fa0d0ea4d8db54166c131dee7b509d3984c2e2f Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 9 Sep 2020 18:30:22 +1000
 | 
			
		||||
Subject: [PATCH 004/124] Geary.Db.Statement: Minor code cleanup
 | 
			
		||||
 | 
			
		||||
Make `sql` a proper auto property. Remove expanded sql workaround.
 | 
			
		||||
Minor code style cleanup.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/db/db-statement.vala | 17 ++++++-----------
 | 
			
		||||
 1 file changed, 6 insertions(+), 11 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/db/db-statement.vala b/src/engine/db/db-statement.vala
 | 
			
		||||
index 088b882b..4d792b42 100644
 | 
			
		||||
--- a/src/engine/db/db-statement.vala
 | 
			
		||||
+++ b/src/engine/db/db-statement.vala
 | 
			
		||||
@@ -9,15 +9,16 @@ private extern string? sqlite3_expanded_sql(Sqlite.Statement stmt);
 | 
			
		||||
 
 | 
			
		||||
 public class Geary.Db.Statement : Context {
 | 
			
		||||
 
 | 
			
		||||
-    public string sql {
 | 
			
		||||
-        get { return this.stmt.sql(); }
 | 
			
		||||
-    }
 | 
			
		||||
+
 | 
			
		||||
+    public string sql { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
     internal DatabaseConnection connection { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
     internal Sqlite.Statement stmt;
 | 
			
		||||
 
 | 
			
		||||
     private Gee.HashMap<string, int>? column_map = null;
 | 
			
		||||
+    private Gee.HashSet<Memory.Buffer> held_buffers = new Gee.HashSet<Memory.Buffer>();
 | 
			
		||||
+
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Fired when the Statement is executed the first time (after creation or after a reset).
 | 
			
		||||
@@ -34,11 +35,11 @@ public class Geary.Db.Statement : Context {
 | 
			
		||||
      */
 | 
			
		||||
     public signal void bindings_cleared();
 | 
			
		||||
 
 | 
			
		||||
-    private Gee.HashSet<Memory.Buffer> held_buffers = new Gee.HashSet<Memory.Buffer>();
 | 
			
		||||
 
 | 
			
		||||
     internal Statement(DatabaseConnection connection, string sql)
 | 
			
		||||
         throws DatabaseError {
 | 
			
		||||
         this.connection = connection;
 | 
			
		||||
+        this.sql = sql;
 | 
			
		||||
         throw_on_error(
 | 
			
		||||
             "Statement.ctor",
 | 
			
		||||
             connection.db.prepare_v2(sql, -1, out stmt, null),
 | 
			
		||||
@@ -48,13 +49,7 @@ public class Geary.Db.Statement : Context {
 | 
			
		||||
 
 | 
			
		||||
     /** Returns SQL for the statement with bound parameters expanded. */
 | 
			
		||||
     public string? get_expanded_sql() {
 | 
			
		||||
-        // Replace all this with `Sqlite.Statement.expanded_sql` is
 | 
			
		||||
-        // readily available. See:
 | 
			
		||||
-        // https://gitlab.gnome.org/GNOME/vala/merge_requests/74
 | 
			
		||||
-        string* sqlite = sqlite3_expanded_sql(this.stmt);
 | 
			
		||||
-        string? sql = sqlite;
 | 
			
		||||
-        Sqlite.Memory.free((void*) sqlite);
 | 
			
		||||
-        return sql;
 | 
			
		||||
+        return this.stmt.expanded_sql();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
From 84c94463cd806ac5dbb1692ef3c04107b5a5f12f Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Mon, 27 Apr 2020 10:43:45 +0200
 | 
			
		||||
Subject: [PATCH 4/8] accounts-editor-eit-pane: Ellipsize the account row label
 | 
			
		||||
 | 
			
		||||
This will help the pane fit in narrower widths.
 | 
			
		||||
---
 | 
			
		||||
 src/client/accounts/accounts-editor-edit-pane.vala | 4 +++-
 | 
			
		||||
 1 file changed, 3 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/accounts/accounts-editor-edit-pane.vala b/src/client/accounts/accounts-editor-edit-pane.vala
 | 
			
		||||
index 2722db6e..5b944333 100644
 | 
			
		||||
--- a/src/client/accounts/accounts-editor-edit-pane.vala
 | 
			
		||||
+++ b/src/client/accounts/accounts-editor-edit-pane.vala
 | 
			
		||||
@@ -376,7 +376,9 @@ private class Accounts.MailboxRow : AccountRow<EditorEditPane,Gtk.Label> {
 | 
			
		||||
 
 | 
			
		||||
     public MailboxRow(Geary.AccountInformation account,
 | 
			
		||||
                       Geary.RFC822.MailboxAddress mailbox) {
 | 
			
		||||
-        base(account, "", new Gtk.Label(""));
 | 
			
		||||
+        var label = new Gtk.Label("");
 | 
			
		||||
+        label.ellipsize = Pango.EllipsizeMode.END;
 | 
			
		||||
+        base(account, "", label);
 | 
			
		||||
         this.mailbox = mailbox;
 | 
			
		||||
         enable_drag();
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,558 @@
 | 
			
		||||
From 7d164ce964aa4118d019a741f9abf821f1897985 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Tue, 13 Oct 2020 15:46:39 +0200
 | 
			
		||||
Subject: [PATCH 4/6] compnents-info-bar: use custom infobar so that the
 | 
			
		||||
 buttons reflow
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/POTFILES.in                                |   1 +
 | 
			
		||||
 .../application/application-main-window.vala  |   2 +-
 | 
			
		||||
 .../components/components-info-bar-stack.vala |  34 ++--
 | 
			
		||||
 .../components/components-info-bar.vala       | 153 ++++++++++++++++--
 | 
			
		||||
 .../conversation-list-box.vala                |   4 +-
 | 
			
		||||
 .../conversation-message.vala                 |   4 +-
 | 
			
		||||
 ui/components-info-bar.ui                     |  83 ++++++++++
 | 
			
		||||
 ui/geary.css                                  |   4 +
 | 
			
		||||
 ui/org.gnome.Geary.gresource.xml              |   1 +
 | 
			
		||||
 9 files changed, 248 insertions(+), 38 deletions(-)
 | 
			
		||||
 create mode 100644 ui/components-info-bar.ui
 | 
			
		||||
 | 
			
		||||
diff --git a/po/POTFILES.in b/po/POTFILES.in
 | 
			
		||||
index cd8b339d..6ab344dc 100644
 | 
			
		||||
--- a/po/POTFILES.in
 | 
			
		||||
+++ b/po/POTFILES.in
 | 
			
		||||
@@ -460,6 +460,7 @@ ui/components-attachment-view.ui
 | 
			
		||||
 ui/components-conversation-actions.ui
 | 
			
		||||
 ui/components-conversation-action-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
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 19f04492..27526e0e 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -889,7 +889,7 @@ public class Application.MainWindow :
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** Displays an infobar in the window. */
 | 
			
		||||
-    public void show_info_bar(Gtk.InfoBar info_bar) {
 | 
			
		||||
+    public void show_info_bar(Components.InfoBar info_bar) {
 | 
			
		||||
         if (!this.info_bars.has_current) {
 | 
			
		||||
             this.info_bars.add(info_bar);
 | 
			
		||||
         }
 | 
			
		||||
diff --git a/src/client/components/components-info-bar-stack.vala b/src/client/components/components-info-bar-stack.vala
 | 
			
		||||
index cbe63e05..83339210 100644
 | 
			
		||||
--- a/src/client/components/components-info-bar-stack.vala
 | 
			
		||||
+++ b/src/client/components/components-info-bar-stack.vala
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
- * A stack-like widget for displaying Gtk InfoBar widgets.
 | 
			
		||||
+ * A stack-like widget for displaying Components.InfoBar widgets.
 | 
			
		||||
  *
 | 
			
		||||
  * The stack ensures only one info bar is shown at once, shows a frame
 | 
			
		||||
  * around the info bar, and manages revealing and hiding itself and
 | 
			
		||||
@@ -40,7 +40,7 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-    private class SingletonQueue : Gee.AbstractQueue<Gtk.InfoBar> {
 | 
			
		||||
+    private class SingletonQueue : Gee.AbstractQueue<Components.InfoBar> {
 | 
			
		||||
 
 | 
			
		||||
         public override bool read_only {
 | 
			
		||||
             get { return false; }
 | 
			
		||||
@@ -62,10 +62,10 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
             get { return (this.element != null) ? 0 : 1; }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        private Gtk.InfoBar? element = null;
 | 
			
		||||
+        private Components.InfoBar? element = null;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-        public override bool add(Gtk.InfoBar to_add) {
 | 
			
		||||
+        public override bool add(Components.InfoBar to_add) {
 | 
			
		||||
             var added = false;
 | 
			
		||||
             if (this.element != to_add) {
 | 
			
		||||
                 this.element = to_add;
 | 
			
		||||
@@ -78,20 +78,20 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
             this.element = null;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        public override bool contains(Gtk.InfoBar other) {
 | 
			
		||||
+        public override bool contains(Components.InfoBar other) {
 | 
			
		||||
             return (this.element == other);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        public override Gee.Iterator<Gtk.InfoBar> iterator() {
 | 
			
		||||
+        public override Gee.Iterator<Components.InfoBar> iterator() {
 | 
			
		||||
             // This sucks but it won't ever be used so oh well
 | 
			
		||||
             return (
 | 
			
		||||
                 this.element == null
 | 
			
		||||
-                ? Gee.Collection.empty<Gtk.InfoBar>().iterator()
 | 
			
		||||
+                ? Gee.Collection.empty<Components.InfoBar>().iterator()
 | 
			
		||||
                 : Geary.Collection.single(this.element).iterator()
 | 
			
		||||
             );
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        public override bool remove(Gtk.InfoBar to_remove) {
 | 
			
		||||
+        public override bool remove(Components.InfoBar to_remove) {
 | 
			
		||||
             var removed = false;
 | 
			
		||||
             if (this.element == to_remove) {
 | 
			
		||||
                 this.element = null;
 | 
			
		||||
@@ -100,11 +100,11 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
             return removed;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        public override Gtk.InfoBar peek() {
 | 
			
		||||
+        public override Components.InfoBar peek() {
 | 
			
		||||
             return this.element;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        public override Gtk.InfoBar poll() {
 | 
			
		||||
+        public override Components.InfoBar poll() {
 | 
			
		||||
             var element = this.element;
 | 
			
		||||
             this.element = null;
 | 
			
		||||
             return element;
 | 
			
		||||
@@ -126,7 +126,7 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
      * @see algorithm
 | 
			
		||||
      * @see StackType.PRIORITY_QUEUE
 | 
			
		||||
      */
 | 
			
		||||
-    public static int priority_queue_comparator(Gtk.InfoBar a, Gtk.InfoBar b) {
 | 
			
		||||
+    public static int priority_queue_comparator(Components.InfoBar a, Components.InfoBar b) {
 | 
			
		||||
         return (
 | 
			
		||||
             b.get_data<int>(PRIORITY_QUEUE_KEY) -
 | 
			
		||||
             a.get_data<int>(PRIORITY_QUEUE_KEY)
 | 
			
		||||
@@ -150,11 +150,11 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** Returns the currently displayed info bar, if any. */
 | 
			
		||||
-    public Gtk.InfoBar? current_info_bar {
 | 
			
		||||
-        get { return get_child() as Gtk.InfoBar; }
 | 
			
		||||
+    public Components.InfoBar? current_info_bar {
 | 
			
		||||
+        get { return get_child() as Components.InfoBar; }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private Gee.Queue<Gtk.InfoBar> available;
 | 
			
		||||
+    private Gee.Queue<Components.InfoBar> available;
 | 
			
		||||
     private int last_allocated_height = 0;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
@@ -175,7 +175,7 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
      * stack constructed, the info bar may or may not be revealed
 | 
			
		||||
      * immediately.
 | 
			
		||||
      */
 | 
			
		||||
-    public new void add(Gtk.InfoBar to_add) {
 | 
			
		||||
+    public new void add(Components.InfoBar to_add) {
 | 
			
		||||
         if (this.available.offer(to_add)) {
 | 
			
		||||
             update();
 | 
			
		||||
         }
 | 
			
		||||
@@ -188,7 +188,7 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
      * replaced with the next info bar added. If the only info bar
 | 
			
		||||
      * present is removed, the stack also hides itself.
 | 
			
		||||
      */
 | 
			
		||||
-    public new void remove(Gtk.InfoBar to_remove) {
 | 
			
		||||
+    public new void remove(Components.InfoBar to_remove) {
 | 
			
		||||
         if (this.available.remove(to_remove)) {
 | 
			
		||||
             update();
 | 
			
		||||
         }
 | 
			
		||||
@@ -234,7 +234,7 @@ public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
 | 
			
		||||
             this.available = new SingletonQueue();
 | 
			
		||||
             break;
 | 
			
		||||
         case PRIORITY_QUEUE:
 | 
			
		||||
-            this.available = new Gee.PriorityQueue<Gtk.InfoBar>(
 | 
			
		||||
+            this.available = new Gee.PriorityQueue<Components.InfoBar>(
 | 
			
		||||
                 InfoBarStack.priority_queue_comparator
 | 
			
		||||
             );
 | 
			
		||||
             break;
 | 
			
		||||
diff --git a/src/client/components/components-info-bar.vala b/src/client/components/components-info-bar.vala
 | 
			
		||||
index 05124c00..4ab6b56d 100644
 | 
			
		||||
--- a/src/client/components/components-info-bar.vala
 | 
			
		||||
+++ b/src/client/components/components-info-bar.vala
 | 
			
		||||
@@ -8,9 +8,11 @@
 | 
			
		||||
 /**
 | 
			
		||||
  * A standard info bar widget with status message and description.
 | 
			
		||||
  */
 | 
			
		||||
-public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
+[GtkTemplate (ui = "/org/gnome/Geary/components-info-bar.ui")]
 | 
			
		||||
+public class Components.InfoBar : Gtk.Box {
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+    public signal void response(int response_id);
 | 
			
		||||
     /**
 | 
			
		||||
      * A short, human-readable status message.
 | 
			
		||||
      *
 | 
			
		||||
@@ -26,11 +28,38 @@ public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
      */
 | 
			
		||||
     public Gtk.Label? description { get; private set; default = null; }
 | 
			
		||||
 
 | 
			
		||||
+    public bool show_close_button { get; set; default = false;}
 | 
			
		||||
+    public bool revealed { get; set; }
 | 
			
		||||
+    private Gtk.MessageType _message_type;
 | 
			
		||||
+    public Gtk.MessageType message_type {
 | 
			
		||||
+        get {
 | 
			
		||||
+            return _message_type;
 | 
			
		||||
+        }
 | 
			
		||||
+        set {
 | 
			
		||||
+            _set_message_type(value);
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
 
 | 
			
		||||
     private Plugin.InfoBar? plugin = null;
 | 
			
		||||
     private string? plugin_action_group_name = null;
 | 
			
		||||
     private Gtk.Button? plugin_primary_button = null;
 | 
			
		||||
 
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.Revealer revealer;
 | 
			
		||||
+
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.Box action_area;
 | 
			
		||||
+
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.Box content_area;
 | 
			
		||||
+
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.Button close_button;
 | 
			
		||||
+
 | 
			
		||||
+    static construct {
 | 
			
		||||
+        set_css_name("infobar");
 | 
			
		||||
+    }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Constructs a new info bar.
 | 
			
		||||
@@ -43,6 +72,20 @@ public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
     public InfoBar(string status, string? description = null) {
 | 
			
		||||
         this.status = new Gtk.Label(status);
 | 
			
		||||
         this.status.halign = START;
 | 
			
		||||
+        this.status.xalign = 0;
 | 
			
		||||
+
 | 
			
		||||
+        _message_type = Gtk.MessageType.OTHER;
 | 
			
		||||
+        _set_message_type(Gtk.MessageType.INFO);
 | 
			
		||||
+
 | 
			
		||||
+        this.bind_property("revealed",
 | 
			
		||||
+                           this.revealer,
 | 
			
		||||
+                           "reveal-child",
 | 
			
		||||
+                           BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
 | 
			
		||||
+
 | 
			
		||||
+        this.bind_property("show-close-button",
 | 
			
		||||
+                           this.close_button,
 | 
			
		||||
+                           "visible",
 | 
			
		||||
+                           BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
 | 
			
		||||
 
 | 
			
		||||
         var attrs = new Pango.AttrList();
 | 
			
		||||
         attrs.change(Pango.attr_weight_new(BOLD));
 | 
			
		||||
@@ -57,11 +100,8 @@ public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
             this.description = new Gtk.Label(description);
 | 
			
		||||
             this.description.halign = START;
 | 
			
		||||
             this.description.valign = START;
 | 
			
		||||
-
 | 
			
		||||
-            // Set the description to be ellipsised and set and the
 | 
			
		||||
-            // tool-tip to be the same, in case it is too long for the
 | 
			
		||||
-            // info bar's width
 | 
			
		||||
-            this.description.ellipsize = END;
 | 
			
		||||
+            this.description.xalign = 0;
 | 
			
		||||
+            this.description.wrap = true;
 | 
			
		||||
             this.description.tooltip_text = description;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
@@ -85,15 +125,28 @@ public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
         this.plugin_action_group_name = action_group_name;
 | 
			
		||||
         this.show_close_button = plugin.show_close_button;
 | 
			
		||||
 
 | 
			
		||||
+        _message_type = Gtk.MessageType.OTHER;
 | 
			
		||||
+        _set_message_type(Gtk.MessageType.INFO);
 | 
			
		||||
+
 | 
			
		||||
+        this.bind_property("revealed",
 | 
			
		||||
+                           this.revealer,
 | 
			
		||||
+                           "reveal-child",
 | 
			
		||||
+                           BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
 | 
			
		||||
+
 | 
			
		||||
+        this.bind_property("show-close-button",
 | 
			
		||||
+                           this.close_button,
 | 
			
		||||
+                           "visible",
 | 
			
		||||
+                           BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
 | 
			
		||||
+
 | 
			
		||||
         plugin.notify["status"].connect(
 | 
			
		||||
             () => { this.status.label = plugin.status; }
 | 
			
		||||
-        );
 | 
			
		||||
+            );
 | 
			
		||||
         plugin.notify["description"].connect(
 | 
			
		||||
             () => { this.description.label = plugin.description; }
 | 
			
		||||
-        );
 | 
			
		||||
+            );
 | 
			
		||||
         plugin.notify["primary-button"].connect(
 | 
			
		||||
             () => { this.update_plugin_primary_button(); }
 | 
			
		||||
-        );
 | 
			
		||||
+            );
 | 
			
		||||
 
 | 
			
		||||
         var secondaries = plugin.secondary_buttons.bidir_list_iterator();
 | 
			
		||||
         bool has_prev = secondaries.last();
 | 
			
		||||
@@ -108,11 +161,12 @@ public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
         show_all();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    /* {@inheritDoc} */
 | 
			
		||||
-    public override void response(int response) {
 | 
			
		||||
-        if (response == Gtk.ResponseType.CLOSE && this.plugin != null) {
 | 
			
		||||
+    [GtkCallback]
 | 
			
		||||
+    public void on_close_button_clicked() {
 | 
			
		||||
+        if (this.plugin != null) {
 | 
			
		||||
             this.plugin.close_activated();
 | 
			
		||||
         }
 | 
			
		||||
+        response(Gtk.ResponseType.CLOSE);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /* {@inheritDoc} */
 | 
			
		||||
@@ -120,10 +174,22 @@ public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
         this.plugin = null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    // GTK 3.24.16 fixed the binding for this, but that and the VAPI
 | 
			
		||||
-    // change has yet to trickle down to common distros like F31
 | 
			
		||||
-    public new Gtk.Box get_action_area() {
 | 
			
		||||
-        return (Gtk.Box) base.get_action_area();
 | 
			
		||||
+    public Gtk.Box get_action_area() {
 | 
			
		||||
+        return this.action_area;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    public Gtk.Box get_content_area() {
 | 
			
		||||
+        return this.content_area;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    public Gtk.Button add_button(string button_text, int response_id) {
 | 
			
		||||
+        var button = new Gtk.Button.with_mnemonic(button_text);
 | 
			
		||||
+        button.clicked.connect(() => {
 | 
			
		||||
+            response(response_id);
 | 
			
		||||
+        });
 | 
			
		||||
+        get_action_area().add(button);
 | 
			
		||||
+        button.visible = true;
 | 
			
		||||
+        return button;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void update_plugin_primary_button() {
 | 
			
		||||
@@ -162,4 +228,59 @@ public class Components.InfoBar : Gtk.InfoBar {
 | 
			
		||||
         return button;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private void _set_message_type(Gtk.MessageType message_type) {
 | 
			
		||||
+        if (this._message_type != message_type) {
 | 
			
		||||
+            Gtk.StyleContext context = this.get_style_context();
 | 
			
		||||
+            const string[] type_class = {
 | 
			
		||||
+                Gtk.STYLE_CLASS_INFO,
 | 
			
		||||
+                Gtk.STYLE_CLASS_WARNING,
 | 
			
		||||
+                Gtk.STYLE_CLASS_QUESTION,
 | 
			
		||||
+                Gtk.STYLE_CLASS_ERROR,
 | 
			
		||||
+                null
 | 
			
		||||
+            };
 | 
			
		||||
+
 | 
			
		||||
+            if (type_class[this._message_type] != null)
 | 
			
		||||
+                context.remove_class(type_class[this._message_type]);
 | 
			
		||||
+
 | 
			
		||||
+            this._message_type = message_type;
 | 
			
		||||
+
 | 
			
		||||
+            var atk_obj = this.get_accessible();
 | 
			
		||||
+            if (atk_obj is Atk.Object) {
 | 
			
		||||
+                string name = null;
 | 
			
		||||
+
 | 
			
		||||
+                atk_obj.set_role(Atk.Role.INFO_BAR);
 | 
			
		||||
+
 | 
			
		||||
+                switch (message_type) {
 | 
			
		||||
+                    case Gtk.MessageType.INFO:
 | 
			
		||||
+                        name = _("Information");
 | 
			
		||||
+                        break;
 | 
			
		||||
+
 | 
			
		||||
+                    case Gtk.MessageType.QUESTION:
 | 
			
		||||
+                        name = _("Question");
 | 
			
		||||
+                        break;
 | 
			
		||||
+
 | 
			
		||||
+                    case Gtk.MessageType.WARNING:
 | 
			
		||||
+                        name = _("Warning");
 | 
			
		||||
+                        break;
 | 
			
		||||
+
 | 
			
		||||
+                    case Gtk.MessageType.ERROR:
 | 
			
		||||
+                        name = _("Error");
 | 
			
		||||
+                        break;
 | 
			
		||||
+
 | 
			
		||||
+                    case Gtk.MessageType.OTHER:
 | 
			
		||||
+                        break;
 | 
			
		||||
+
 | 
			
		||||
+                    default:
 | 
			
		||||
+                        warning("Unknown GtkMessageType %u", message_type);
 | 
			
		||||
+                        break;
 | 
			
		||||
+                }
 | 
			
		||||
+
 | 
			
		||||
+                if (name != null)
 | 
			
		||||
+                    atk_obj.set_name(name);
 | 
			
		||||
+            }
 | 
			
		||||
+
 | 
			
		||||
+            if (type_class[this._message_type] != null)
 | 
			
		||||
+                context.add_class(type_class[this._message_type]);
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-list-box.vala b/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
index 3eb8240b..7d0c94af 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-list-box.vala
 | 
			
		||||
@@ -936,7 +936,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
 
 | 
			
		||||
     /** Adds an info bar to the given email, if any. */
 | 
			
		||||
     public void add_email_info_bar(Geary.EmailIdentifier id,
 | 
			
		||||
-                                   Gtk.InfoBar info_bar) {
 | 
			
		||||
+                                   Components.InfoBar info_bar) {
 | 
			
		||||
         var row = this.email_rows.get(id);
 | 
			
		||||
         if (row != null) {
 | 
			
		||||
             row.view.primary_message.info_bars.add(info_bar);
 | 
			
		||||
@@ -945,7 +945,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 | 
			
		||||
 
 | 
			
		||||
     /** Adds an info bar to the given email, if any. */
 | 
			
		||||
     public void remove_email_info_bar(Geary.EmailIdentifier id,
 | 
			
		||||
-                                      Gtk.InfoBar info_bar) {
 | 
			
		||||
+                                      Components.InfoBar info_bar) {
 | 
			
		||||
         var row = this.email_rows.get(id);
 | 
			
		||||
         if (row != null) {
 | 
			
		||||
             row.view.primary_message.info_bars.remove(info_bar);
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-message.vala b/src/client/conversation-viewer/conversation-message.vala
 | 
			
		||||
index 109c4a1c..868fea7e 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-message.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-message.vala
 | 
			
		||||
@@ -380,7 +380,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.ProgressBar body_progress;
 | 
			
		||||
 
 | 
			
		||||
-    private Gtk.InfoBar? remote_images_info_bar = null;
 | 
			
		||||
+    private Components.InfoBar? remote_images_info_bar = null;
 | 
			
		||||
 
 | 
			
		||||
     private Gtk.Widget? body_placeholder = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -1460,7 +1460,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_remote_images_response(Gtk.InfoBar info_bar, int response_id) {
 | 
			
		||||
+    private void on_remote_images_response(Components.InfoBar info_bar, int response_id) {
 | 
			
		||||
         switch (response_id) {
 | 
			
		||||
         case 1:
 | 
			
		||||
             // Show images for the message
 | 
			
		||||
diff --git a/ui/components-info-bar.ui b/ui/components-info-bar.ui
 | 
			
		||||
new file mode 100644
 | 
			
		||||
index 00000000..11dcfe37
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/ui/components-info-bar.ui
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
+<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
+<interface>
 | 
			
		||||
+  <requires lib="gtk+" version="3.20"/>
 | 
			
		||||
+  <template class="ComponentsInfoBar" parent="GtkBox">
 | 
			
		||||
+    <property name="visible">True</property>
 | 
			
		||||
+    <property name="can_focus">False</property>
 | 
			
		||||
+    <child>
 | 
			
		||||
+      <object class="GtkRevealer" id="revealer">
 | 
			
		||||
+        <property name="visible">True</property>
 | 
			
		||||
+        <property name="can_focus">False</property>
 | 
			
		||||
+        <property name="transition_type">slide-down</property>
 | 
			
		||||
+        <child>
 | 
			
		||||
+          <object class="GtkBox">
 | 
			
		||||
+            <property name="visible">True</property>
 | 
			
		||||
+            <property name="can_focus">False</property>
 | 
			
		||||
+            <child>
 | 
			
		||||
+              <object class="GtkFlowBox">
 | 
			
		||||
+                <property name="visible">True</property>
 | 
			
		||||
+                <property name="can_focus">False</property>
 | 
			
		||||
+                <property name="hexpand">True</property>
 | 
			
		||||
+                <property name="selection-mode">none</property>
 | 
			
		||||
+                <property name="max_children_per_line">2</property>
 | 
			
		||||
+                <property name="border-width">12</property>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkFlowBoxChild">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">True</property>
 | 
			
		||||
+                    <child>
 | 
			
		||||
+                      <object class="GtkBox" id="content_area">
 | 
			
		||||
+                        <property name="visible">True</property>
 | 
			
		||||
+                        <property name="can_focus">False</property>
 | 
			
		||||
+                        <property name="spacing">16</property>
 | 
			
		||||
+                      </object>
 | 
			
		||||
+                    </child>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkFlowBoxChild">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">True</property>
 | 
			
		||||
+                    <child>
 | 
			
		||||
+                      <object class="GtkButtonBox" id="action_area">
 | 
			
		||||
+                        <property name="visible">True</property>
 | 
			
		||||
+                        <property name="can_focus">False</property>
 | 
			
		||||
+                        <property name="layout_style">end</property>
 | 
			
		||||
+                        <property name="spacing">6</property>
 | 
			
		||||
+                      </object>
 | 
			
		||||
+                    </child>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
+              </object>
 | 
			
		||||
+            </child>
 | 
			
		||||
+            <child>
 | 
			
		||||
+              <object class="GtkButton" id="close_button">
 | 
			
		||||
+                <property name="can_focus">True</property>
 | 
			
		||||
+                <property name="receives_default">True</property>
 | 
			
		||||
+                <property name="halign">end</property>
 | 
			
		||||
+                <property name="valign">center</property>
 | 
			
		||||
+                <property name="margin">6</property>
 | 
			
		||||
+                <property name="no_show_all">True</property>
 | 
			
		||||
+                <signal name="clicked" handler="on_close_button_clicked" swapped="no"/>
 | 
			
		||||
+                <style>
 | 
			
		||||
+                  <class name="titlebutton"/>
 | 
			
		||||
+                  <class name="close"/>
 | 
			
		||||
+                </style>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkImage">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">False</property>
 | 
			
		||||
+                    <property name="icon_name">window-close-symbolic</property>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
+              </object>
 | 
			
		||||
+              <packing>
 | 
			
		||||
+                <property name="pack_type">end</property>
 | 
			
		||||
+              </packing>
 | 
			
		||||
+            </child>
 | 
			
		||||
+          </object>
 | 
			
		||||
+        </child>
 | 
			
		||||
+      </object>
 | 
			
		||||
+    </child>
 | 
			
		||||
+  </template>
 | 
			
		||||
+</interface>
 | 
			
		||||
diff --git a/ui/geary.css b/ui/geary.css
 | 
			
		||||
index 2d1d48c3..e38d135a 100644
 | 
			
		||||
--- a/ui/geary.css
 | 
			
		||||
+++ b/ui/geary.css
 | 
			
		||||
@@ -62,6 +62,10 @@ geary-conversation-viewer {
 | 
			
		||||
   border-right-width: 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+infobar flowboxchild {
 | 
			
		||||
+	padding: 0px;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* FolderPopover */
 | 
			
		||||
 
 | 
			
		||||
 row.geary-folder-popover-list-row {
 | 
			
		||||
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
index 0b9e900f..fbd7899d 100644
 | 
			
		||||
--- a/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
+++ b/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
     <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>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">components-inspector.ui</file>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">components-inspector-error-view.ui</file>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">components-inspector-log-view.ui</file>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,150 @@
 | 
			
		||||
From 940ca83195ba1f145a70b9dd0246f4d5aa2a069d Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 9 Sep 2020 18:33:44 +1000
 | 
			
		||||
Subject: [PATCH 005/124] Geary.Db.Context: Remove separate `logging_parent`
 | 
			
		||||
 property
 | 
			
		||||
 | 
			
		||||
Since each context type already has access to the object that is its
 | 
			
		||||
context parent, don't bother with a stand-alone `logging_parent`
 | 
			
		||||
property, just have context types implement it and return the
 | 
			
		||||
appropriate object.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/db/db-context.vala             |  8 +-------
 | 
			
		||||
 src/engine/db/db-database-connection.vala |  6 +++++-
 | 
			
		||||
 src/engine/db/db-database.vala            | 10 ++++++++--
 | 
			
		||||
 src/engine/db/db-result.vala              |  6 ++++--
 | 
			
		||||
 src/engine/db/db-statement.vala           |  5 +++++
 | 
			
		||||
 5 files changed, 23 insertions(+), 12 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/db/db-context.vala b/src/engine/db/db-context.vala
 | 
			
		||||
index 6713f6c8..2ba8b305 100644
 | 
			
		||||
--- a/src/engine/db/db-context.vala
 | 
			
		||||
+++ b/src/engine/db/db-context.vala
 | 
			
		||||
@@ -33,8 +33,7 @@ public abstract class Geary.Db.Context : BaseObject, Logging.Source {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
-    public Logging.Source? logging_parent { get { return _logging_parent; } }
 | 
			
		||||
-    private weak Logging.Source? _logging_parent = null;
 | 
			
		||||
+    public abstract Logging.Source? logging_parent { get; }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     internal virtual Database? get_database() {
 | 
			
		||||
@@ -53,11 +52,6 @@ public abstract class Geary.Db.Context : BaseObject, Logging.Source {
 | 
			
		||||
         return null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    public void set_logging_parent(Logging.Source parent) {
 | 
			
		||||
-        this._logging_parent = parent;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public abstract Logging.State to_logging_state();
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/engine/db/db-database-connection.vala b/src/engine/db/db-database-connection.vala
 | 
			
		||||
index d58911e4..54d36160 100644
 | 
			
		||||
--- a/src/engine/db/db-database-connection.vala
 | 
			
		||||
+++ b/src/engine/db/db-database-connection.vala
 | 
			
		||||
@@ -66,6 +66,11 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
     public Database database { get { return this._database; } }
 | 
			
		||||
     private weak Database _database;
 | 
			
		||||
 
 | 
			
		||||
+    /** {@inheritDoc} */
 | 
			
		||||
+    public override Logging.Source? logging_parent {
 | 
			
		||||
+        get { return this._database; }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     internal Sqlite.Database db { get { return this._db; } }
 | 
			
		||||
     private Sqlite.Database _db;
 | 
			
		||||
@@ -119,7 +124,6 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public Statement prepare(string sql) throws DatabaseError {
 | 
			
		||||
         var prepared = new Statement(this, sql);
 | 
			
		||||
-        prepared.set_logging_parent(this);
 | 
			
		||||
         return prepared;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/engine/db/db-database.vala b/src/engine/db/db-database.vala
 | 
			
		||||
index a807e7ba..df5bed21 100644
 | 
			
		||||
--- a/src/engine/db/db-database.vala
 | 
			
		||||
+++ b/src/engine/db/db-database.vala
 | 
			
		||||
@@ -57,6 +57,10 @@ public class Geary.Db.Database : Context {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    /** {@inheritDoc} */
 | 
			
		||||
+    public override Logging.Source? logging_parent { get { return _logging_parent; } }
 | 
			
		||||
+    private weak Logging.Source? _logging_parent = null;
 | 
			
		||||
+
 | 
			
		||||
     private DatabaseConnection? primary = null;
 | 
			
		||||
     private int outstanding_async_jobs = 0;
 | 
			
		||||
     private ThreadPool<TransactionAsyncJob>? thread_pool = null;
 | 
			
		||||
@@ -143,7 +147,6 @@ public class Geary.Db.Database : Context {
 | 
			
		||||
             var cx = new DatabaseConnection(
 | 
			
		||||
                 this, Sqlite.OPEN_READWRITE, cancellable
 | 
			
		||||
             );
 | 
			
		||||
-            cx.set_logging_parent(this);
 | 
			
		||||
 
 | 
			
		||||
             try {
 | 
			
		||||
                 // drop existing test table (in case created in prior failed open)
 | 
			
		||||
@@ -233,7 +236,6 @@ public class Geary.Db.Database : Context {
 | 
			
		||||
         DatabaseConnection cx = new DatabaseConnection(
 | 
			
		||||
             this, sqlite_flags, cancellable
 | 
			
		||||
         );
 | 
			
		||||
-        cx.set_logging_parent(this);
 | 
			
		||||
         prepare_connection(cx);
 | 
			
		||||
         return cx;
 | 
			
		||||
     }
 | 
			
		||||
@@ -357,6 +359,10 @@ public class Geary.Db.Database : Context {
 | 
			
		||||
         return yield job.wait_for_completion_async();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    /** Sets the logging parent context object for this database. */
 | 
			
		||||
+    public void set_logging_parent(Logging.Source parent) {
 | 
			
		||||
+        this._logging_parent = parent;
 | 
			
		||||
+    }
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public override Logging.State to_logging_state() {
 | 
			
		||||
diff --git a/src/engine/db/db-result.vala b/src/engine/db/db-result.vala
 | 
			
		||||
index b5382179..8c40c475 100644
 | 
			
		||||
--- a/src/engine/db/db-result.vala
 | 
			
		||||
+++ b/src/engine/db/db-result.vala
 | 
			
		||||
@@ -10,12 +10,14 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
 
 | 
			
		||||
     public Statement statement { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
+    /** {@inheritDoc} */
 | 
			
		||||
+    public override Logging.Source? logging_parent {
 | 
			
		||||
+        get { return this.statement; }
 | 
			
		||||
+    }
 | 
			
		||||
 
 | 
			
		||||
     // This results in an automatic first next().
 | 
			
		||||
     internal Result(Statement statement, Cancellable? cancellable) throws Error {
 | 
			
		||||
         this.statement = statement;
 | 
			
		||||
-        set_logging_parent(statement);
 | 
			
		||||
-
 | 
			
		||||
         statement.was_reset.connect(on_query_finished);
 | 
			
		||||
         statement.bindings_cleared.connect(on_query_finished);
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/engine/db/db-statement.vala b/src/engine/db/db-statement.vala
 | 
			
		||||
index 4d792b42..072692ff 100644
 | 
			
		||||
--- a/src/engine/db/db-statement.vala
 | 
			
		||||
+++ b/src/engine/db/db-statement.vala
 | 
			
		||||
@@ -12,6 +12,11 @@ public class Geary.Db.Statement : Context {
 | 
			
		||||
 
 | 
			
		||||
     public string sql { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
+    /** {@inheritDoc} */
 | 
			
		||||
+    public override Logging.Source? logging_parent {
 | 
			
		||||
+        get { return this.connection; }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     internal DatabaseConnection connection { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
     internal Sqlite.Statement stmt;
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
From 7c9d1258c6a952c7b7f79f34feb3225dea3fcc15 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Arnaud Ferraris <arnaud.ferraris@collabora.com>
 | 
			
		||||
Date: Wed, 25 Mar 2020 14:40:11 +0100
 | 
			
		||||
Subject: [PATCH 5/8] accounts-editor: make window usable on phones
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 ui/accounts_editor.ui           | 2 +-
 | 
			
		||||
 ui/accounts_editor_list_pane.ui | 1 +
 | 
			
		||||
 2 files changed, 2 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/accounts_editor.ui b/ui/accounts_editor.ui
 | 
			
		||||
index 4e23cdd5..04581e8d 100644
 | 
			
		||||
--- a/ui/accounts_editor.ui
 | 
			
		||||
+++ b/ui/accounts_editor.ui
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
   <template class="AccountsEditor" parent="GtkDialog">
 | 
			
		||||
     <property name="can_focus">False</property>
 | 
			
		||||
     <property name="modal">True</property>
 | 
			
		||||
-    <property name="default_width">700</property>
 | 
			
		||||
+    <property name="default_width">360</property>
 | 
			
		||||
     <property name="default_height">450</property>
 | 
			
		||||
     <property name="type_hint">dialog</property>
 | 
			
		||||
     <child type="titlebar">
 | 
			
		||||
diff --git a/ui/accounts_editor_list_pane.ui b/ui/accounts_editor_list_pane.ui
 | 
			
		||||
index a40604e3..b3946196 100644
 | 
			
		||||
--- a/ui/accounts_editor_list_pane.ui
 | 
			
		||||
+++ b/ui/accounts_editor_list_pane.ui
 | 
			
		||||
@@ -59,6 +59,7 @@
 | 
			
		||||
                         <property name="can_focus">False</property>
 | 
			
		||||
                         <property name="halign">start</property>
 | 
			
		||||
                         <property name="valign">start</property>
 | 
			
		||||
+                        <property name="wrap">True</property>
 | 
			
		||||
                         <property name="label" translatable="yes">To get started, select an email provider below.</property>
 | 
			
		||||
                         <property name="xalign">0</property>
 | 
			
		||||
                         <property name="wrap">True</property>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
From d1800de4dac6911b414b223318c6b12549e3a887 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Wed, 21 Oct 2020 11:18:19 +0200
 | 
			
		||||
Subject: [PATCH 5/6] conversation-viewer: don't show action-bar when in
 | 
			
		||||
 composer
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/components/main-toolbar.vala | 6 +++++-
 | 
			
		||||
 1 file changed, 5 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index f216238a..8255c93b 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -60,6 +60,7 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
         }
 | 
			
		||||
         this.conversation_viewer_action_bar = action_bar;
 | 
			
		||||
         conversation_header.size_allocate.connect(on_size_allocate);
 | 
			
		||||
+        conversation_header.notify["parent"].connect(on_size_allocate);
 | 
			
		||||
 
 | 
			
		||||
         // Assemble the main/mark menus
 | 
			
		||||
         Gtk.Builder builder = new Gtk.Builder.from_resource("/org/gnome/Geary/main-toolbar-menus.ui");
 | 
			
		||||
@@ -110,7 +111,10 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void on_size_allocate() {
 | 
			
		||||
-        if (reply_forward_buttons != null && archive_trash_delete_buttons != null)
 | 
			
		||||
+        /* Only show the action_bar when the conversation_header is shown */
 | 
			
		||||
+        if (conversation_header.parent == null)
 | 
			
		||||
+            conversation_viewer_action_bar.reveal_child = false;
 | 
			
		||||
+        else if (reply_forward_buttons != null && archive_trash_delete_buttons != null)
 | 
			
		||||
             if (conversation_viewer_action_bar.reveal_child && get_allocated_width() > 600) {
 | 
			
		||||
                 conversation_viewer_action_bar.reveal_child = false;
 | 
			
		||||
                 remove_action_parent();
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
From e39853db6215ac720dd047f48d940236cdbaa7f1 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 9 Sep 2020 18:38:08 +1000
 | 
			
		||||
Subject: [PATCH 006/124] Geary.ImapEngine.GenericAccount: Set database logging
 | 
			
		||||
 parent per account
 | 
			
		||||
 | 
			
		||||
Set the database's logging parent so its log statements are associated
 | 
			
		||||
with its account in the inspector.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap-engine/imap-engine-generic-account.vala | 2 ++
 | 
			
		||||
 1 file changed, 2 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala b/src/engine/imap-engine/imap-engine-generic-account.vala
 | 
			
		||||
index 2bd087b1..ef1ba7b4 100644
 | 
			
		||||
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
 | 
			
		||||
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
 | 
			
		||||
@@ -79,6 +79,8 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
 | 
			
		||||
         base(config, imap, smtp);
 | 
			
		||||
 
 | 
			
		||||
         this.local = local;
 | 
			
		||||
+        this.local.db.set_logging_parent(this);
 | 
			
		||||
+
 | 
			
		||||
         this.contact_store = new ContactStoreImpl(local.db);
 | 
			
		||||
 
 | 
			
		||||
         imap.min_pool_size = IMAP_MIN_POOL_SIZE;
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
From 805eb739e94e84ff3566283b9a89dcacc7b871e8 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Thu, 22 Oct 2020 12:33:58 +0200
 | 
			
		||||
Subject: [PATCH 6/6] in-app-notification: wrap text and add start/end margin
 | 
			
		||||
 | 
			
		||||
This makes sure that the in-app-notification fits also small window
 | 
			
		||||
sizes and eventually wraps the text to a new.
 | 
			
		||||
---
 | 
			
		||||
 ui/components-in-app-notification.ui | 5 +++++
 | 
			
		||||
 1 file changed, 5 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/components-in-app-notification.ui b/ui/components-in-app-notification.ui
 | 
			
		||||
index 54a1dafd..adbb3e2f 100644
 | 
			
		||||
--- a/ui/components-in-app-notification.ui
 | 
			
		||||
+++ b/ui/components-in-app-notification.ui
 | 
			
		||||
@@ -5,6 +5,8 @@
 | 
			
		||||
     <property name="visible">False</property>
 | 
			
		||||
     <property name="halign">center</property>
 | 
			
		||||
     <property name="valign">start</property>
 | 
			
		||||
+    <property name="margin-start">12</property>
 | 
			
		||||
+    <property name="margin-end">12</property>
 | 
			
		||||
     <signal name="notify::child-revealed" handler="on_child_revealed" swapped="no"/>
 | 
			
		||||
     <child>
 | 
			
		||||
       <object class="GtkBox" id="layout">
 | 
			
		||||
@@ -17,18 +19,21 @@
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkLabel" id="message_label">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
+            <property name="wrap">True</property>
 | 
			
		||||
           </object>
 | 
			
		||||
         </child>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkButton" id="action_button">
 | 
			
		||||
             <property name="visible">False</property>
 | 
			
		||||
             <property name="can_focus">False</property>
 | 
			
		||||
+            <property name="valign">center</property>
 | 
			
		||||
           </object>
 | 
			
		||||
         </child>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkButton" id="close_button">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
             <property name="can_focus">False</property>
 | 
			
		||||
+            <property name="valign">center</property>
 | 
			
		||||
             <signal name="clicked" handler="close" swapped="no"/>
 | 
			
		||||
             <style>
 | 
			
		||||
               <class name="flat"/>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										157
									
								
								mail-client/geary/files/0007-Geary.Db-Update-SQL-logging.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								mail-client/geary/files/0007-Geary.Db-Update-SQL-logging.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
			
		||||
From 0f60c285df50586058f9368c29f7b288c8076b76 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 9 Sep 2020 18:48:43 +1000
 | 
			
		||||
Subject: [PATCH 007/124] Geary.Db: Update SQL logging
 | 
			
		||||
 | 
			
		||||
Ensure all code paths that execute SQL are logging it if enabled, and
 | 
			
		||||
clean up the log formatting.
 | 
			
		||||
 | 
			
		||||
Add new `enable_result_logging` static property to control result
 | 
			
		||||
logging separately from SQL logging, so we can get SQL logged without
 | 
			
		||||
having to see email. Clean up result formatting, and keep track of the
 | 
			
		||||
current result row number and log that as context.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/db/db-context.vala             | 17 ++++++++++----
 | 
			
		||||
 src/engine/db/db-database-connection.vala | 14 +++++++-----
 | 
			
		||||
 src/engine/db/db-result.vala              | 27 +++++++++++++----------
 | 
			
		||||
 3 files changed, 37 insertions(+), 21 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/db/db-context.vala b/src/engine/db/db-context.vala
 | 
			
		||||
index 2ba8b305..7b8b9d65 100644
 | 
			
		||||
--- a/src/engine/db/db-context.vala
 | 
			
		||||
+++ b/src/engine/db/db-context.vala
 | 
			
		||||
@@ -16,16 +16,25 @@
 | 
			
		||||
 public abstract class Geary.Db.Context : BaseObject, Logging.Source {
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+    /** The GLib logging domain used by this class. */
 | 
			
		||||
+    public const string LOGGING_DOMAIN = Logging.DOMAIN + ".Db";
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
     /**
 | 
			
		||||
-     * Determines if SQL queries and results will be logged.
 | 
			
		||||
+     * Determines if SQL queries will be logged.
 | 
			
		||||
      *
 | 
			
		||||
-     * This will cause extremely verbose logging, so enable with care.
 | 
			
		||||
+     * This will cause verbose logging, so enable with care.
 | 
			
		||||
      */
 | 
			
		||||
     public static bool enable_sql_logging = false;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-    /** The GLib logging domain used by this class. */
 | 
			
		||||
-    public const string LOGGING_DOMAIN = Logging.DOMAIN + ".Db";
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Determines if SQL results will be logged.
 | 
			
		||||
+     *
 | 
			
		||||
+     * This will cause extremely verbose logging, so enable with extra care.
 | 
			
		||||
+     */
 | 
			
		||||
+    public static bool enable_result_logging = false;
 | 
			
		||||
+
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public string logging_domain {
 | 
			
		||||
diff --git a/src/engine/db/db-database-connection.vala b/src/engine/db/db-database-connection.vala
 | 
			
		||||
index 54d36160..29d52fd1 100644
 | 
			
		||||
--- a/src/engine/db/db-database-connection.vala
 | 
			
		||||
+++ b/src/engine/db/db-database-connection.vala
 | 
			
		||||
@@ -123,8 +123,10 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public Statement prepare(string sql) throws DatabaseError {
 | 
			
		||||
-        var prepared = new Statement(this, sql);
 | 
			
		||||
-        return prepared;
 | 
			
		||||
+        if (Db.Context.enable_sql_logging) {
 | 
			
		||||
+            debug(sql);
 | 
			
		||||
+        }
 | 
			
		||||
+        return new Statement(this, sql);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
@@ -136,11 +138,10 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public void exec(string sql, GLib.Cancellable? cancellable = null)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
+        check_cancelled("Connection.exec", cancellable);
 | 
			
		||||
         if (Db.Context.enable_sql_logging) {
 | 
			
		||||
-            debug("exec:\n\t%s", sql);
 | 
			
		||||
+            debug(sql);
 | 
			
		||||
         }
 | 
			
		||||
-
 | 
			
		||||
-        check_cancelled("Connection.exec", cancellable);
 | 
			
		||||
         var timer = new GLib.Timer();
 | 
			
		||||
         throw_on_error("Connection.exec_file", this.db.exec(sql), sql);
 | 
			
		||||
         check_elapsed("Query \"%s\"".printf(sql), timer);
 | 
			
		||||
@@ -150,6 +151,9 @@ public class Geary.Db.DatabaseConnection : Context, Connection {
 | 
			
		||||
     public void exec_file(GLib.File file, GLib.Cancellable? cancellable = null)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
         check_cancelled("Connection.exec_file", cancellable);
 | 
			
		||||
+        if (Db.Context.enable_sql_logging) {
 | 
			
		||||
+            debug(file.get_path());
 | 
			
		||||
+        }
 | 
			
		||||
 
 | 
			
		||||
         string sql;
 | 
			
		||||
         FileUtils.get_contents(file.get_path(), out sql);
 | 
			
		||||
diff --git a/src/engine/db/db-result.vala b/src/engine/db/db-result.vala
 | 
			
		||||
index 8c40c475..14dc71a9 100644
 | 
			
		||||
--- a/src/engine/db/db-result.vala
 | 
			
		||||
+++ b/src/engine/db/db-result.vala
 | 
			
		||||
@@ -8,8 +8,12 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
     public bool finished { get; private set; default = false; }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+    /** The statement this result was generated from. */
 | 
			
		||||
     public Statement statement { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
+    /** The current row represented by this result. */
 | 
			
		||||
+    public uint64 row { get; private set; default = 0; }
 | 
			
		||||
+
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public override Logging.Source? logging_parent {
 | 
			
		||||
         get { return this.statement; }
 | 
			
		||||
@@ -39,7 +43,8 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
     public bool next(Cancellable? cancellable = null) throws Error {
 | 
			
		||||
         check_cancelled("Result.next", cancellable);
 | 
			
		||||
 
 | 
			
		||||
-        if (!finished) {
 | 
			
		||||
+        if (!this.finished) {
 | 
			
		||||
+            this.row++;
 | 
			
		||||
             var timer = new GLib.Timer();
 | 
			
		||||
             this.finished = throw_on_error(
 | 
			
		||||
                 "Result.next", statement.stmt.step(), statement.sql
 | 
			
		||||
@@ -298,7 +303,12 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public override Logging.State to_logging_state() {
 | 
			
		||||
-        return new Logging.State(this, this.finished ? "finished" : "not finished");
 | 
			
		||||
+        return new Logging.State(
 | 
			
		||||
+            this,
 | 
			
		||||
+            "%llu, %s",
 | 
			
		||||
+            this.row,
 | 
			
		||||
+            this.finished ? "finished" : "!finished"
 | 
			
		||||
+        );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     internal override Result? get_result() {
 | 
			
		||||
@@ -306,16 +316,9 @@ public class Geary.Db.Result : Geary.Db.Context {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     [PrintfFormat]
 | 
			
		||||
-    private void log_result(string fmt, ...) {
 | 
			
		||||
-        if (Db.Context.enable_sql_logging) {
 | 
			
		||||
-            Statement? stmt = get_statement();
 | 
			
		||||
-            if (stmt != null) {
 | 
			
		||||
-                debug("%s\n\t<%s>",
 | 
			
		||||
-                      fmt.vprintf(va_list()),
 | 
			
		||||
-                      (stmt != null) ? "%.100s".printf(stmt.sql) : "no sql");
 | 
			
		||||
-            } else {
 | 
			
		||||
-                debug(fmt.vprintf(va_list()));
 | 
			
		||||
-            }
 | 
			
		||||
+    private inline void log_result(string fmt, ...) {
 | 
			
		||||
+        if (Db.Context.enable_result_logging) {
 | 
			
		||||
+            debug(fmt.vprintf(va_list()));
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,354 @@
 | 
			
		||||
From a30afb9e861450f042fd0d1e52ab6b965a247065 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Wed, 14 Oct 2020 14:44:26 +0200
 | 
			
		||||
Subject: [PATCH 7/8] account-editor: replace remove confirm view with dialog
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/POTFILES.in                                |   1 -
 | 
			
		||||
 .../accounts/accounts-editor-edit-pane.vala   |  23 ++-
 | 
			
		||||
 .../accounts/accounts-editor-remove-pane.vala |  74 --------
 | 
			
		||||
 src/client/meson.build                        |   1 -
 | 
			
		||||
 ui/accounts_editor_remove_pane.ui             | 159 ------------------
 | 
			
		||||
 ui/geary.css                                  |   8 +
 | 
			
		||||
 ui/org.gnome.Geary.gresource.xml              |   1 -
 | 
			
		||||
 7 files changed, 30 insertions(+), 237 deletions(-)
 | 
			
		||||
 delete mode 100644 src/client/accounts/accounts-editor-remove-pane.vala
 | 
			
		||||
 delete mode 100644 ui/accounts_editor_remove_pane.ui
 | 
			
		||||
 | 
			
		||||
diff --git a/po/POTFILES.in b/po/POTFILES.in
 | 
			
		||||
index cd8b339d..d9dcb0b7 100644
 | 
			
		||||
--- a/po/POTFILES.in
 | 
			
		||||
+++ b/po/POTFILES.in
 | 
			
		||||
@@ -9,7 +9,6 @@ src/client/accounts/accounts-editor.vala
 | 
			
		||||
 src/client/accounts/accounts-editor-add-pane.vala
 | 
			
		||||
 src/client/accounts/accounts-editor-edit-pane.vala
 | 
			
		||||
 src/client/accounts/accounts-editor-list-pane.vala
 | 
			
		||||
-src/client/accounts/accounts-editor-remove-pane.vala
 | 
			
		||||
 src/client/accounts/accounts-editor-row.vala
 | 
			
		||||
 src/client/accounts/accounts-editor-servers-pane.vala
 | 
			
		||||
 src/client/accounts/accounts-manager.vala
 | 
			
		||||
diff --git a/src/client/accounts/accounts-editor-edit-pane.vala b/src/client/accounts/accounts-editor-edit-pane.vala
 | 
			
		||||
index 5b944333..405dc7ba 100644
 | 
			
		||||
--- a/src/client/accounts/accounts-editor-edit-pane.vala
 | 
			
		||||
+++ b/src/client/accounts/accounts-editor-edit-pane.vala
 | 
			
		||||
@@ -217,7 +217,28 @@ internal class Accounts.EditorEditPane :
 | 
			
		||||
     [GtkCallback]
 | 
			
		||||
     private void on_remove_account_clicked() {
 | 
			
		||||
         if (!this.editor.accounts.is_goa_account(account)) {
 | 
			
		||||
-            this.editor.push(new EditorRemovePane(this.editor, this.account));
 | 
			
		||||
+            var button = new Gtk.Button.with_mnemonic(_("Remove Account"));
 | 
			
		||||
+            button.get_style_context().add_class(Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
 | 
			
		||||
+            button.show();
 | 
			
		||||
+
 | 
			
		||||
+            var dialog = new Gtk.MessageDialog(this.editor,
 | 
			
		||||
+            Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
 | 
			
		||||
+            Gtk.MessageType.WARNING,
 | 
			
		||||
+            Gtk.ButtonsType.NONE,
 | 
			
		||||
+            _("Remove Account: %s"),
 | 
			
		||||
+            account.primary_mailbox.address);
 | 
			
		||||
+            dialog.secondary_text = _("This will remove it from Geary and delete locally cached email data from your computer. Nothing will be deleted from your service provider.");
 | 
			
		||||
+
 | 
			
		||||
+            dialog.add_button (_("_Cancel"), Gtk.ResponseType.CANCEL);
 | 
			
		||||
+            dialog.add_action_widget(button, Gtk.ResponseType.ACCEPT);
 | 
			
		||||
+
 | 
			
		||||
+            dialog.response.connect((response_id) => {
 | 
			
		||||
+                if (response_id == Gtk.ResponseType.ACCEPT)
 | 
			
		||||
+                    this.editor.remove_account(this.account);
 | 
			
		||||
+
 | 
			
		||||
+                dialog.destroy();
 | 
			
		||||
+            });
 | 
			
		||||
+            dialog.show();
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/client/accounts/accounts-editor-remove-pane.vala b/src/client/accounts/accounts-editor-remove-pane.vala
 | 
			
		||||
deleted file mode 100644
 | 
			
		||||
index 2a6844cd..00000000
 | 
			
		||||
--- a/src/client/accounts/accounts-editor-remove-pane.vala
 | 
			
		||||
+++ /dev/null
 | 
			
		||||
@@ -1,74 +0,0 @@
 | 
			
		||||
-/*
 | 
			
		||||
- * Copyright 2018-2019 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.
 | 
			
		||||
- */
 | 
			
		||||
-
 | 
			
		||||
-/**
 | 
			
		||||
- * An account editor pane for removing an account from the client.
 | 
			
		||||
- */
 | 
			
		||||
-[GtkTemplate (ui = "/org/gnome/Geary/accounts_editor_remove_pane.ui")]
 | 
			
		||||
-internal class Accounts.EditorRemovePane : Gtk.Grid, EditorPane, AccountPane {
 | 
			
		||||
-
 | 
			
		||||
-
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    internal weak Accounts.Editor editor { get; set; }
 | 
			
		||||
-
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    internal Geary.AccountInformation account { get ; protected set; }
 | 
			
		||||
-
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    internal Gtk.Widget initial_widget {
 | 
			
		||||
-        get { return this.remove_button; }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    internal bool is_operation_running { get; protected set; default = false; }
 | 
			
		||||
-
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    internal GLib.Cancellable? op_cancellable {
 | 
			
		||||
-        get; protected set; default = null;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    [GtkChild]
 | 
			
		||||
-    private Gtk.HeaderBar header;
 | 
			
		||||
-
 | 
			
		||||
-    [GtkChild]
 | 
			
		||||
-    private Gtk.Label warning_label;
 | 
			
		||||
-
 | 
			
		||||
-    [GtkChild]
 | 
			
		||||
-    private Gtk.Button remove_button;
 | 
			
		||||
-
 | 
			
		||||
-
 | 
			
		||||
-    public EditorRemovePane(Editor editor, Geary.AccountInformation account) {
 | 
			
		||||
-        this.editor = editor;
 | 
			
		||||
-        this.account = account;
 | 
			
		||||
-
 | 
			
		||||
-        this.warning_label.set_text(
 | 
			
		||||
-            this.warning_label.get_text().printf(account.display_name)
 | 
			
		||||
-        );
 | 
			
		||||
-
 | 
			
		||||
-        connect_account_signals();
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    ~EditorRemovePane() {
 | 
			
		||||
-        disconnect_account_signals();
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    /** {@inheritDoc} */
 | 
			
		||||
-    internal Gtk.HeaderBar get_header() {
 | 
			
		||||
-        return this.header;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    [GtkCallback]
 | 
			
		||||
-    private void on_remove_button_clicked() {
 | 
			
		||||
-        this.editor.remove_account(this.account);
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    [GtkCallback]
 | 
			
		||||
-    private void on_back_button_clicked() {
 | 
			
		||||
-        this.editor.pop();
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-}
 | 
			
		||||
diff --git a/src/client/meson.build b/src/client/meson.build
 | 
			
		||||
index 4efadc6d..6514adca 100644
 | 
			
		||||
--- a/src/client/meson.build
 | 
			
		||||
+++ b/src/client/meson.build
 | 
			
		||||
@@ -38,7 +38,6 @@ client_vala_sources = files(
 | 
			
		||||
   'accounts/accounts-editor-add-pane.vala',
 | 
			
		||||
   'accounts/accounts-editor-edit-pane.vala',
 | 
			
		||||
   'accounts/accounts-editor-list-pane.vala',
 | 
			
		||||
-  'accounts/accounts-editor-remove-pane.vala',
 | 
			
		||||
   'accounts/accounts-editor-row.vala',
 | 
			
		||||
   'accounts/accounts-editor-servers-pane.vala',
 | 
			
		||||
   'accounts/accounts-signature-web-view.vala',
 | 
			
		||||
diff --git a/ui/accounts_editor_remove_pane.ui b/ui/accounts_editor_remove_pane.ui
 | 
			
		||||
deleted file mode 100644
 | 
			
		||||
index 7edf4c13..00000000
 | 
			
		||||
--- a/ui/accounts_editor_remove_pane.ui
 | 
			
		||||
+++ /dev/null
 | 
			
		||||
@@ -1,159 +0,0 @@
 | 
			
		||||
-<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
-<!-- Generated with glade 3.22.1 -->
 | 
			
		||||
-<interface>
 | 
			
		||||
-  <requires lib="gtk+" version="3.20"/>
 | 
			
		||||
-  <template class="AccountsEditorRemovePane" parent="GtkGrid">
 | 
			
		||||
-    <property name="visible">True</property>
 | 
			
		||||
-    <property name="can_focus">False</property>
 | 
			
		||||
-    <property name="valign">center</property>
 | 
			
		||||
-    <child>
 | 
			
		||||
-      <object class="HdyClamp">
 | 
			
		||||
-        <property name="visible">True</property>
 | 
			
		||||
-        <property name="can_focus">False</property>
 | 
			
		||||
-        <property name="margin">24</property>
 | 
			
		||||
-        <child>
 | 
			
		||||
-          <object class="GtkGrid">
 | 
			
		||||
-            <property name="visible">True</property>
 | 
			
		||||
-            <property name="can_focus">False</property>
 | 
			
		||||
-            <property name="valign">start</property>
 | 
			
		||||
-            <property name="vexpand">True</property>
 | 
			
		||||
-            <property name="row_spacing">32</property>
 | 
			
		||||
-            <child>
 | 
			
		||||
-              <object class="GtkButtonBox">
 | 
			
		||||
-                <property name="visible">True</property>
 | 
			
		||||
-                <property name="can_focus">False</property>
 | 
			
		||||
-                <property name="layout_style">end</property>
 | 
			
		||||
-                <child>
 | 
			
		||||
-                  <object class="GtkButton" id="remove_button">
 | 
			
		||||
-                    <property name="label" translatable="yes" comments="This is the remove account button in the account settings.">Remove Account</property>
 | 
			
		||||
-                    <property name="visible">True</property>
 | 
			
		||||
-                    <property name="can_focus">True</property>
 | 
			
		||||
-                    <property name="receives_default">True</property>
 | 
			
		||||
-                    <property name="tooltip_text" translatable="yes">Remove this account from Geary</property>
 | 
			
		||||
-                    <signal name="clicked" handler="on_remove_button_clicked" swapped="no"/>
 | 
			
		||||
-                    <style>
 | 
			
		||||
-                      <class name="destructive-action"/>
 | 
			
		||||
-                    </style>
 | 
			
		||||
-                  </object>
 | 
			
		||||
-                  <packing>
 | 
			
		||||
-                    <property name="expand">True</property>
 | 
			
		||||
-                    <property name="fill">True</property>
 | 
			
		||||
-                    <property name="position">1</property>
 | 
			
		||||
-                  </packing>
 | 
			
		||||
-                </child>
 | 
			
		||||
-                <style>
 | 
			
		||||
-                  <class name="geary-settings"/>
 | 
			
		||||
-                </style>
 | 
			
		||||
-              </object>
 | 
			
		||||
-              <packing>
 | 
			
		||||
-                <property name="left_attach">0</property>
 | 
			
		||||
-                <property name="top_attach">1</property>
 | 
			
		||||
-              </packing>
 | 
			
		||||
-            </child>
 | 
			
		||||
-            <child>
 | 
			
		||||
-              <object class="GtkGrid">
 | 
			
		||||
-                <property name="visible">True</property>
 | 
			
		||||
-                <property name="can_focus">False</property>
 | 
			
		||||
-                <property name="row_spacing">6</property>
 | 
			
		||||
-                <property name="column_spacing">18</property>
 | 
			
		||||
-                <child>
 | 
			
		||||
-                  <object class="GtkImage">
 | 
			
		||||
-                    <property name="visible">True</property>
 | 
			
		||||
-                    <property name="can_focus">False</property>
 | 
			
		||||
-                    <property name="icon_name">dialog-warning-symbolic</property>
 | 
			
		||||
-                    <property name="icon_size">6</property>
 | 
			
		||||
-                  </object>
 | 
			
		||||
-                  <packing>
 | 
			
		||||
-                    <property name="left_attach">0</property>
 | 
			
		||||
-                    <property name="top_attach">0</property>
 | 
			
		||||
-                    <property name="height">2</property>
 | 
			
		||||
-                  </packing>
 | 
			
		||||
-                </child>
 | 
			
		||||
-                <child>
 | 
			
		||||
-                  <object class="GtkLabel" id="warning_label">
 | 
			
		||||
-                    <property name="visible">True</property>
 | 
			
		||||
-                    <property name="can_focus">False</property>
 | 
			
		||||
-                    <property name="halign">start</property>
 | 
			
		||||
-                    <property name="vexpand">True</property>
 | 
			
		||||
-                    <property name="label" translatable="yes" comments="This title is shown to users when confirming if they want to remove an account. The string substitution is replaced with the account's name.">Confirm removing: %s</property>
 | 
			
		||||
-                    <attributes>
 | 
			
		||||
-                      <attribute name="weight" value="bold"/>
 | 
			
		||||
-                    </attributes>
 | 
			
		||||
-                    <style>
 | 
			
		||||
-                      <class name="title"/>
 | 
			
		||||
-                    </style>
 | 
			
		||||
-                  </object>
 | 
			
		||||
-                  <packing>
 | 
			
		||||
-                    <property name="left_attach">1</property>
 | 
			
		||||
-                    <property name="top_attach">0</property>
 | 
			
		||||
-                  </packing>
 | 
			
		||||
-                </child>
 | 
			
		||||
-                <child>
 | 
			
		||||
-                  <object class="GtkLabel">
 | 
			
		||||
-                    <property name="visible">True</property>
 | 
			
		||||
-                    <property name="can_focus">False</property>
 | 
			
		||||
-                    <property name="halign">start</property>
 | 
			
		||||
-                    <property name="label" translatable="yes">Removing an account will remove it from Geary and delete locally cached email data from your computer, but not from your service provider.</property>
 | 
			
		||||
-                    <property name="wrap">True</property>
 | 
			
		||||
-                    <property name="xalign">0</property>
 | 
			
		||||
-                  </object>
 | 
			
		||||
-                  <packing>
 | 
			
		||||
-                    <property name="left_attach">1</property>
 | 
			
		||||
-                    <property name="top_attach">1</property>
 | 
			
		||||
-                  </packing>
 | 
			
		||||
-                </child>
 | 
			
		||||
-              </object>
 | 
			
		||||
-              <packing>
 | 
			
		||||
-                <property name="left_attach">0</property>
 | 
			
		||||
-                <property name="top_attach">0</property>
 | 
			
		||||
-              </packing>
 | 
			
		||||
-            </child>
 | 
			
		||||
-            <style>
 | 
			
		||||
-              <class name="geary-accounts-editor-pane-content"/>
 | 
			
		||||
-            </style>
 | 
			
		||||
-          </object>
 | 
			
		||||
-        </child>
 | 
			
		||||
-      </object>
 | 
			
		||||
-      <packing>
 | 
			
		||||
-        <property name="left_attach">0</property>
 | 
			
		||||
-        <property name="top_attach">0</property>
 | 
			
		||||
-      </packing>
 | 
			
		||||
-    </child>
 | 
			
		||||
-    <style>
 | 
			
		||||
-      <class name="geary-accounts-editor-pane"/>
 | 
			
		||||
-    </style>
 | 
			
		||||
-  </template>
 | 
			
		||||
-  <object class="GtkHeaderBar" id="header">
 | 
			
		||||
-    <property name="visible">True</property>
 | 
			
		||||
-    <property name="can_focus">False</property>
 | 
			
		||||
-    <property name="title" translatable="yes">Remove account</property>
 | 
			
		||||
-    <property name="subtitle" translatable="yes">Account name</property>
 | 
			
		||||
-    <property name="show_close_button">True</property>
 | 
			
		||||
-    <child>
 | 
			
		||||
-      <object class="GtkGrid">
 | 
			
		||||
-        <property name="visible">True</property>
 | 
			
		||||
-        <property name="can_focus">False</property>
 | 
			
		||||
-        <child>
 | 
			
		||||
-          <object class="GtkButton" id="back_button">
 | 
			
		||||
-            <property name="visible">True</property>
 | 
			
		||||
-            <property name="can_focus">True</property>
 | 
			
		||||
-            <property name="receives_default">True</property>
 | 
			
		||||
-            <signal name="clicked" handler="on_back_button_clicked" swapped="no"/>
 | 
			
		||||
-            <child>
 | 
			
		||||
-              <object class="GtkImage">
 | 
			
		||||
-                <property name="visible">True</property>
 | 
			
		||||
-                <property name="can_focus">False</property>
 | 
			
		||||
-                <property name="no_show_all">True</property>
 | 
			
		||||
-                <property name="icon_name">go-previous-symbolic</property>
 | 
			
		||||
-              </object>
 | 
			
		||||
-            </child>
 | 
			
		||||
-          </object>
 | 
			
		||||
-          <packing>
 | 
			
		||||
-            <property name="left_attach">0</property>
 | 
			
		||||
-            <property name="top_attach">0</property>
 | 
			
		||||
-          </packing>
 | 
			
		||||
-        </child>
 | 
			
		||||
-      </object>
 | 
			
		||||
-    </child>
 | 
			
		||||
-  </object>
 | 
			
		||||
-</interface>
 | 
			
		||||
diff --git a/ui/geary.css b/ui/geary.css
 | 
			
		||||
index ca3cf640..3877038f 100644
 | 
			
		||||
--- a/ui/geary.css
 | 
			
		||||
+++ b/ui/geary.css
 | 
			
		||||
@@ -334,6 +334,14 @@ popover.geary-editor > grid > button.geary-setting-remove {
 | 
			
		||||
   margin-top: 12px;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+dialog.geary-remove-confirm .dialog-vbox {
 | 
			
		||||
+	margin: 12px;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+dialog.geary-remove-confirm .dialog-action-box {
 | 
			
		||||
+	margin: 6px;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* FolderList.Tree */
 | 
			
		||||
 
 | 
			
		||||
 treeview.sidebar:drop(active).after,
 | 
			
		||||
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
index 0b9e900f..efdc87d6 100644
 | 
			
		||||
--- a/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
+++ b/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
@@ -5,7 +5,6 @@
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">accounts_editor_add_pane.ui</file>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">accounts_editor_edit_pane.ui</file>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">accounts_editor_list_pane.ui</file>
 | 
			
		||||
-    <file compressed="true" preprocess="xml-stripblanks">accounts_editor_remove_pane.ui</file>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">accounts_editor_servers_pane.ui</file>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">application-main-window.ui</file>
 | 
			
		||||
     <file compressed="true" preprocess="xml-stripblanks">certificate_warning_dialog.glade</file>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,262 @@
 | 
			
		||||
From 915a38faca33caf04cab2398a52d743dea554359 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 11 Sep 2020 00:00:02 +1000
 | 
			
		||||
Subject: [PATCH 008/124] Geary.ImapDb.Account: Slice up search table
 | 
			
		||||
 population work better
 | 
			
		||||
 | 
			
		||||
Although populating the search table had been broken up into batches
 | 
			
		||||
of 50 email, it was still search for and loading every single message
 | 
			
		||||
id in both the MessageTable and MessageSearchTable, doing a manual
 | 
			
		||||
join, and then updating the batch, for *each* batch, and in a RW
 | 
			
		||||
transaction.
 | 
			
		||||
 | 
			
		||||
Break this up so that the ids are loaded and joined only once, the
 | 
			
		||||
queries happens in a RO transaction, the manual join happens in a side
 | 
			
		||||
thread, leaving each RW transaction only having to load the messages
 | 
			
		||||
and update the search index for up to 50 messages.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap-db/imap-db-account.vala | 205 ++++++++++++++----------
 | 
			
		||||
 1 file changed, 120 insertions(+), 85 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap-db/imap-db-account.vala b/src/engine/imap-db/imap-db-account.vala
 | 
			
		||||
index 99244dc2..54522b90 100644
 | 
			
		||||
--- a/src/engine/imap-db/imap-db-account.vala
 | 
			
		||||
+++ b/src/engine/imap-db/imap-db-account.vala
 | 
			
		||||
@@ -955,8 +955,78 @@ private class Geary.ImapDB.Account : BaseObject {
 | 
			
		||||
 
 | 
			
		||||
     public async void populate_search_table(Cancellable? cancellable) {
 | 
			
		||||
         debug("%s: Populating search table", account_information.id);
 | 
			
		||||
+        // Since all queries involved can be quite extensive and this
 | 
			
		||||
+        // is not a time-critical operation, split them up
 | 
			
		||||
+
 | 
			
		||||
+        var search_ids = new Gee.HashSet<int64?>(
 | 
			
		||||
+            Collection.int64_hash_func,
 | 
			
		||||
+            Collection.int64_equal_func
 | 
			
		||||
+        );
 | 
			
		||||
+        var message_ids = new Gee.HashSet<int64?>(
 | 
			
		||||
+            Collection.int64_hash_func,
 | 
			
		||||
+            Collection.int64_equal_func
 | 
			
		||||
+        );
 | 
			
		||||
+        var unindexed_message_ids = new Gee.HashSet<int64?>(
 | 
			
		||||
+            Collection.int64_hash_func,
 | 
			
		||||
+            Collection.int64_equal_func
 | 
			
		||||
+        );
 | 
			
		||||
+
 | 
			
		||||
         try {
 | 
			
		||||
-            while (!yield populate_search_table_batch_async(50, cancellable)) {
 | 
			
		||||
+            yield this.db.exec_transaction_async(
 | 
			
		||||
+                RO,
 | 
			
		||||
+                (cx, cancellable) => {
 | 
			
		||||
+                    // Embedding a SELECT within a SELECT is painfully slow
 | 
			
		||||
+                    // with SQLite, and a LEFT OUTER JOIN will still take in
 | 
			
		||||
+                    // the order of seconds, so manually perform the operation
 | 
			
		||||
+
 | 
			
		||||
+                    var result = cx.prepare(
 | 
			
		||||
+                        "SELECT docid FROM MessageSearchTable"
 | 
			
		||||
+                    ).exec(cancellable);
 | 
			
		||||
+                    while (!result.finished) {
 | 
			
		||||
+                        search_ids.add(result.rowid_at(0));
 | 
			
		||||
+                        result.next(cancellable);
 | 
			
		||||
+                    }
 | 
			
		||||
+
 | 
			
		||||
+                    var stmt = cx.prepare(
 | 
			
		||||
+                        "SELECT id FROM MessageTable WHERE (fields & ?) = ?"
 | 
			
		||||
+                    );
 | 
			
		||||
+                    stmt.bind_uint(0, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
 | 
			
		||||
+                    stmt.bind_uint(1, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
 | 
			
		||||
+                    result = stmt.exec(cancellable);
 | 
			
		||||
+                    while (!result.finished) {
 | 
			
		||||
+                        message_ids.add(result.rowid_at(0));
 | 
			
		||||
+                        result.next(cancellable);
 | 
			
		||||
+                    }
 | 
			
		||||
+
 | 
			
		||||
+                    return DONE;
 | 
			
		||||
+                },
 | 
			
		||||
+                cancellable
 | 
			
		||||
+            );
 | 
			
		||||
+
 | 
			
		||||
+            // Run this in a separate thread since it could be quite a
 | 
			
		||||
+            // substantial process for large accounts
 | 
			
		||||
+            yield Nonblocking.Concurrent.global.schedule_async(
 | 
			
		||||
+                () => {
 | 
			
		||||
+                    foreach (int64 message_id in message_ids) {
 | 
			
		||||
+                        if (!search_ids.contains(message_id)) {
 | 
			
		||||
+                            unindexed_message_ids.add(message_id);
 | 
			
		||||
+                        }
 | 
			
		||||
+                    }
 | 
			
		||||
+                },
 | 
			
		||||
+                cancellable
 | 
			
		||||
+            );
 | 
			
		||||
+
 | 
			
		||||
+            debug("%s: Found %d missing messages to populate",
 | 
			
		||||
+                  this.account_information.id,
 | 
			
		||||
+                  unindexed_message_ids.size
 | 
			
		||||
+            );
 | 
			
		||||
+
 | 
			
		||||
+            // Do the actual updating in batches since these require
 | 
			
		||||
+            // RW transactions
 | 
			
		||||
+            while (!unindexed_message_ids.is_empty) {
 | 
			
		||||
+                yield populate_search_table_batch_async(
 | 
			
		||||
+                    50, unindexed_message_ids, cancellable
 | 
			
		||||
+                );
 | 
			
		||||
                 // With multiple accounts, meaning multiple background threads
 | 
			
		||||
                 // doing such CPU- and disk-heavy work, this process can cause
 | 
			
		||||
                 // the main thread to slow to a crawl.  This delay means the
 | 
			
		||||
@@ -965,105 +1035,70 @@ private class Geary.ImapDB.Account : BaseObject {
 | 
			
		||||
                 yield Geary.Scheduler.sleep_ms_async(50);
 | 
			
		||||
             }
 | 
			
		||||
         } catch (Error e) {
 | 
			
		||||
-            debug("Error populating %s search table: %s", account_information.id, e.message);
 | 
			
		||||
+            debug("%s: Error populating search table: %s", account_information.id, e.message);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         debug("%s: Done populating search table", account_information.id);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private static Gee.HashSet<int64?> do_build_rowid_set(Db.Result result, Cancellable? cancellable)
 | 
			
		||||
-        throws Error {
 | 
			
		||||
-        Gee.HashSet<int64?> rowid_set = new Gee.HashSet<int64?>(Collection.int64_hash_func,
 | 
			
		||||
-            Collection.int64_equal_func);
 | 
			
		||||
-        while (!result.finished) {
 | 
			
		||||
-            rowid_set.add(result.rowid_at(0));
 | 
			
		||||
-            result.next(cancellable);
 | 
			
		||||
-        }
 | 
			
		||||
-
 | 
			
		||||
-        return rowid_set;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    private async bool populate_search_table_batch_async(int limit, Cancellable? cancellable)
 | 
			
		||||
-        throws Error {
 | 
			
		||||
+    private async void populate_search_table_batch_async(
 | 
			
		||||
+        int limit,
 | 
			
		||||
+        Gee.HashSet<int64?> unindexed_message_ids,
 | 
			
		||||
+        GLib.Cancellable? cancellable
 | 
			
		||||
+    ) throws GLib.Error {
 | 
			
		||||
         check_open();
 | 
			
		||||
-        debug("%s: Searching for up to %d missing indexed messages...", account_information.id,
 | 
			
		||||
-            limit);
 | 
			
		||||
-
 | 
			
		||||
-        int count = 0, total_unindexed = 0;
 | 
			
		||||
-        yield db.exec_transaction_async(Db.TransactionType.RW, (cx, cancellable) => {
 | 
			
		||||
-            // Embedding a SELECT within a SELECT is painfully slow
 | 
			
		||||
-            // with SQLite, and a LEFT OUTER JOIN will still take in
 | 
			
		||||
-            // the order of seconds, so manually perform the operation
 | 
			
		||||
 
 | 
			
		||||
-            Db.Statement stmt = cx.prepare("""
 | 
			
		||||
-                SELECT docid FROM MessageSearchTable
 | 
			
		||||
-            """);
 | 
			
		||||
-            Gee.HashSet<int64?> search_ids = do_build_rowid_set(stmt.exec(cancellable), cancellable);
 | 
			
		||||
-
 | 
			
		||||
-            stmt = cx.prepare("""
 | 
			
		||||
-                SELECT id FROM MessageTable WHERE (fields & ?) = ?
 | 
			
		||||
-            """);
 | 
			
		||||
-            stmt.bind_uint(0, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
 | 
			
		||||
-            stmt.bind_uint(1, Geary.ImapDB.Folder.REQUIRED_FTS_FIELDS);
 | 
			
		||||
-            Gee.HashSet<int64?> message_ids = do_build_rowid_set(stmt.exec(cancellable), cancellable);
 | 
			
		||||
-
 | 
			
		||||
-            // This is hard to calculate correctly without doing a
 | 
			
		||||
-            // join (which we should above, but is currently too
 | 
			
		||||
-            // slow), and if we do get it wrong the progress monitor
 | 
			
		||||
-            // will crash and burn, so just something too big to fail
 | 
			
		||||
-            // for now. See Bug 776383.
 | 
			
		||||
-            total_unindexed = message_ids.size;
 | 
			
		||||
-
 | 
			
		||||
-            // chaff out any MessageTable entries not present in the MessageSearchTable ... since
 | 
			
		||||
-            // we're given a limit, stuff messages req'ing search into separate set and stop when limit
 | 
			
		||||
-            // reached
 | 
			
		||||
-            Gee.HashSet<int64?> unindexed_message_ids = new Gee.HashSet<int64?>(Collection.int64_hash_func,
 | 
			
		||||
-                Collection.int64_equal_func);
 | 
			
		||||
-            foreach (int64 message_id in message_ids) {
 | 
			
		||||
-                if (search_ids.contains(message_id))
 | 
			
		||||
-                    continue;
 | 
			
		||||
-
 | 
			
		||||
-                unindexed_message_ids.add(message_id);
 | 
			
		||||
-                if (unindexed_message_ids.size >= limit)
 | 
			
		||||
-                    break;
 | 
			
		||||
-            }
 | 
			
		||||
-
 | 
			
		||||
-            // For all remaining MessageTable rowid's, generate search table entry
 | 
			
		||||
-            foreach (int64 message_id in unindexed_message_ids) {
 | 
			
		||||
-                try {
 | 
			
		||||
-                    Geary.Email.Field search_fields = Geary.Email.REQUIRED_FOR_MESSAGE |
 | 
			
		||||
-                        Geary.Email.Field.ORIGINATORS | Geary.Email.Field.RECEIVERS |
 | 
			
		||||
-                        Geary.Email.Field.SUBJECT;
 | 
			
		||||
+        uint count = 0;
 | 
			
		||||
+        var iter = unindexed_message_ids.iterator();
 | 
			
		||||
+        yield this.db.exec_transaction_async(
 | 
			
		||||
+            RW,
 | 
			
		||||
+            (cx, cancellable) => {
 | 
			
		||||
+                while (iter.has_next() && count < limit) {
 | 
			
		||||
+                    iter.next();
 | 
			
		||||
+                    int64 message_id = iter.get();
 | 
			
		||||
+                    try {
 | 
			
		||||
+                        Email.Field search_fields = (
 | 
			
		||||
+                            Email.REQUIRED_FOR_MESSAGE |
 | 
			
		||||
+                            Email.Field.ORIGINATORS |
 | 
			
		||||
+                            Email.Field.RECEIVERS |
 | 
			
		||||
+                            Email.Field.SUBJECT
 | 
			
		||||
+                        );
 | 
			
		||||
 
 | 
			
		||||
-                    Geary.Email.Field db_fields;
 | 
			
		||||
-                    MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
 | 
			
		||||
-                        cx, message_id, search_fields, out db_fields, cancellable);
 | 
			
		||||
-                    Geary.Email email = row.to_email(new Geary.ImapDB.EmailIdentifier(message_id, null));
 | 
			
		||||
-                    Attachment.add_attachments(
 | 
			
		||||
-                        cx, this.db.attachments_path, email, message_id, cancellable
 | 
			
		||||
-                    );
 | 
			
		||||
+                        Email.Field db_fields;
 | 
			
		||||
+                        MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
 | 
			
		||||
+                            cx, message_id, search_fields, out db_fields, cancellable
 | 
			
		||||
+                        );
 | 
			
		||||
+                        Email email = row.to_email(
 | 
			
		||||
+                            new Geary.ImapDB.EmailIdentifier(message_id, null)
 | 
			
		||||
+                        );
 | 
			
		||||
+                        Attachment.add_attachments(
 | 
			
		||||
+                            cx, this.db.attachments_path, email, message_id, cancellable
 | 
			
		||||
+                        );
 | 
			
		||||
+                        Geary.ImapDB.Folder.do_add_email_to_search_table(
 | 
			
		||||
+                            cx, message_id, email, cancellable
 | 
			
		||||
+                        );
 | 
			
		||||
+                    } catch (GLib.Error e) {
 | 
			
		||||
+                        // This is a somewhat serious issue since we rely on
 | 
			
		||||
+                        // there always being a row in the search table for
 | 
			
		||||
+                        // every message.
 | 
			
		||||
+                        warning(
 | 
			
		||||
+                            "Error populating message %s for indexing: %s",
 | 
			
		||||
+                            message_id.to_string(),
 | 
			
		||||
+                            e.message
 | 
			
		||||
+                        );
 | 
			
		||||
+                    }
 | 
			
		||||
 
 | 
			
		||||
-                    Geary.ImapDB.Folder.do_add_email_to_search_table(cx, message_id, email, cancellable);
 | 
			
		||||
-                } catch (Error e) {
 | 
			
		||||
-                    // This is a somewhat serious issue since we rely on
 | 
			
		||||
-                    // there always being a row in the search table for
 | 
			
		||||
-                    // every message.
 | 
			
		||||
-                    warning("Error adding message %s to the search table: %s", message_id.to_string(),
 | 
			
		||||
-                        e.message);
 | 
			
		||||
+                    iter.remove();
 | 
			
		||||
+                    ++count;
 | 
			
		||||
                 }
 | 
			
		||||
 
 | 
			
		||||
-                ++count;
 | 
			
		||||
-            }
 | 
			
		||||
-
 | 
			
		||||
-            return Db.TransactionOutcome.DONE;
 | 
			
		||||
+            return COMMIT;
 | 
			
		||||
         }, cancellable);
 | 
			
		||||
 
 | 
			
		||||
         if (count > 0) {
 | 
			
		||||
-            debug("%s: Found %d/%d missing indexed messages, %d remaining...",
 | 
			
		||||
-                account_information.id, count, limit, total_unindexed);
 | 
			
		||||
+            debug("%s: Populated %u missing indexed messages...",
 | 
			
		||||
+                account_information.id, count);
 | 
			
		||||
         }
 | 
			
		||||
-
 | 
			
		||||
-        return (count < limit);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     //
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
From 17afbca1727cc7780358239c7cafc8de1742bb0c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Tue, 20 Oct 2020 12:20:45 +0200
 | 
			
		||||
Subject: [PATCH 8/8] account-editor: don't show close button for edit/servers
 | 
			
		||||
 pane
 | 
			
		||||
 | 
			
		||||
This makes it consistent with the other panes.
 | 
			
		||||
---
 | 
			
		||||
 ui/accounts_editor_edit_pane.ui    | 2 +-
 | 
			
		||||
 ui/accounts_editor_servers_pane.ui | 2 +-
 | 
			
		||||
 2 files changed, 2 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/accounts_editor_edit_pane.ui b/ui/accounts_editor_edit_pane.ui
 | 
			
		||||
index 33b4a9e8..ce9bcb9a 100644
 | 
			
		||||
--- a/ui/accounts_editor_edit_pane.ui
 | 
			
		||||
+++ b/ui/accounts_editor_edit_pane.ui
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
     <property name="title" translatable="yes">Edit Account</property>
 | 
			
		||||
     <property name="subtitle" translatable="yes">Account Name</property>
 | 
			
		||||
     <property name="has_subtitle">False</property>
 | 
			
		||||
-    <property name="show_close_button">True</property>
 | 
			
		||||
+    <property name="show_close_button">False</property>
 | 
			
		||||
     <child>
 | 
			
		||||
       <object class="GtkGrid">
 | 
			
		||||
         <property name="visible">True</property>
 | 
			
		||||
diff --git a/ui/accounts_editor_servers_pane.ui b/ui/accounts_editor_servers_pane.ui
 | 
			
		||||
index a01eba5b..77ba674e 100644
 | 
			
		||||
--- a/ui/accounts_editor_servers_pane.ui
 | 
			
		||||
+++ b/ui/accounts_editor_servers_pane.ui
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
     <property name="can_focus">False</property>
 | 
			
		||||
     <property name="title" translatable="yes">Server Settings</property>
 | 
			
		||||
     <property name="subtitle" translatable="yes">Account Name</property>
 | 
			
		||||
-    <property name="show_close_button">True</property>
 | 
			
		||||
+    <property name="show_close_button">False</property>
 | 
			
		||||
     <child>
 | 
			
		||||
       <object class="GtkGrid">
 | 
			
		||||
         <property name="visible">True</property>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
From 3d8b86dd4e46939dc1a839873a2d049d650d0491 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 12 Sep 2020 12:02:49 +1000
 | 
			
		||||
Subject: [PATCH 009/124] Geary.ImapDB.Folder: Drop create/merge batch size
 | 
			
		||||
 down
 | 
			
		||||
 | 
			
		||||
We've had reports on Matrix that existing batch transactions in
 | 
			
		||||
`create_or_merge_email_async` are taking up to 30s to run, which is
 | 
			
		||||
getting uncomfortably close to the 60s timeout.
 | 
			
		||||
 | 
			
		||||
Drop the batch size down from 25 to 10 to reduce the chance that this
 | 
			
		||||
will eventually fail with a "database is locked" error.
 | 
			
		||||
 | 
			
		||||
See #921 for context.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap-db/imap-db-folder.vala | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala
 | 
			
		||||
index 4b015cd1..2c2d4015 100644
 | 
			
		||||
--- a/src/engine/imap-db/imap-db-folder.vala
 | 
			
		||||
+++ b/src/engine/imap-db/imap-db-folder.vala
 | 
			
		||||
@@ -40,7 +40,7 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
 | 
			
		||||
     private const int LIST_EMAIL_METADATA_COUNT = 100;
 | 
			
		||||
     private const int LIST_EMAIL_FIELDS_CHUNK_COUNT = 500;
 | 
			
		||||
     private const int REMOVE_COMPLETE_LOCATIONS_CHUNK_COUNT = 500;
 | 
			
		||||
-    private const int CREATE_MERGE_EMAIL_CHUNK_COUNT = 25;
 | 
			
		||||
+    private const int CREATE_MERGE_EMAIL_CHUNK_COUNT = 10;
 | 
			
		||||
     private const int OLD_MSG_DETACH_BATCH_SIZE = 1000;
 | 
			
		||||
 
 | 
			
		||||
     // When old messages beyond the period set in the account preferences are removed this number 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										405
									
								
								mail-client/geary/files/0010-Update-Friulian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								mail-client/geary/files/0010-Update-Friulian-translation.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,405 @@
 | 
			
		||||
From 56b77cf0d7595c1ccd0846d410a16cb5d5c540b8 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Fabio Tomat <f.t.public@gmail.com>
 | 
			
		||||
Date: Mon, 14 Sep 2020 19:32:40 +0000
 | 
			
		||||
Subject: [PATCH 010/124] Update Friulian translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/fur.po | 103 +++++++++++++++++++++++++++++-------------------------
 | 
			
		||||
 1 file changed, 55 insertions(+), 48 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/fur.po b/po/fur.po
 | 
			
		||||
index f680a065..fd5e3639 100644
 | 
			
		||||
--- a/po/fur.po
 | 
			
		||||
+++ b/po/fur.po
 | 
			
		||||
@@ -7,8 +7,8 @@ msgid ""
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary master\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
-"POT-Creation-Date: 2020-08-29 01:59+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-09-08 16:21+0200\n"
 | 
			
		||||
+"POT-Creation-Date: 2020-09-13 04:23+0000\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-09-14 21:31+0200\n"
 | 
			
		||||
 "Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
 | 
			
		||||
 "Language-Team: Friulian <fur@li.org>\n"
 | 
			
		||||
 "Language: fur\n"
 | 
			
		||||
@@ -232,6 +232,8 @@ msgid ""
 | 
			
		||||
 "Enables shortcuts for email actions that do not require pressing <Ctrl> to "
 | 
			
		||||
 "emulate those used by Gmail."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Al abilite lis scurtis pes azions e-mail che no àn bisugne de pression di "
 | 
			
		||||
+"<Ctrl> par emulâ chês dopradis di Gmail."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:82
 | 
			
		||||
 msgid "Languages that shall be used in the spell checker"
 | 
			
		||||
@@ -242,16 +244,23 @@ msgid ""
 | 
			
		||||
 "A list of POSIX locales, with the empty list disabling spell checking and "
 | 
			
		||||
 "the null list using desktop languages by default."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Une liste di localizazions POSIX, cuntune liste vueide si disabilite il "
 | 
			
		||||
+"control ortografic e cuntune liste nule si dopre lis lenghis predefinidis "
 | 
			
		||||
+"dal scritori."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:90
 | 
			
		||||
 msgid "Languages that are displayed in the spell checker popover"
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Lis lenghis che a vegnin mostradis intal ricuadri a comparse dal control "
 | 
			
		||||
+"ortografic"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:91
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "List of languages that are always displayed in the popover of the spell "
 | 
			
		||||
 "checker."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Liste di lenghis che a vegnin simpri mostradis intal ricuadri a comparse dal "
 | 
			
		||||
+"control ortografic."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:96
 | 
			
		||||
 msgid "Notify of new mail at startup"
 | 
			
		||||
@@ -285,6 +294,7 @@ msgstr ""
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "Acceptable values are “exact”, “conservative”, “aggressive”, and “horizon”."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"I valôrs ametûts a son “exact”, “conservative”, “aggressive”, e “horizon”."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:120
 | 
			
		||||
 msgid "Zoom of conversation viewer"
 | 
			
		||||
@@ -304,13 +314,15 @@ msgstr "La ultime dimension regjistrade dal barcon dal redatôr distacât."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:132
 | 
			
		||||
 msgid "Undo sending email delay"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Anule ritart di spedizion e-mail"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:133
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "The number of seconds to wait before sending an email. Set to zero or less "
 | 
			
		||||
 "to disable."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Il numar di seconts di spietâ prime di inviâ une e-mail. Met a zero o mancul "
 | 
			
		||||
+"par disabilitâ."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:139
 | 
			
		||||
 msgid "Brief notification display time"
 | 
			
		||||
@@ -320,7 +332,7 @@ msgstr ""
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "The length of time in seconds for which brief notifications should be "
 | 
			
		||||
 "displayed."
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "La lungjece temporâl in seconts che si à di mostrâ lis notifichis."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:146
 | 
			
		||||
 msgid "List of optional plugins"
 | 
			
		||||
@@ -332,12 +344,13 @@ msgstr "I plugin listâts achì a vignaran cjariâts al inviament."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:152
 | 
			
		||||
 msgid "Whether we migrated the old settings"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Indiche se o ven migrât lis impostazions vecjis"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:153
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "False to check for the old “org.yorba.geary”-schema and copy its values."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Fals par controlâ il vecjo scheme “org.yorba.geary” e copiâ i siei valôrs."
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: In-app notification label, when
 | 
			
		||||
 #. the app had a problem pinning an otherwise
 | 
			
		||||
@@ -772,11 +785,11 @@ msgstr "Salve pueste inviade sul servidôr"
 | 
			
		||||
 #: src/client/accounts/accounts-editor-servers-pane.vala:961
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "%s using OAuth2"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "%s doprant OAuth2"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/accounts/accounts-editor-servers-pane.vala:971
 | 
			
		||||
 msgid "Use receiving server login"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Dopre acès dal servidôr di ricezion"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: File name used in save chooser when saving
 | 
			
		||||
 #. attachments that do not otherwise have a name.
 | 
			
		||||
@@ -822,12 +835,12 @@ msgstr "Visite il sît web di Geary"
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:97
 | 
			
		||||
 msgid "Print debug logging"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Stampe i regjistris di debug"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:100
 | 
			
		||||
 msgid "Start with the main window hidden (deprecated)"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Partìs cul barcon principâl platât (deplorât)"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:103
 | 
			
		||||
@@ -960,13 +973,13 @@ msgstr "Fabio Tomat <f.t.public@gmail.com>, 2020"
 | 
			
		||||
 
 | 
			
		||||
 #. / Warning printed to the console when a deprecated
 | 
			
		||||
 #. / command line option is used.
 | 
			
		||||
-#: src/client/application/application-client.vala:1047
 | 
			
		||||
+#: src/client/application/application-client.vala:1045
 | 
			
		||||
 msgid "The `--hidden` option is deprecated and will be removed in the future."
 | 
			
		||||
 msgstr "La opzion `--hidden` e je deplorade e un doman e vignarà gjavade."
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line warning, string substitution
 | 
			
		||||
 #. / is the given argument
 | 
			
		||||
-#: src/client/application/application-client.vala:1080
 | 
			
		||||
+#: src/client/application/application-client.vala:1078
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Unrecognised program argument: “%s”"
 | 
			
		||||
 msgstr "Argoment di program no ricognossût: “%s”"
 | 
			
		||||
@@ -1322,7 +1335,7 @@ msgstr "Salve come"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/components/components-inspector.vala:230
 | 
			
		||||
 #: src/client/dialogs/dialogs-problem-details-dialog.vala:224
 | 
			
		||||
-#: ui/accounts_editor_servers_pane.ui:17
 | 
			
		||||
+#: ui/accounts_editor_servers_pane.ui:17 ui/composer-headerbar.ui:61
 | 
			
		||||
 msgid "Cancel"
 | 
			
		||||
 msgstr "Anule"
 | 
			
		||||
 
 | 
			
		||||
@@ -2208,10 +2221,8 @@ msgstr "Compile e invie modei di e-mail doprant un sfuei di calcul"
 | 
			
		||||
 #. Translators: Info bar label for starting sending a mail
 | 
			
		||||
 #. merge
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.vala:118
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "StartTLS"
 | 
			
		||||
 msgid "Start"
 | 
			
		||||
-msgstr "StartTLS"
 | 
			
		||||
+msgstr "Scomence"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Info bar label for pausing sending a mail
 | 
			
		||||
 #. merge
 | 
			
		||||
@@ -2379,21 +2390,21 @@ msgstr "%A"
 | 
			
		||||
 #. / http://developer.gnome.org/glib/2.32/glib-GDateTime.html#g-date-time-format
 | 
			
		||||
 #: src/client/util/util-date.vala:218
 | 
			
		||||
 msgid "%a, %b %-e, %Y at %l:%M %P"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "%a, %-e di %b dal %Y aes %l:%M %P"
 | 
			
		||||
 
 | 
			
		||||
 #. / 24 hours format for the datetime that a message being
 | 
			
		||||
 #. / replied to was received See
 | 
			
		||||
 #. / http://developer.gnome.org/glib/2.32/glib-GDateTime.html#g-date-time-format
 | 
			
		||||
 #: src/client/util/util-date.vala:224
 | 
			
		||||
 msgid "%a, %b %-e, %Y at %H:%M"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "%a, %-e di %b dal %Y aes %H:%M"
 | 
			
		||||
 
 | 
			
		||||
 #. / Format for the datetime that a message being replied to
 | 
			
		||||
 #. / was received See
 | 
			
		||||
 #. / http://developer.gnome.org/glib/2.32/glib-GDateTime.html#g-date-time-format
 | 
			
		||||
 #: src/client/util/util-date.vala:230
 | 
			
		||||
 msgid "%a, %b %-e, %Y at %X"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "%a, %-e di %b dal %Y aes %X"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Label used when an email has a missing or
 | 
			
		||||
 #. an empty subject
 | 
			
		||||
@@ -2426,7 +2437,7 @@ msgstr[1] "%s e altris %d"
 | 
			
		||||
 #: src/client/util/util-email.vala:193
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "On %1$s, %2$s wrote:"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Ai %1$s, %2$s al/e à scrit:"
 | 
			
		||||
 
 | 
			
		||||
 #. / The quoted header for a message being replied to (in case the date is not known).
 | 
			
		||||
 #. / %s will be replaced by the original sender.
 | 
			
		||||
@@ -2721,7 +2732,6 @@ msgstr ""
 | 
			
		||||
 #. put the most common localized name to the front for the
 | 
			
		||||
 #. default. English names do not need to be included.
 | 
			
		||||
 #: src/engine/imap-engine/imap-engine-generic-account.vala:1030
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
 msgid "Trash | Rubbish | Rubbish Bin"
 | 
			
		||||
 msgstr "Scovacere | Refudum | Bidon"
 | 
			
		||||
 
 | 
			
		||||
@@ -2811,7 +2821,7 @@ msgstr "Account"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/accounts_editor_list_pane.ui:62
 | 
			
		||||
 msgid "To get started, select an email provider below."
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Par scomençâ, selezione un furnidôr di e-mail chi sot."
 | 
			
		||||
 
 | 
			
		||||
 #: ui/accounts_editor_list_pane.ui:75
 | 
			
		||||
 msgid "Welcome to Geary"
 | 
			
		||||
@@ -2855,27 +2865,27 @@ msgstr "_No sta fidâti di chest servidôr"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:100
 | 
			
		||||
 msgid "Bold text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Test neret"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:124
 | 
			
		||||
 msgid "Italic text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Test corsîf"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:148
 | 
			
		||||
 msgid "Underline text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Test sotlineât"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:172
 | 
			
		||||
 msgid "Strikethrough text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Test stricât"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:205
 | 
			
		||||
 msgid "Insert bulleted list"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Inserìs liste pontade"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:229
 | 
			
		||||
 msgid "Insert numbered list"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Inserìs liste numerade"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:262
 | 
			
		||||
 msgid "Indent or quote text"
 | 
			
		||||
@@ -2887,7 +2897,7 @@ msgstr ""
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:315
 | 
			
		||||
 msgid "Remove text formatting"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Gjave formatazion dal test"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:334
 | 
			
		||||
 msgid "Change font type"
 | 
			
		||||
@@ -2915,7 +2925,7 @@ msgstr "Cambie dimension dal caratar"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:447
 | 
			
		||||
 msgid "Insert or update text link"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Inserìs o inzorne il colegament dal test"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:471
 | 
			
		||||
 msgid "Insert an image"
 | 
			
		||||
@@ -3034,7 +3044,7 @@ msgstr "Salve e siere"
 | 
			
		||||
 #. Note that this button and the Update button will never be shown at the same time to the user.
 | 
			
		||||
 #: ui/composer-link-popover.ui:42
 | 
			
		||||
 msgid "Insert the new link with this URL"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Inserìs il gnûf colegament cun chest URL"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-link-popover.ui:43
 | 
			
		||||
 msgid "Add"
 | 
			
		||||
@@ -3047,7 +3057,7 @@ msgstr "URL colegament"
 | 
			
		||||
 #. Note that this button and the Insert button will never be shown at the same time to the user.
 | 
			
		||||
 #: ui/composer-link-popover.ui:61
 | 
			
		||||
 msgid "Update this link’s URL"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Inzorne chest URL dal link"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-link-popover.ui:62
 | 
			
		||||
 msgid "Update"
 | 
			
		||||
@@ -3127,7 +3137,7 @@ msgstr "Detais:"
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
 #: ui/components-inspector.ui:19 ui/problem-details-dialog.ui:24
 | 
			
		||||
 msgid "Search for matching log entries"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Cîr vôs di regjistri corispondentis"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #: ui/components-inspector.ui:35
 | 
			
		||||
@@ -3143,7 +3153,7 @@ msgstr ""
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
 #: ui/components-inspector.ui:81 ui/problem-details-dialog.ui:51
 | 
			
		||||
 msgid "Save logs entries and details"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Salve vôs dai regjistris e detais"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
@@ -3182,10 +3192,8 @@ msgstr "Cjarie simpri lis imagjins rimotis"
 | 
			
		||||
 
 | 
			
		||||
 #. Title label on contact popover
 | 
			
		||||
 #: ui/conversation-contact-popover.ui:264
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "Email address"
 | 
			
		||||
 msgid "Deceptive email address"
 | 
			
		||||
-msgstr "Direzion e-mail"
 | 
			
		||||
+msgstr "Direzion e-mail ingjanose"
 | 
			
		||||
 
 | 
			
		||||
 #. Contact popover label
 | 
			
		||||
 #: ui/conversation-contact-popover.ui:294
 | 
			
		||||
@@ -3245,7 +3253,6 @@ msgstr "Sposte messaç te _Scovacere"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Menu item to delete a single, specific message
 | 
			
		||||
 #: ui/conversation-email-menus.ui:57
 | 
			
		||||
-#| msgid "Autoselect next message"
 | 
			
		||||
 msgid "_Delete message…"
 | 
			
		||||
 msgstr "_Elimine messaç…"
 | 
			
		||||
 
 | 
			
		||||
@@ -3256,23 +3263,23 @@ msgstr "_Viôt sorzint"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/conversation-message-link-popover.ui:54
 | 
			
		||||
 msgid "But actually goes to:"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Ma invezit al va su:"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/conversation-message-link-popover.ui:84
 | 
			
		||||
 msgid "The link appears to go to:"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Al semee che il colegament al ledi su:"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/conversation-message-link-popover.ui:96
 | 
			
		||||
 msgid "Deceptive link found"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Colegament ingjanôs cjatât"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/conversation-message-link-popover.ui:111
 | 
			
		||||
 msgid "The email sender may be leading you to the wrong web site."
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Il mitent de e-mail al podarès puartâti su sîts web sbaliâts."
 | 
			
		||||
 
 | 
			
		||||
 #: ui/conversation-message-link-popover.ui:124
 | 
			
		||||
 msgid "If unsure, contact the sender and ask before continuing."
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Se no si è sigûrs, contatâ il mitent e domandâ prime di continuâ."
 | 
			
		||||
 
 | 
			
		||||
 #: ui/conversation-message-menus.ui:7
 | 
			
		||||
 msgid "_Open Link"
 | 
			
		||||
@@ -3611,27 +3618,27 @@ msgstr "Modifiche cun test formatât"
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:468
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Paste without formatting"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Tache cence formatazion"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:475
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Bold text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Met test in neret"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:482
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Italicize text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Met test in corsîf"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:489
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Underline text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Sotlinie il test"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:496
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Strike text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Striche il test"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:503
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
@@ -3711,7 +3718,7 @@ msgstr "_Autentiche"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/upgrade_dialog.glade:60
 | 
			
		||||
 msgid "Geary update in progress…"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Inzornament di Geary in vore…"
 | 
			
		||||
 
 | 
			
		||||
 #~ msgid "mail-send"
 | 
			
		||||
 #~ msgstr "mail-send"
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										180
									
								
								mail-client/geary/files/0011-Update-Friulian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								mail-client/geary/files/0011-Update-Friulian-translation.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,180 @@
 | 
			
		||||
From 4a4e6a6992fc1349fd532ad35b0c787992024162 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Fabio Tomat <f.t.public@gmail.com>
 | 
			
		||||
Date: Tue, 15 Sep 2020 05:20:06 +0000
 | 
			
		||||
Subject: [PATCH 011/124] Update Friulian translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/fur.po | 46 +++++++++++++++++++++++-----------------------
 | 
			
		||||
 1 file changed, 23 insertions(+), 23 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/fur.po b/po/fur.po
 | 
			
		||||
index fd5e3639..1db111d0 100644
 | 
			
		||||
--- a/po/fur.po
 | 
			
		||||
+++ b/po/fur.po
 | 
			
		||||
@@ -7,8 +7,8 @@ msgid ""
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary master\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
-"POT-Creation-Date: 2020-09-13 04:23+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-09-14 21:31+0200\n"
 | 
			
		||||
+"POT-Creation-Date: 2020-09-14 19:33+0000\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-09-15 07:19+0200\n"
 | 
			
		||||
 "Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
 | 
			
		||||
 "Language-Team: Friulian <fur@li.org>\n"
 | 
			
		||||
 "Language: fur\n"
 | 
			
		||||
@@ -288,7 +288,7 @@ msgstr "Vêr par scrivi lis e-mail in HTML; fals pal test sempliç."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:114
 | 
			
		||||
 msgid "Advisory strategy for full-text searching"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Strategjie consultive pe ricercje di tescj complets"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:115
 | 
			
		||||
 msgid ""
 | 
			
		||||
@@ -326,7 +326,7 @@ msgstr ""
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:139
 | 
			
		||||
 msgid "Brief notification display time"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Timp di visualizazion des notifichis"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:140
 | 
			
		||||
 msgid ""
 | 
			
		||||
@@ -580,7 +580,7 @@ msgstr "Discjarie pueste"
 | 
			
		||||
 #: src/client/accounts/accounts-editor-edit-pane.vala:822
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Change download period back to: %s"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Tornâ al precedent periodi di discjariament: %s"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/accounts/accounts-editor-edit-pane.vala:843
 | 
			
		||||
 msgid "Everything"
 | 
			
		||||
@@ -850,18 +850,18 @@ msgstr "Abilite l'ispetôr WebKitGTK intes viodudis web"
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:106
 | 
			
		||||
 msgid "Log conversation monitoring"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Regjistre il monitorament des conversazions"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:109
 | 
			
		||||
 msgid "Log IMAP network deserialization"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Regjistre la deserializazion de rêt IMAP"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option. "Normalization" can also be called
 | 
			
		||||
 #. / "synchronization".
 | 
			
		||||
 #: src/client/application/application-client.vala:113
 | 
			
		||||
 msgid "Log folder normalization"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Regjistre la sincronizazion de cartele"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:116
 | 
			
		||||
@@ -873,7 +873,7 @@ msgstr "Regjistre ativitât di rêt IMAP"
 | 
			
		||||
 #. / also be called the IMAP events queue.
 | 
			
		||||
 #: src/client/application/application-client.vala:121
 | 
			
		||||
 msgid "Log IMAP replay queue"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Regjistre la code di events IMAP"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:124
 | 
			
		||||
@@ -897,10 +897,8 @@ msgstr "Vierç un gnûf barcon"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:135
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "Failed to store certificate"
 | 
			
		||||
 msgid "Revoke all pinned TLS server certificates"
 | 
			
		||||
-msgstr "No si è rivâts a archiviâ il certificât"
 | 
			
		||||
+msgstr "Revoche ducj i certificâts di servidôr TLS fissâts"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
 #: src/client/application/application-client.vala:138
 | 
			
		||||
@@ -2268,10 +2266,8 @@ msgid "Messaging Menu"
 | 
			
		||||
 msgstr "Menù di messaç"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/plugin/messaging-menu/messaging-menu.plugin.desktop.in:5
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "Show notifications for new mail"
 | 
			
		||||
 msgid "Displays Unity Messaging Menu notifications for new email"
 | 
			
		||||
-msgstr "Mostre lis notifichis pe gnove pueste"
 | 
			
		||||
+msgstr "Al mostre lis notifichis di gnove pueste tal menù dai messaçs di Unity"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/plugin/messaging-menu/messaging-menu.vala:79
 | 
			
		||||
 #, c-format
 | 
			
		||||
@@ -2838,6 +2834,8 @@ msgid ""
 | 
			
		||||
 "Removing an account will remove it from Geary and delete locally cached "
 | 
			
		||||
 "email data from your computer, but not from your service provider."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Gjavant un account si lu gjavarà di Geary e si eliminarà dal computer i dâts "
 | 
			
		||||
+"e-mail te cache locâl, ma no dal gjestôr/furnidôr dal servizi."
 | 
			
		||||
 
 | 
			
		||||
 #: ui/accounts_editor_remove_pane.ui:122
 | 
			
		||||
 msgid "Remove account"
 | 
			
		||||
@@ -2889,11 +2887,11 @@ msgstr "Inserìs liste numerade"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:262
 | 
			
		||||
 msgid "Indent or quote text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Indentâ o citâ test"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:286
 | 
			
		||||
 msgid "Un-indent or unquote text"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Gjavâ la indintidure o la citazion dal test"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/composer-editor.ui:315
 | 
			
		||||
 msgid "Remove text formatting"
 | 
			
		||||
@@ -3128,6 +3126,10 @@ msgid ""
 | 
			
		||||
 "channels</a> or attach to a <a href=\"https://wiki.gnome.org/Apps/Geary/"
 | 
			
		||||
 "ReportingABug\">new bug report</a>."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Se il probleme al è grivi o al persist, salve e invie chescj detais a un dai "
 | 
			
		||||
+"<a href=\"https://wiki.gnome.org/Apps/Geary/Contact\">canâi di contat</a> o "
 | 
			
		||||
+"zonte suntune <a href=\"https://wiki.gnome.org/Apps/Geary/ReportingABug"
 | 
			
		||||
+"\">gnove segnalazion di erôr</a>."
 | 
			
		||||
 
 | 
			
		||||
 #: ui/components-inspector-error-view.ui:47
 | 
			
		||||
 msgid "Details:"
 | 
			
		||||
@@ -3142,12 +3144,12 @@ msgstr "Cîr vôs di regjistri corispondentis"
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #: ui/components-inspector.ui:35
 | 
			
		||||
 msgid "Toggle appending new log entries"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Ativâ/disativâ la zonte di gnovis vôs di regjistri"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #: ui/components-inspector.ui:55
 | 
			
		||||
 msgid "Add a marker entry to the log"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Zonte une vôs-marcadôr al regjistri"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
@@ -3423,7 +3425,7 @@ msgstr "Bute vie conversazions"
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:87 ui/gtk/help-overlay.ui:340
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Junk conversations"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Conversazions malvoludis"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:95 ui/gtk/help-overlay.ui:347
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
@@ -3526,11 +3528,9 @@ msgid "Select next/previous conversation"
 | 
			
		||||
 msgstr "Selezione la prossime/precedente conversazion"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:248
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "Autoselect next message"
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Focus next/previous message"
 | 
			
		||||
-msgstr "Selezione in automatic il prossim messaç"
 | 
			
		||||
+msgstr "Met a fûc (il stât atîf) il prossim/precedent messaç"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:260
 | 
			
		||||
 msgid "Single-key Shortcuts"
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
From acabdc9e73e7a6e23f14540ac2485783161eecc4 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Fabio Tomat <f.t.public@gmail.com>
 | 
			
		||||
Date: Tue, 15 Sep 2020 05:52:24 +0000
 | 
			
		||||
Subject: [PATCH 012/124] Update Friulian translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/fur.po | 4 ++--
 | 
			
		||||
 1 file changed, 2 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/fur.po b/po/fur.po
 | 
			
		||||
index 1db111d0..d13465ba 100644
 | 
			
		||||
--- a/po/fur.po
 | 
			
		||||
+++ b/po/fur.po
 | 
			
		||||
@@ -8,7 +8,7 @@ msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary master\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
 "POT-Creation-Date: 2020-09-14 19:33+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-09-15 07:19+0200\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-09-15 07:51+0200\n"
 | 
			
		||||
 "Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
 | 
			
		||||
 "Language-Team: Friulian <fur@li.org>\n"
 | 
			
		||||
 "Language: fur\n"
 | 
			
		||||
@@ -2491,7 +2491,7 @@ msgstr "Inviade"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/util/util-i18n.vala:280
 | 
			
		||||
 msgid "Starred"
 | 
			
		||||
-msgstr "Preferidis"
 | 
			
		||||
+msgstr "Preferide"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/util/util-i18n.vala:283
 | 
			
		||||
 msgid "Important"
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
From e957f0f8a7310950d36837b9945a09ad7a97e63c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Fabio Tomat <f.t.public@gmail.com>
 | 
			
		||||
Date: Tue, 15 Sep 2020 06:56:54 +0000
 | 
			
		||||
Subject: [PATCH 013/124] Update Friulian translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/fur.po | 4 ++--
 | 
			
		||||
 1 file changed, 2 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/fur.po b/po/fur.po
 | 
			
		||||
index d13465ba..b5e17eec 100644
 | 
			
		||||
--- a/po/fur.po
 | 
			
		||||
+++ b/po/fur.po
 | 
			
		||||
@@ -8,7 +8,7 @@ msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary master\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
 "POT-Creation-Date: 2020-09-14 19:33+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-09-15 07:51+0200\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-09-15 08:56+0200\n"
 | 
			
		||||
 "Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
 | 
			
		||||
 "Language-Team: Friulian <fur@li.org>\n"
 | 
			
		||||
 "Language: fur\n"
 | 
			
		||||
@@ -1181,7 +1181,7 @@ msgstr "Si lavore fûr rêt"
 | 
			
		||||
 #: src/client/application/application-main-window.vala:542
 | 
			
		||||
 msgid "You will not be able to send or receive email until re-connected."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
-"No tu podarâs inviâ o ricevi e-mail fintremai che no tu tornarâs a coneti."
 | 
			
		||||
+"No tu podarâs inviâ o ricevi e-mail fintremai che no tu ti tornarâs a coneti."
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar status label
 | 
			
		||||
 #: src/client/application/application-main-window.vala:549
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3505
									
								
								mail-client/geary/files/0014-Update-Croatian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3505
									
								
								mail-client/geary/files/0014-Update-Croatian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2893
									
								
								mail-client/geary/files/0015-Update-Croatian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2893
									
								
								mail-client/geary/files/0015-Update-Croatian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3209
									
								
								mail-client/geary/files/0016-Update-Slovak-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3209
									
								
								mail-client/geary/files/0016-Update-Slovak-translation.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										276
									
								
								mail-client/geary/files/0017-Update-Slovak-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								mail-client/geary/files/0017-Update-Slovak-translation.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,276 @@
 | 
			
		||||
From 5942e30377f7e47abe60236ceac100384bf74add Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Du=C5=A1an=20Kazik?= <prescott66@gmail.com>
 | 
			
		||||
Date: Mon, 21 Sep 2020 11:52:17 +0000
 | 
			
		||||
Subject: [PATCH 017/124] Update Slovak translation
 | 
			
		||||
 | 
			
		||||
(cherry picked from commit 2028c9dea3f1d8f6c5dcfdd44f5f1990121e0983)
 | 
			
		||||
---
 | 
			
		||||
 po/sk.po | 71 ++++++++++++++++++++++++++------------------------------
 | 
			
		||||
 1 file changed, 33 insertions(+), 38 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/sk.po b/po/sk.po
 | 
			
		||||
index 8fc3e1f4..dc0138c2 100644
 | 
			
		||||
--- a/po/sk.po
 | 
			
		||||
+++ b/po/sk.po
 | 
			
		||||
@@ -10,8 +10,8 @@ msgid ""
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary-0.4.1\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
-"POT-Creation-Date: 2020-08-29 01:59+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-09-16 13:28+0200\n"
 | 
			
		||||
+"POT-Creation-Date: 2020-09-19 08:49+0000\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-09-21 13:51+0200\n"
 | 
			
		||||
 "Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
 | 
			
		||||
 "Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
 | 
			
		||||
 "Language: sk\n"
 | 
			
		||||
@@ -212,6 +212,8 @@ msgstr "Automaticky vybrať ďalšiu správu"
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:63
 | 
			
		||||
 msgid "True if we should autoselect the next available conversation."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Nastavte na True, ak by sme mali automaticky vybrať nasledujúci dostupný "
 | 
			
		||||
+"rozhovor."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:68
 | 
			
		||||
 msgid "Display message previews"
 | 
			
		||||
@@ -219,7 +221,7 @@ msgstr "Zobraziť náhľady správ"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:69
 | 
			
		||||
 msgid "True if we should display a short preview of each message."
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Nastavte na True, ak by sme mali zobraziť krátky náhľad každej správy."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:74
 | 
			
		||||
 msgid "Use single key shortcuts"
 | 
			
		||||
@@ -261,7 +263,7 @@ msgstr "Nastavením na True, bude oznamovaná nová pošta po spustení."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:102
 | 
			
		||||
 msgid "Ask when opening an attachment"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Opýtať sa pri otváraní prílohy"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:103
 | 
			
		||||
 msgid "True to ask when opening an attachment."
 | 
			
		||||
@@ -290,7 +292,7 @@ msgstr "Priblíženie prehliadača konverzácií"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:121
 | 
			
		||||
 msgid "The zoom to apply on the conservation view."
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Priblíženie, ktoré sa má použiť pre zobrazenie rozhovorov."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:126
 | 
			
		||||
 msgid "Size of detached composer window"
 | 
			
		||||
@@ -298,7 +300,7 @@ msgstr "Veľkosť odpojeného okna tvorcu správ"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:127
 | 
			
		||||
 msgid "The last recorded size of the detached composer window."
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Posledná zaznamenaná veľkosť odpojeného okna tvorcu správ."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:132
 | 
			
		||||
 msgid "Undo sending email delay"
 | 
			
		||||
@@ -314,13 +316,15 @@ msgstr ""
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:139
 | 
			
		||||
 msgid "Brief notification display time"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Doba zobrazenia stručného oznámenia"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:140
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "The length of time in seconds for which brief notifications should be "
 | 
			
		||||
 "displayed."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
+"Dĺžka trvania v sekundách, počas ktorého by mali byť zobrazované stručné "
 | 
			
		||||
+"oznámenia."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:146
 | 
			
		||||
 msgid "List of optional plugins"
 | 
			
		||||
@@ -958,13 +962,13 @@ msgstr "Dušan Kazik <prescott66@gmail.com>"
 | 
			
		||||
 
 | 
			
		||||
 #. / Warning printed to the console when a deprecated
 | 
			
		||||
 #. / command line option is used.
 | 
			
		||||
-#: src/client/application/application-client.vala:1047
 | 
			
		||||
+#: src/client/application/application-client.vala:1045
 | 
			
		||||
 msgid "The `--hidden` option is deprecated and will be removed in the future."
 | 
			
		||||
 msgstr "Voľba „--hidden“ je zastaraná a bude v budúcnosti odstránená."
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line warning, string substitution
 | 
			
		||||
 #. / is the given argument
 | 
			
		||||
-#: src/client/application/application-client.vala:1080
 | 
			
		||||
+#: src/client/application/application-client.vala:1078
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Unrecognised program argument: “%s”"
 | 
			
		||||
 msgstr "Nerozpoznaný parameter programu: „%s“"
 | 
			
		||||
@@ -1140,21 +1144,21 @@ msgstr ""
 | 
			
		||||
 #: src/client/application/application-controller.vala:1501
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email sent to %s"
 | 
			
		||||
-msgstr "Email pre %s bol odoslaný"
 | 
			
		||||
+msgstr "Email pre príjemcu %s bol odoslaný"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: The label for an in-app notification. The
 | 
			
		||||
 #. / string substitution is a list of recipients of the email.
 | 
			
		||||
 #: src/client/application/application-controller.vala:2491
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email to %s queued for delivery"
 | 
			
		||||
-msgstr "Email pre %s bol zaradený do fronty na doručenie"
 | 
			
		||||
+msgstr "Email pre príjemcu %s bol zaradený do fronty na doručenie"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: The label for an in-app notification. The
 | 
			
		||||
 #. / string substitution is a list of recipients of the email.
 | 
			
		||||
 #: src/client/application/application-controller.vala:2555
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email to %s saved"
 | 
			
		||||
-msgstr "Email pre %s bol uložený"
 | 
			
		||||
+msgstr "Email pre príjemcu %s bol uložený"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: A label for an in-app notification.
 | 
			
		||||
 #: src/client/application/application-controller.vala:2570
 | 
			
		||||
@@ -1167,7 +1171,7 @@ msgstr "Nepodarilo sa obnoviť tvorcu správ"
 | 
			
		||||
 #: src/client/application/application-controller.vala:2613
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email to %s discarded"
 | 
			
		||||
-msgstr "Email pre %s bol zahodený"
 | 
			
		||||
+msgstr "Email pre príjemcu %s bol zahodený"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar status label
 | 
			
		||||
 #: src/client/application/application-main-window.vala:540
 | 
			
		||||
@@ -1334,7 +1338,7 @@ msgstr "Uložiť ako"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/components/components-inspector.vala:230
 | 
			
		||||
 #: src/client/dialogs/dialogs-problem-details-dialog.vala:224
 | 
			
		||||
-#: ui/accounts_editor_servers_pane.ui:17
 | 
			
		||||
+#: ui/accounts_editor_servers_pane.ui:17 ui/composer-headerbar.ui:61
 | 
			
		||||
 msgid "Cancel"
 | 
			
		||||
 msgstr "Zrušiť"
 | 
			
		||||
 
 | 
			
		||||
@@ -2185,7 +2189,6 @@ msgstr "Vytvára opakovane použiteľné šablóny na odosielanie emailov"
 | 
			
		||||
 #. included.
 | 
			
		||||
 #: src/client/plugin/email-templates/email-templates.vala:29
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.vala:29
 | 
			
		||||
-#| msgid "Sent | Sent Mail | Sent Email | Sent E-Mail"
 | 
			
		||||
 msgid "Templates | Template Mail | Template Email | Template E-Mail"
 | 
			
		||||
 msgstr "Šablóny | Poštová šablóna | Šablóna emailu | Šablóna e-mailu"
 | 
			
		||||
 
 | 
			
		||||
@@ -2195,11 +2198,12 @@ msgstr "Šablóny | Poštová šablóna | Šablóna emailu | Šablóna e-mailu"
 | 
			
		||||
 msgid "Templates"
 | 
			
		||||
 msgstr "Šablóny"
 | 
			
		||||
 
 | 
			
		||||
+# DK: šablóna
 | 
			
		||||
 #. Translators: Info bar button label for creating a
 | 
			
		||||
 #. new email template
 | 
			
		||||
 #: src/client/plugin/email-templates/email-templates.vala:282
 | 
			
		||||
 msgid "New"
 | 
			
		||||
-msgstr "Nový"
 | 
			
		||||
+msgstr "Nová"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Infobar status label for an email template
 | 
			
		||||
 #: src/client/plugin/email-templates/email-templates.vala:293
 | 
			
		||||
@@ -2233,11 +2237,11 @@ msgstr "Upraviť"
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.vala:389
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.vala:488
 | 
			
		||||
 msgid "Mail Merge"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Zlúčenie pošty"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.plugin.desktop.in:6
 | 
			
		||||
 msgid "Fill in and send email templates using a spreadsheet"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Vyplní šablóny emailov na odoslanie pomocou tabuľkového súboru"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Info bar label for starting sending a mail
 | 
			
		||||
 #. merge
 | 
			
		||||
@@ -2258,21 +2262,21 @@ msgstr "Pozastaviť"
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Sent %u of %u"
 | 
			
		||||
 msgid_plural "Sent %u of %u"
 | 
			
		||||
-msgstr[0] ""
 | 
			
		||||
-msgstr[1] ""
 | 
			
		||||
-msgstr[2] ""
 | 
			
		||||
+msgstr[0] "Odoslaných %u emailov z %u"
 | 
			
		||||
+msgstr[1] "Odoslaný %u email z %u"
 | 
			
		||||
+msgstr[2] "Odoslané %u emaily z %u"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Infobar status label for an email mail merge
 | 
			
		||||
 #. template
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.vala:324
 | 
			
		||||
 msgid "Mail merge template"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Šablóna pre zlúčenie pošty"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Info bar button label for performing a
 | 
			
		||||
 #. mail-merge on an email template
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.vala:328
 | 
			
		||||
 msgid "Merge"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Zlúčiť"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Action bar menu button label for
 | 
			
		||||
 #. / mail-merge plugin
 | 
			
		||||
@@ -2290,10 +2294,8 @@ msgid "Messaging Menu"
 | 
			
		||||
 msgstr "Ponuka správ"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/plugin/messaging-menu/messaging-menu.plugin.desktop.in:5
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "Show notifications for new mail"
 | 
			
		||||
 msgid "Displays Unity Messaging Menu notifications for new email"
 | 
			
		||||
-msgstr "Zobraziť upozornenia pre novú poštu"
 | 
			
		||||
+msgstr "Zobrazí oznámenia pre novú poštu v ponuke správ prostredia Unity"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/plugin/messaging-menu/messaging-menu.vala:79
 | 
			
		||||
 #, c-format
 | 
			
		||||
@@ -2301,14 +2303,12 @@ msgid "%s — New Messages"
 | 
			
		||||
 msgstr "%s — Nové správy"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/plugin/sent-sound/sent-sound.plugin.desktop.in:4
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "not found"
 | 
			
		||||
 msgid "Sent Sound"
 | 
			
		||||
-msgstr "nenájdené"
 | 
			
		||||
+msgstr "Zvuk po odoslaní"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/plugin/sent-sound/sent-sound.plugin.desktop.in:5
 | 
			
		||||
 msgid "Plays the desktop sent-mail sound when an email is sent"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Prehrá systémový zvuk po odoslaní emailu"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Info bar button label for emptying
 | 
			
		||||
 #. trash/spam folders
 | 
			
		||||
@@ -3190,7 +3190,7 @@ msgstr "Prepne pridávanie nových položiek záznamu"
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #: ui/components-inspector.ui:55
 | 
			
		||||
 msgid "Add a marker entry to the log"
 | 
			
		||||
-msgstr ""
 | 
			
		||||
+msgstr "Pridá značku do záznamu"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
@@ -3237,10 +3237,8 @@ msgstr "Vždy načítať vzdialené obrázky"
 | 
			
		||||
 
 | 
			
		||||
 #. Title label on contact popover
 | 
			
		||||
 #: ui/conversation-contact-popover.ui:264
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgid "Remove email address"
 | 
			
		||||
 msgid "Deceptive email address"
 | 
			
		||||
-msgstr "Odstráni emailové adresy"
 | 
			
		||||
+msgstr "Podvodná emailová adresa"
 | 
			
		||||
 
 | 
			
		||||
 #. Contact popover label
 | 
			
		||||
 #: ui/conversation-contact-popover.ui:294
 | 
			
		||||
@@ -3662,12 +3660,9 @@ msgid "Unquote text"
 | 
			
		||||
 msgstr "Zrušenie citácie textu"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:464
 | 
			
		||||
-#, fuzzy
 | 
			
		||||
-#| msgctxt "shortcut window"
 | 
			
		||||
-#| msgid "Rich text mode"
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
 msgid "Rich text editing"
 | 
			
		||||
-msgstr "Formátovanie textu"
 | 
			
		||||
+msgstr "Úprava formátovaného textu"
 | 
			
		||||
 
 | 
			
		||||
 #: ui/gtk/help-overlay.ui:468
 | 
			
		||||
 msgctxt "shortcut window"
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
From 571c10add8f8b0ad33031935f5de1bd6ff6fed2b Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Daniel Mustieles <daniel.mustieles@gmail.com>
 | 
			
		||||
Date: Wed, 23 Sep 2020 09:26:43 +0200
 | 
			
		||||
Subject: [PATCH 018/124] Updated Spanish translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/es.po | 16 ++++++++--------
 | 
			
		||||
 1 file changed, 8 insertions(+), 8 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/es.po b/po/es.po
 | 
			
		||||
index c387333b..fc6a4f53 100644
 | 
			
		||||
--- a/po/es.po
 | 
			
		||||
+++ b/po/es.po
 | 
			
		||||
@@ -18,8 +18,8 @@ msgid ""
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary-0.4.1\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
-"POT-Creation-Date: 2020-08-29 01:59+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-08-26 10:09+0200\n"
 | 
			
		||||
+"POT-Creation-Date: 2020-09-21 11:52+0000\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-09-23 09:16+0200\n"
 | 
			
		||||
 "Last-Translator: Daniel Mustieles <daniel.mustieles@gmail.com>\n"
 | 
			
		||||
 "Language-Team: Spanish - Spain <gnome-es-list@gnome.org>\n"
 | 
			
		||||
 "Language: es_ES\n"
 | 
			
		||||
@@ -27,7 +27,7 @@ msgstr ""
 | 
			
		||||
 "Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
 "Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
-"X-Generator: Gtranslator 3.36.0\n"
 | 
			
		||||
+"X-Generator: Gtranslator 3.38.0\n"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/geary-attach.contract.desktop.in:3
 | 
			
		||||
 msgid "Send by email"
 | 
			
		||||
@@ -982,13 +982,13 @@ msgstr ""
 | 
			
		||||
 
 | 
			
		||||
 #. / Warning printed to the console when a deprecated
 | 
			
		||||
 #. / command line option is used.
 | 
			
		||||
-#: src/client/application/application-client.vala:1047
 | 
			
		||||
+#: src/client/application/application-client.vala:1045
 | 
			
		||||
 msgid "The `--hidden` option is deprecated and will be removed in the future."
 | 
			
		||||
 msgstr "La opción «--hidden» está obsoleta y se eliminará en el futuro."
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line warning, string substitution
 | 
			
		||||
 #. / is the given argument
 | 
			
		||||
-#: src/client/application/application-client.vala:1080
 | 
			
		||||
+#: src/client/application/application-client.vala:1078
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Unrecognised program argument: “%s”"
 | 
			
		||||
 msgstr "Opción de la línea de comandos no reconocida: «%s»"
 | 
			
		||||
@@ -1345,7 +1345,7 @@ msgstr "Guardar como"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/components/components-inspector.vala:230
 | 
			
		||||
 #: src/client/dialogs/dialogs-problem-details-dialog.vala:224
 | 
			
		||||
-#: ui/accounts_editor_servers_pane.ui:17
 | 
			
		||||
+#: ui/accounts_editor_servers_pane.ui:17 ui/composer-headerbar.ui:61
 | 
			
		||||
 msgid "Cancel"
 | 
			
		||||
 msgstr "Cancelar"
 | 
			
		||||
 
 | 
			
		||||
@@ -2248,11 +2248,11 @@ msgstr "Pausar"
 | 
			
		||||
 #. folder. The first string substitution the number of email
 | 
			
		||||
 #. already sent, the second is the total number to send.
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.vala:240
 | 
			
		||||
-#, fuzzy, c-format
 | 
			
		||||
+#, c-format
 | 
			
		||||
 #| msgid "Sent %u of %u"
 | 
			
		||||
 msgid "Sent %u of %u"
 | 
			
		||||
 msgid_plural "Sent %u of %u"
 | 
			
		||||
-msgstr[0] "Enviados %u de %u"
 | 
			
		||||
+msgstr[0] "Enviado %u de %u"
 | 
			
		||||
 msgstr[1] "Enviados %u de %u"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Infobar status label for an email mail merge
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
From 7f7c55e79a0ec40ec3fae5c86568e4c1b6cc37df Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 25 Sep 2020 08:25:34 +1000
 | 
			
		||||
Subject: [PATCH 020/124] Application.CertificateManager: Fix critical when no
 | 
			
		||||
 GCR trust stores
 | 
			
		||||
 | 
			
		||||
Ensure GCR store not null before accessing it.
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-certificate-manager.vala | 6 ++++--
 | 
			
		||||
 1 file changed, 4 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-certificate-manager.vala b/src/client/application/application-certificate-manager.vala
 | 
			
		||||
index ff0e7785..d9e40fcd 100644
 | 
			
		||||
--- a/src/client/application/application-certificate-manager.vala
 | 
			
		||||
+++ b/src/client/application/application-certificate-manager.vala
 | 
			
		||||
@@ -74,8 +74,10 @@ public class Application.CertificateManager : GLib.Object {
 | 
			
		||||
         bool has_rw_store = false;
 | 
			
		||||
         if (has_uris) {
 | 
			
		||||
             Gck.Slot? store = Gcr.pkcs11_get_trust_store_slot();
 | 
			
		||||
-            has_rw_store = !store.has_flags(CKF_WRITE_PROTECTED);
 | 
			
		||||
-            debug("GCR store is R/W: %s", has_rw_store.to_string());
 | 
			
		||||
+            if (store != null) {
 | 
			
		||||
+                has_rw_store = !store.has_flags(CKF_WRITE_PROTECTED);
 | 
			
		||||
+                debug("GCR store is R/W: %s", has_rw_store.to_string());
 | 
			
		||||
+            }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         return has_rw_store;
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
From 0475d29f84ef13861fdc5ee2e747c00644c002fc Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 25 Sep 2020 08:27:36 +1000
 | 
			
		||||
Subject: [PATCH 021/124] Application.CertificateManager: Warn when GCR not
 | 
			
		||||
 able to access stores
 | 
			
		||||
 | 
			
		||||
At least let people know somehow their GCR setup is lacking.
 | 
			
		||||
---
 | 
			
		||||
 .../application-certificate-manager.vala           | 14 +++++++++++++-
 | 
			
		||||
 1 file changed, 13 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-certificate-manager.vala b/src/client/application/application-certificate-manager.vala
 | 
			
		||||
index d9e40fcd..3add2206 100644
 | 
			
		||||
--- a/src/client/application/application-certificate-manager.vala
 | 
			
		||||
+++ b/src/client/application/application-certificate-manager.vala
 | 
			
		||||
@@ -68,7 +68,13 @@ public class Application.CertificateManager : GLib.Object {
 | 
			
		||||
                 !Geary.String.is_empty(Gcr.pkcs11_get_trust_store_uri()) &&
 | 
			
		||||
                 Gcr.pkcs11_get_trust_lookup_uris().length > 0
 | 
			
		||||
             );
 | 
			
		||||
-            debug("GCR slot URIs found: %s", has_uris.to_string());
 | 
			
		||||
+            if (has_uris) {
 | 
			
		||||
+                debug("GCR slot URIs found: %s", has_uris.to_string());
 | 
			
		||||
+            } else {
 | 
			
		||||
+                warning(
 | 
			
		||||
+                    "No GCR slot URIs found, GCR certificate pinning unavailable"
 | 
			
		||||
+                );
 | 
			
		||||
+            }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         bool has_rw_store = false;
 | 
			
		||||
@@ -77,6 +83,12 @@ public class Application.CertificateManager : GLib.Object {
 | 
			
		||||
             if (store != null) {
 | 
			
		||||
                 has_rw_store = !store.has_flags(CKF_WRITE_PROTECTED);
 | 
			
		||||
                 debug("GCR store is R/W: %s", has_rw_store.to_string());
 | 
			
		||||
+            } else {
 | 
			
		||||
+                warning("No GCR store found, GCR certificate pinning unavailable");
 | 
			
		||||
+            }
 | 
			
		||||
+
 | 
			
		||||
+            if (!has_rw_store) {
 | 
			
		||||
+                warning("GCR store is not RW, GCR certificate pinning unavailable");
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
From 2093aa32292e11455648d62d8b7a992532aac04e Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 23 Sep 2020 08:44:04 +1000
 | 
			
		||||
Subject: [PATCH 022/124] Geary.Imap.Session: Avoid critical when client
 | 
			
		||||
 session logged out
 | 
			
		||||
 | 
			
		||||
If the client session is being logging out but some other tasks is
 | 
			
		||||
still attempting to use it, getting a mailbox will assume at least
 | 
			
		||||
one personal namespace exists, but it will have been cleared.
 | 
			
		||||
 | 
			
		||||
Add a check and throw an exception if none are present, so at least
 | 
			
		||||
it is handled in a well defined way.
 | 
			
		||||
 | 
			
		||||
Fixes #986
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap/transport/imap-client-session.vala | 3 +++
 | 
			
		||||
 1 file changed, 3 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap/transport/imap-client-session.vala b/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
index f42112f2..81d892ef 100644
 | 
			
		||||
--- a/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
+++ b/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
@@ -599,6 +599,9 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
             }
 | 
			
		||||
             if (ns == null) {
 | 
			
		||||
                 // fall back to the default personal namespace
 | 
			
		||||
+                if (this.personal_namespaces.is_empty) {
 | 
			
		||||
+                    throw new ImapError.UNAVAILABLE("No personal namespace");
 | 
			
		||||
+                }
 | 
			
		||||
                 ns = this.personal_namespaces[0];
 | 
			
		||||
             }
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
From 1c951f890840b91885d5f3752bb8bc3fdfc26324 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 23 Sep 2020 08:48:45 +1000
 | 
			
		||||
Subject: [PATCH 023/124] Geary.Imap.SessionObject: Ensure the session is
 | 
			
		||||
 connected when accessed
 | 
			
		||||
 | 
			
		||||
Ensure the client session is connected as well as non-null when being
 | 
			
		||||
accessed, so that if being logged out it is also treated as being
 | 
			
		||||
disconnected.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap/api/imap-session-object.vala | 16 ++++++++++------
 | 
			
		||||
 1 file changed, 10 insertions(+), 6 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-session-object.vala b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
index 4937d462..ee1ac09f 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
@@ -83,16 +83,20 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
-     * Obtains IMAP session the server for use by this object.
 | 
			
		||||
+     * Returns a valid IMAP client session for use by this object.
 | 
			
		||||
      *
 | 
			
		||||
-     * @throws ImapError.NOT_CONNECTED if the session with the server
 | 
			
		||||
-     * server has been dropped via {@link close}, or because
 | 
			
		||||
-     * the connection was lost.
 | 
			
		||||
+     * @throws ImapError.NOT_CONNECTED if the client session has been
 | 
			
		||||
+     * dropped via {@link close}, if the client session is logging out
 | 
			
		||||
+     * or has been closed, or because the connection to the server was
 | 
			
		||||
+     * lost.
 | 
			
		||||
      */
 | 
			
		||||
     protected ClientSession claim_session()
 | 
			
		||||
         throws ImapError {
 | 
			
		||||
-        if (this.session == null) {
 | 
			
		||||
-            throw new ImapError.NOT_CONNECTED("IMAP object has no session");
 | 
			
		||||
+        if (this.session == null ||
 | 
			
		||||
+            this.session.get_protocol_state() == NOT_CONNECTED) {
 | 
			
		||||
+            throw new ImapError.NOT_CONNECTED(
 | 
			
		||||
+                "IMAP object has no session or is not connected"
 | 
			
		||||
+            );
 | 
			
		||||
         }
 | 
			
		||||
         return this.session;
 | 
			
		||||
     }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,101 @@
 | 
			
		||||
From b209f84e5895d7ae3b9ca200f36343d162914932 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 23 Sep 2020 09:11:50 +1000
 | 
			
		||||
Subject: [PATCH 024/124] Geary.Imap.FolderSession: Ensure client session is
 | 
			
		||||
 selected when accessed
 | 
			
		||||
 | 
			
		||||
Ensure the underlying ClientSession object is in the SELECTED state
 | 
			
		||||
for the correct mailbox when obtaining it.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap/api/imap-folder-session.vala | 31 ++++++++++++++++----
 | 
			
		||||
 src/engine/imap/api/imap-session-object.vala |  2 +-
 | 
			
		||||
 2 files changed, 26 insertions(+), 7 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
index 092c06cd..98db3088 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
@@ -38,6 +38,8 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
     /** Determines if this folder accepts custom IMAP flags. */
 | 
			
		||||
     public Trillian accepts_user_flags { get; private set; default = Trillian.UNKNOWN; }
 | 
			
		||||
 
 | 
			
		||||
+    private MailboxSpecifier mailbox;
 | 
			
		||||
+
 | 
			
		||||
     private Quirks quirks;
 | 
			
		||||
 
 | 
			
		||||
     private Nonblocking.Mutex cmd_mutex = new Nonblocking.Mutex();
 | 
			
		||||
@@ -107,9 +109,9 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
         session.search.connect(on_search);
 | 
			
		||||
         session.status_response_received.connect(on_status_response);
 | 
			
		||||
 
 | 
			
		||||
-        MailboxSpecifier mailbox = session.get_mailbox_for_path(folder.path);
 | 
			
		||||
+        this.mailbox = session.get_mailbox_for_path(folder.path);
 | 
			
		||||
         StatusResponse? response = yield session.select_async(
 | 
			
		||||
-            mailbox, cancellable
 | 
			
		||||
+            this.mailbox, cancellable
 | 
			
		||||
         );
 | 
			
		||||
         throw_on_not_ok(response, "SELECT " + this.folder.path.to_string());
 | 
			
		||||
 
 | 
			
		||||
@@ -1107,8 +1109,6 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
                                                            Geary.EmailFlags? flags,
 | 
			
		||||
                                                            GLib.DateTime? date_received)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
-
 | 
			
		||||
         MessageFlags? msg_flags = null;
 | 
			
		||||
         if (flags != null) {
 | 
			
		||||
             Imap.EmailFlags imap_flags = Imap.EmailFlags.from_api_email_flags(flags);
 | 
			
		||||
@@ -1121,9 +1121,8 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
         if (date_received != null)
 | 
			
		||||
             internaldate = new InternalDate.from_date_time(date_received);
 | 
			
		||||
 
 | 
			
		||||
-        MailboxSpecifier mailbox = session.get_mailbox_for_path(this.folder.path);
 | 
			
		||||
         AppendCommand cmd = new AppendCommand(
 | 
			
		||||
-            mailbox,
 | 
			
		||||
+            this.mailbox,
 | 
			
		||||
             msg_flags,
 | 
			
		||||
             internaldate,
 | 
			
		||||
             message.get_rfc822_buffer(),
 | 
			
		||||
@@ -1161,6 +1160,26 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Returns a valid IMAP client session for use by this object.
 | 
			
		||||
+     *
 | 
			
		||||
+     * In addition to the checks made by {@link
 | 
			
		||||
+     * SessionObject.claim_session}, this method also ensures that the
 | 
			
		||||
+     * IMAP session is in the SELECTED state for the correct mailbox.
 | 
			
		||||
+     */
 | 
			
		||||
+    protected override ClientSession claim_session()
 | 
			
		||||
+        throws ImapError {
 | 
			
		||||
+        var session = base.claim_session();
 | 
			
		||||
+        if (session.get_protocol_state() != SELECTED &&
 | 
			
		||||
+            !this.mailbox.equal_to(session.selected_mailbox)) {
 | 
			
		||||
+            throw new ImapError.NOT_CONNECTED(
 | 
			
		||||
+                "IMAP object no longer SELECTED for %s",
 | 
			
		||||
+                this.mailbox.to_string()
 | 
			
		||||
+            );
 | 
			
		||||
+        }
 | 
			
		||||
+        return session;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     // HACK: See https://bugzilla.gnome.org/show_bug.cgi?id=714902
 | 
			
		||||
     //
 | 
			
		||||
     // Detect when a server has returned a BAD response to FETCH
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-session-object.vala b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
index ee1ac09f..d47c6950 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
@@ -90,7 +90,7 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
 | 
			
		||||
      * or has been closed, or because the connection to the server was
 | 
			
		||||
      * lost.
 | 
			
		||||
      */
 | 
			
		||||
-    protected ClientSession claim_session()
 | 
			
		||||
+    protected virtual ClientSession claim_session()
 | 
			
		||||
         throws ImapError {
 | 
			
		||||
         if (this.session == null ||
 | 
			
		||||
             this.session.get_protocol_state() == NOT_CONNECTED) {
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,134 @@
 | 
			
		||||
From ac425f57b134c2264723e20ea15319ab615f0f9d Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 23 Sep 2020 09:17:28 +1000
 | 
			
		||||
Subject: [PATCH 025/124] Geary.Imap.SessionObject: Rename `claim_session` to
 | 
			
		||||
 `get_session`
 | 
			
		||||
 | 
			
		||||
Don't over-sell what it does.
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap/api/imap-account-session.vala | 10 +++++-----
 | 
			
		||||
 src/engine/imap/api/imap-folder-session.vala  | 14 +++++++-------
 | 
			
		||||
 src/engine/imap/api/imap-session-object.vala  |  2 +-
 | 
			
		||||
 3 files changed, 13 insertions(+), 13 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-account-session.vala b/src/engine/imap/api/imap-account-session.vala
 | 
			
		||||
index 238bd85c..813d9e5e 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-account-session.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-account-session.vala
 | 
			
		||||
@@ -45,7 +45,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
 | 
			
		||||
      */
 | 
			
		||||
     public async FolderPath get_default_personal_namespace(Cancellable? cancellable)
 | 
			
		||||
     throws Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
         Gee.List<Namespace> personal = session.get_personal_namespaces();
 | 
			
		||||
         if (personal.is_empty) {
 | 
			
		||||
             throw new ImapError.INVALID("No personal namespace found");
 | 
			
		||||
@@ -69,7 +69,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
 | 
			
		||||
     public bool is_folder_path_valid(FolderPath? path) throws GLib.Error {
 | 
			
		||||
         bool is_valid = false;
 | 
			
		||||
         if (path != null) {
 | 
			
		||||
-            ClientSession session = claim_session();
 | 
			
		||||
+            ClientSession session = get_session();
 | 
			
		||||
             try {
 | 
			
		||||
                 session.get_mailbox_for_path(path);
 | 
			
		||||
                 is_valid = true;
 | 
			
		||||
@@ -94,7 +94,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
 | 
			
		||||
                                           Geary.Folder.SpecialUse? use,
 | 
			
		||||
                                           Cancellable? cancellable)
 | 
			
		||||
     throws Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
         MailboxSpecifier mailbox = session.get_mailbox_for_path(path);
 | 
			
		||||
         bool can_create_special = session.capabilities.has_capability(Capabilities.CREATE_SPECIAL_USE);
 | 
			
		||||
         CreateCommand cmd = (
 | 
			
		||||
@@ -125,7 +125,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
 | 
			
		||||
     public async Imap.Folder fetch_folder_async(FolderPath path,
 | 
			
		||||
                                                 Cancellable? cancellable)
 | 
			
		||||
         throws Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
         Imap.Folder? folder = this.folders.get(path);
 | 
			
		||||
         if (folder == null) {
 | 
			
		||||
             Gee.List<MailboxInformation>? mailboxes = yield send_list_async(
 | 
			
		||||
@@ -169,7 +169,7 @@ internal class Geary.Imap.AccountSession : Geary.Imap.SessionObject {
 | 
			
		||||
         fetch_child_folders_async(FolderPath parent,
 | 
			
		||||
                                   GLib.Cancellable? cancellable)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
         Gee.List<Imap.Folder> children = new Gee.ArrayList<Imap.Folder>();
 | 
			
		||||
         Gee.List<MailboxInformation> mailboxes = yield send_list_async(
 | 
			
		||||
             session, parent, true, cancellable
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
index 98db3088..8b4212e6 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
@@ -127,7 +127,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
      */
 | 
			
		||||
     public async void enable_idle(Cancellable? cancellable)
 | 
			
		||||
         throws Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
         int token = yield this.cmd_mutex.claim_async(cancellable);
 | 
			
		||||
         Error? cmd_err = null;
 | 
			
		||||
         try {
 | 
			
		||||
@@ -303,7 +303,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
                             Gee.Set<Imap.UID>? search_results,
 | 
			
		||||
                             GLib.Cancellable? cancellable)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
         Gee.Map<Command, StatusResponse>? responses = null;
 | 
			
		||||
         int token = yield this.cmd_mutex.claim_async(cancellable);
 | 
			
		||||
 
 | 
			
		||||
@@ -648,7 +648,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
     public async void remove_email_async(Gee.List<MessageSet> msg_sets,
 | 
			
		||||
                                          GLib.Cancellable? cancellable)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
         Gee.List<MessageFlag> flags = new Gee.ArrayList<MessageFlag>();
 | 
			
		||||
         flags.add(MessageFlag.DELETED);
 | 
			
		||||
 
 | 
			
		||||
@@ -721,7 +721,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
                                                      FolderPath destination,
 | 
			
		||||
                                                      GLib.Cancellable? cancellable)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        ClientSession session = claim_session();
 | 
			
		||||
+        ClientSession session = get_session();
 | 
			
		||||
 
 | 
			
		||||
         MailboxSpecifier mailbox = session.get_mailbox_for_path(destination);
 | 
			
		||||
         CopyCommand cmd = new CopyCommand(msg_set, mailbox, cancellable);
 | 
			
		||||
@@ -1164,12 +1164,12 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
      * Returns a valid IMAP client session for use by this object.
 | 
			
		||||
      *
 | 
			
		||||
      * In addition to the checks made by {@link
 | 
			
		||||
-     * SessionObject.claim_session}, this method also ensures that the
 | 
			
		||||
+     * SessionObject.get_session}, this method also ensures that the
 | 
			
		||||
      * IMAP session is in the SELECTED state for the correct mailbox.
 | 
			
		||||
      */
 | 
			
		||||
-    protected override ClientSession claim_session()
 | 
			
		||||
+    protected override ClientSession get_session()
 | 
			
		||||
         throws ImapError {
 | 
			
		||||
-        var session = base.claim_session();
 | 
			
		||||
+        var session = base.get_session();
 | 
			
		||||
         if (session.get_protocol_state() != SELECTED &&
 | 
			
		||||
             !this.mailbox.equal_to(session.selected_mailbox)) {
 | 
			
		||||
             throw new ImapError.NOT_CONNECTED(
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-session-object.vala b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
index d47c6950..4a46ae1e 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
@@ -90,7 +90,7 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
 | 
			
		||||
      * or has been closed, or because the connection to the server was
 | 
			
		||||
      * lost.
 | 
			
		||||
      */
 | 
			
		||||
-    protected virtual ClientSession claim_session()
 | 
			
		||||
+    protected virtual ClientSession get_session()
 | 
			
		||||
         throws ImapError {
 | 
			
		||||
         if (this.session == null ||
 | 
			
		||||
             this.session.get_protocol_state() == NOT_CONNECTED) {
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,154 @@
 | 
			
		||||
From ed4ba33127795a7ffefb6517ed57185ef44fe1c7 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sun, 27 Sep 2020 15:58:40 +1000
 | 
			
		||||
Subject: [PATCH 026/124] Geary.State.Machine: Support GObject notify signal
 | 
			
		||||
 for state changes
 | 
			
		||||
 | 
			
		||||
Modernise the API a bit by using properties instead of explicit
 | 
			
		||||
getters/setters, an hence support GObject notify signals when the
 | 
			
		||||
state property changes.
 | 
			
		||||
---
 | 
			
		||||
 .../imap/transport/imap-client-session.vala   |  9 ++---
 | 
			
		||||
 .../imap/transport/imap-deserializer.vala     |  4 +-
 | 
			
		||||
 src/engine/state/state-machine.vala           | 37 ++++++-------------
 | 
			
		||||
 3 files changed, 18 insertions(+), 32 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap/transport/imap-client-session.vala b/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
index 81d892ef..91137f1e 100644
 | 
			
		||||
--- a/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
+++ b/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
@@ -483,11 +483,10 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         };
 | 
			
		||||
 
 | 
			
		||||
         fsm = new Geary.State.Machine(machine_desc, mappings, on_ignored_transition);
 | 
			
		||||
-        fsm.set_logging(false);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     ~ClientSession() {
 | 
			
		||||
-        switch (fsm.get_state()) {
 | 
			
		||||
+        switch (fsm.state) {
 | 
			
		||||
             case State.NOT_CONNECTED:
 | 
			
		||||
             case State.CLOSED:
 | 
			
		||||
                 // no problem-o
 | 
			
		||||
@@ -782,7 +781,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
 
 | 
			
		||||
     private bool on_greeting_timeout() {
 | 
			
		||||
         // if still in CONNECTING state, the greeting never arrived
 | 
			
		||||
-        if (fsm.get_state() == State.CONNECTING)
 | 
			
		||||
+        if (fsm.state == State.CONNECTING)
 | 
			
		||||
             fsm.issue(Event.TIMEOUT);
 | 
			
		||||
 
 | 
			
		||||
         return false;
 | 
			
		||||
@@ -1645,12 +1644,12 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         return (this.selected_mailbox == null)
 | 
			
		||||
             ? new Logging.State(
 | 
			
		||||
                 this,
 | 
			
		||||
-                this.fsm.get_state_string(fsm.get_state())
 | 
			
		||||
+                this.fsm.get_state_string(fsm.state)
 | 
			
		||||
             )
 | 
			
		||||
             : new Logging.State(
 | 
			
		||||
                 this,
 | 
			
		||||
                 "%s:%s selected %s",
 | 
			
		||||
-                this.fsm.get_state_string(fsm.get_state()),
 | 
			
		||||
+                this.fsm.get_state_string(fsm.state),
 | 
			
		||||
                 this.selected_mailbox.to_string(),
 | 
			
		||||
                 this.selected_readonly ? "RO" : "RW"
 | 
			
		||||
             );
 | 
			
		||||
diff --git a/src/engine/imap/transport/imap-deserializer.vala b/src/engine/imap/transport/imap-deserializer.vala
 | 
			
		||||
index 249f7c85..559a5e78 100644
 | 
			
		||||
--- a/src/engine/imap/transport/imap-deserializer.vala
 | 
			
		||||
+++ b/src/engine/imap/transport/imap-deserializer.vala
 | 
			
		||||
@@ -294,7 +294,7 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
     public Logging.State to_logging_state() {
 | 
			
		||||
-        return new Logging.State(this, fsm.get_state_string(fsm.get_state()));
 | 
			
		||||
+        return new Logging.State(this, fsm.get_state_string(fsm.state));
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** Sets the connection's logging parent. */
 | 
			
		||||
@@ -429,7 +429,7 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private Mode get_mode() {
 | 
			
		||||
-        switch (fsm.get_state()) {
 | 
			
		||||
+        switch (fsm.state) {
 | 
			
		||||
             case State.LITERAL_DATA:
 | 
			
		||||
                 return Mode.BLOCK;
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/engine/state/state-machine.vala b/src/engine/state/state-machine.vala
 | 
			
		||||
index 351babb8..ef32555d 100644
 | 
			
		||||
--- a/src/engine/state/state-machine.vala
 | 
			
		||||
+++ b/src/engine/state/state-machine.vala
 | 
			
		||||
@@ -5,13 +5,20 @@
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
 public class Geary.State.Machine : BaseObject {
 | 
			
		||||
+
 | 
			
		||||
+    /** The state machine's current state. */
 | 
			
		||||
+    public uint state { get; private set; }
 | 
			
		||||
+
 | 
			
		||||
+    /** Determines if the state machine crashes your app when mis-configured. */
 | 
			
		||||
+    public bool abort_on_no_transition { get; set; default = true; }
 | 
			
		||||
+
 | 
			
		||||
+    /** Determines if transition logging is enabled. */
 | 
			
		||||
+    public bool logging { get; private set; default = false; }
 | 
			
		||||
+
 | 
			
		||||
     private Geary.State.MachineDescriptor descriptor;
 | 
			
		||||
-    private uint state;
 | 
			
		||||
     private Mapping[,] transitions;
 | 
			
		||||
     private unowned Transition? default_transition;
 | 
			
		||||
     private bool locked = false;
 | 
			
		||||
-    private bool abort_on_no_transition = true;
 | 
			
		||||
-    private bool logging = false;
 | 
			
		||||
     private unowned PostTransition? post_transition = null;
 | 
			
		||||
     private void *post_user = null;
 | 
			
		||||
     private Object? post_object = null;
 | 
			
		||||
@@ -39,26 +46,6 @@ public class Geary.State.Machine : BaseObject {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public uint get_state() {
 | 
			
		||||
-        return state;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    public bool get_abort_on_no_transition() {
 | 
			
		||||
-        return abort_on_no_transition;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    public void set_abort_on_no_transition(bool abort) {
 | 
			
		||||
-        abort_on_no_transition = abort;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    public void set_logging(bool logging) {
 | 
			
		||||
-        this.logging = logging;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    public bool is_logging() {
 | 
			
		||||
-        return logging;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     public uint issue(uint event, void *user = null, Object? object = null, Error? err = null) {
 | 
			
		||||
         assert(event < descriptor.event_count);
 | 
			
		||||
         assert(state < descriptor.state_count);
 | 
			
		||||
@@ -70,7 +57,7 @@ public class Geary.State.Machine : BaseObject {
 | 
			
		||||
             string msg = "%s: No transition defined for %s@%s".printf(to_string(),
 | 
			
		||||
                 descriptor.get_event_string(event), descriptor.get_state_string(state));
 | 
			
		||||
 
 | 
			
		||||
-            if (get_abort_on_no_transition())
 | 
			
		||||
+            if (this.abort_on_no_transition)
 | 
			
		||||
                 error(msg);
 | 
			
		||||
             else
 | 
			
		||||
                 critical(msg);
 | 
			
		||||
@@ -96,7 +83,7 @@ public class Geary.State.Machine : BaseObject {
 | 
			
		||||
         }
 | 
			
		||||
         locked = false;
 | 
			
		||||
 
 | 
			
		||||
-        if (is_logging())
 | 
			
		||||
+        if (this.logging)
 | 
			
		||||
             message("%s: %s", to_string(), get_transition_string(old_state, event, state));
 | 
			
		||||
 
 | 
			
		||||
         // Perform post-transition if registered
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,561 @@
 | 
			
		||||
From 41be8693d4481d6a50f49e3bf6698e9103d0bfa7 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sun, 27 Sep 2020 16:00:35 +1000
 | 
			
		||||
Subject: [PATCH 027/124] Geary.Imap.ClientSession: Treat logout as disconnect
 | 
			
		||||
 | 
			
		||||
Convert `get_protocol_state` to an automatic property, so that rather
 | 
			
		||||
than requiring explcit signals for lifecycle events, a GObject notify
 | 
			
		||||
signal can be used instead.
 | 
			
		||||
 | 
			
		||||
Convert disconnect signal to a property so it can be accessed if needed.
 | 
			
		||||
 | 
			
		||||
Convert code listening to the disconnect signal to listen to notify
 | 
			
		||||
signals for `protocol_state` instead, and hence also treat the session
 | 
			
		||||
as disconnected when a logout is in progress.
 | 
			
		||||
 | 
			
		||||
Fixes #986
 | 
			
		||||
---
 | 
			
		||||
 src/engine/imap/api/imap-client-service.vala  |  38 +++---
 | 
			
		||||
 src/engine/imap/api/imap-folder-session.vala  |   2 +-
 | 
			
		||||
 src/engine/imap/api/imap-session-object.vala  |  26 ++--
 | 
			
		||||
 .../imap/transport/imap-client-session.vala   | 118 ++++++++++--------
 | 
			
		||||
 .../transport/imap-client-session-test.vala   |  40 +++---
 | 
			
		||||
 test/integration/imap/client-session.vala     |   2 +-
 | 
			
		||||
 6 files changed, 130 insertions(+), 96 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-client-service.vala b/src/engine/imap/api/imap-client-service.vala
 | 
			
		||||
index e0aad41b..da3598f3 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-client-service.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-client-service.vala
 | 
			
		||||
@@ -252,7 +252,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
 | 
			
		||||
         if (!disconnect) {
 | 
			
		||||
             // If the session has a mailbox selected, close it before
 | 
			
		||||
             // adding it back to the pool
 | 
			
		||||
-            ClientSession.ProtocolState proto = session.get_protocol_state();
 | 
			
		||||
+            ClientSession.ProtocolState proto = session.protocol_state;
 | 
			
		||||
             if (proto == ClientSession.ProtocolState.SELECTED ||
 | 
			
		||||
                 proto == ClientSession.ProtocolState.SELECTING) {
 | 
			
		||||
                 // always close mailbox to return to authorized state
 | 
			
		||||
@@ -263,7 +263,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
 | 
			
		||||
                           session.to_string(), imap_error.message);
 | 
			
		||||
                     disconnect = true;
 | 
			
		||||
                 }
 | 
			
		||||
-                if (session.get_protocol_state() != AUTHORIZED) {
 | 
			
		||||
+                if (session.protocol_state != AUTHORIZED) {
 | 
			
		||||
                     // Closing it didn't leave it in the desired
 | 
			
		||||
                     // state, so drop it
 | 
			
		||||
                     disconnect = true;
 | 
			
		||||
@@ -393,7 +393,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
 | 
			
		||||
     /** Determines if a session is valid, disposing of it if not. */
 | 
			
		||||
     private async bool check_session(ClientSession target, bool claiming) {
 | 
			
		||||
         bool valid = false;
 | 
			
		||||
-        switch (target.get_protocol_state()) {
 | 
			
		||||
+        switch (target.protocol_state) {
 | 
			
		||||
         case ClientSession.ProtocolState.AUTHORIZED:
 | 
			
		||||
         case ClientSession.ProtocolState.CLOSING_MAILBOX:
 | 
			
		||||
             valid = true;
 | 
			
		||||
@@ -472,7 +472,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
 | 
			
		||||
 
 | 
			
		||||
         // Only bother tracking disconnects and enabling keeping alive
 | 
			
		||||
         // now the session is properly established.
 | 
			
		||||
-        new_session.disconnected.connect(on_disconnected);
 | 
			
		||||
+        new_session.notify["disconnected"].connect(on_session_disconnected);
 | 
			
		||||
         new_session.enable_keepalives(selected_keepalive_sec,
 | 
			
		||||
                                       unselected_keepalive_sec,
 | 
			
		||||
                                       selected_with_idle_keepalive_sec);
 | 
			
		||||
@@ -509,7 +509,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private async void disconnect_session(ClientSession session) {
 | 
			
		||||
-        if (session.get_protocol_state() != NOT_CONNECTED) {
 | 
			
		||||
+        if (session.protocol_state != NOT_CONNECTED) {
 | 
			
		||||
             debug("Logging out session: %s", session.to_string());
 | 
			
		||||
             // No need to remove it after logging out, the
 | 
			
		||||
             // disconnected handler will do that for us.
 | 
			
		||||
@@ -548,21 +548,27 @@ public class Geary.Imap.ClientService : Geary.ClientService {
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         if (removed) {
 | 
			
		||||
-            session.disconnected.disconnect(on_disconnected);
 | 
			
		||||
+            session.notify["disconnected"].connect(on_session_disconnected);
 | 
			
		||||
         }
 | 
			
		||||
         return removed;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_disconnected(ClientSession session,
 | 
			
		||||
-                                 ClientSession.DisconnectReason reason) {
 | 
			
		||||
-        debug(
 | 
			
		||||
-            "Session disconnected: %s: %s",
 | 
			
		||||
-            session.to_string(), reason.to_string()
 | 
			
		||||
-        );
 | 
			
		||||
-        this.remove_session_async.begin(
 | 
			
		||||
-            session,
 | 
			
		||||
-            (obj, res) => { this.remove_session_async.end(res); }
 | 
			
		||||
-        );
 | 
			
		||||
+    private void on_session_disconnected(GLib.Object source,
 | 
			
		||||
+                                         GLib.ParamSpec param) {
 | 
			
		||||
+        var session = source as ClientSession;
 | 
			
		||||
+        if (session != null &&
 | 
			
		||||
+            session.protocol_state == NOT_CONNECTED &&
 | 
			
		||||
+            session.disconnected != null) {
 | 
			
		||||
+            debug(
 | 
			
		||||
+                "Session disconnected: %s: %s",
 | 
			
		||||
+                session.to_string(),
 | 
			
		||||
+                session.disconnected.to_string()
 | 
			
		||||
+            );
 | 
			
		||||
+            this.remove_session_async.begin(
 | 
			
		||||
+                session,
 | 
			
		||||
+                (obj, res) => { this.remove_session_async.end(res); }
 | 
			
		||||
+            );
 | 
			
		||||
+        }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
index 8b4212e6..8a2290cb 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-folder-session.vala
 | 
			
		||||
@@ -1170,7 +1170,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
 | 
			
		||||
     protected override ClientSession get_session()
 | 
			
		||||
         throws ImapError {
 | 
			
		||||
         var session = base.get_session();
 | 
			
		||||
-        if (session.get_protocol_state() != SELECTED &&
 | 
			
		||||
+        if (session.protocol_state != SELECTED &&
 | 
			
		||||
             !this.mailbox.equal_to(session.selected_mailbox)) {
 | 
			
		||||
             throw new ImapError.NOT_CONNECTED(
 | 
			
		||||
                 "IMAP object no longer SELECTED for %s",
 | 
			
		||||
diff --git a/src/engine/imap/api/imap-session-object.vala b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
index 4a46ae1e..80695fca 100644
 | 
			
		||||
--- a/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
+++ b/src/engine/imap/api/imap-session-object.vala
 | 
			
		||||
@@ -39,7 +39,7 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
 | 
			
		||||
      */
 | 
			
		||||
     protected SessionObject(ClientSession session) {
 | 
			
		||||
         this.session = session;
 | 
			
		||||
-        this.session.disconnected.connect(on_disconnected);
 | 
			
		||||
+        this.session.notify["protocol-state"].connect(on_session_state_change);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     ~SessionObject() {
 | 
			
		||||
@@ -63,7 +63,9 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
 | 
			
		||||
         this.session = null;
 | 
			
		||||
 
 | 
			
		||||
         if (old_session != null) {
 | 
			
		||||
-            old_session.disconnected.disconnect(on_disconnected);
 | 
			
		||||
+            old_session.notify["protocol-state"].disconnect(
 | 
			
		||||
+                on_session_state_change
 | 
			
		||||
+            );
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         return old_session;
 | 
			
		||||
@@ -93,7 +95,7 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
 | 
			
		||||
     protected virtual ClientSession get_session()
 | 
			
		||||
         throws ImapError {
 | 
			
		||||
         if (this.session == null ||
 | 
			
		||||
-            this.session.get_protocol_state() == NOT_CONNECTED) {
 | 
			
		||||
+            this.session.protocol_state == NOT_CONNECTED) {
 | 
			
		||||
             throw new ImapError.NOT_CONNECTED(
 | 
			
		||||
                 "IMAP object has no session or is not connected"
 | 
			
		||||
             );
 | 
			
		||||
@@ -101,11 +103,19 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
 | 
			
		||||
         return this.session;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_disconnected(ClientSession.DisconnectReason reason) {
 | 
			
		||||
-        debug("Disconnected %s", reason.to_string());
 | 
			
		||||
-
 | 
			
		||||
-        close();
 | 
			
		||||
-        disconnected(reason);
 | 
			
		||||
+    private void on_session_state_change() {
 | 
			
		||||
+        if (this.session != null &&
 | 
			
		||||
+            this.session.protocol_state == NOT_CONNECTED) {
 | 
			
		||||
+            // Disconnect reason will null when the session is being
 | 
			
		||||
+            // logged out but the logout command has not yet been
 | 
			
		||||
+            // completed.
 | 
			
		||||
+            var reason = (
 | 
			
		||||
+                this.session.disconnected ??
 | 
			
		||||
+                ClientSession.DisconnectReason.LOCAL_CLOSE
 | 
			
		||||
+            );
 | 
			
		||||
+            close();
 | 
			
		||||
+            disconnected(reason);
 | 
			
		||||
+        }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/src/engine/imap/transport/imap-client-session.vala b/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
index 91137f1e..ba125616 100644
 | 
			
		||||
--- a/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
+++ b/src/engine/imap/transport/imap-client-session.vala
 | 
			
		||||
@@ -90,7 +90,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
      *
 | 
			
		||||
      * See [[http://tools.ietf.org/html/rfc3501#section-3]]
 | 
			
		||||
      *
 | 
			
		||||
-     * @see get_protocol_state
 | 
			
		||||
+     * @see protocol_state
 | 
			
		||||
      */
 | 
			
		||||
     public enum ProtocolState {
 | 
			
		||||
         NOT_CONNECTED,
 | 
			
		||||
@@ -230,6 +230,55 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         "Geary.Imap.ClientSession", State.NOT_CONNECTED, State.COUNT, Event.COUNT,
 | 
			
		||||
         state_to_string, event_to_string);
 | 
			
		||||
 
 | 
			
		||||
+
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Returns the current IMAP protocol state for the session.
 | 
			
		||||
+     */
 | 
			
		||||
+    public ProtocolState protocol_state {
 | 
			
		||||
+        get {
 | 
			
		||||
+            var state = ProtocolState.NOT_CONNECTED;
 | 
			
		||||
+            switch (fsm.state) {
 | 
			
		||||
+            case State.NOT_CONNECTED:
 | 
			
		||||
+            case State.LOGOUT:
 | 
			
		||||
+            case State.CLOSED:
 | 
			
		||||
+                state = NOT_CONNECTED;
 | 
			
		||||
+                break;
 | 
			
		||||
+
 | 
			
		||||
+            case State.NOAUTH:
 | 
			
		||||
+                state = UNAUTHORIZED;
 | 
			
		||||
+                break;
 | 
			
		||||
+
 | 
			
		||||
+            case State.AUTHORIZED:
 | 
			
		||||
+                state = AUTHORIZED;
 | 
			
		||||
+                break;
 | 
			
		||||
+
 | 
			
		||||
+            case State.SELECTED:
 | 
			
		||||
+                state = SELECTED;
 | 
			
		||||
+                break;
 | 
			
		||||
+
 | 
			
		||||
+            case State.CONNECTING:
 | 
			
		||||
+                state = CONNECTING;
 | 
			
		||||
+                break;
 | 
			
		||||
+
 | 
			
		||||
+            case State.AUTHORIZING:
 | 
			
		||||
+                state = AUTHORIZING;
 | 
			
		||||
+                break;
 | 
			
		||||
+
 | 
			
		||||
+            case State.SELECTING:
 | 
			
		||||
+                state = SELECTING;
 | 
			
		||||
+                break;
 | 
			
		||||
+
 | 
			
		||||
+            case State.CLOSING_MAILBOX:
 | 
			
		||||
+                state = CLOSING_MAILBOX;
 | 
			
		||||
+                break;
 | 
			
		||||
+            }
 | 
			
		||||
+            return state;
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    /** Specifies the reason the session was disconnected, if any. */
 | 
			
		||||
+    public DisconnectReason? disconnected { get; private set; default = null; }
 | 
			
		||||
+
 | 
			
		||||
     /**
 | 
			
		||||
      * Set of IMAP extensions reported as being supported by the server.
 | 
			
		||||
      *
 | 
			
		||||
@@ -330,9 +379,6 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
     // Connection state changes
 | 
			
		||||
     //
 | 
			
		||||
 
 | 
			
		||||
-    /** Emitted when the session is disconnected for any reason. */
 | 
			
		||||
-    public signal void disconnected(DisconnectReason reason);
 | 
			
		||||
-
 | 
			
		||||
     /** Emitted when an IMAP command status response is received. */
 | 
			
		||||
     public signal void status_response_received(StatusResponse status_response);
 | 
			
		||||
 
 | 
			
		||||
@@ -482,7 +528,14 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
             new Geary.State.Mapping(State.CLOSED, Event.RECV_ERROR, Geary.State.nop),
 | 
			
		||||
         };
 | 
			
		||||
 
 | 
			
		||||
-        fsm = new Geary.State.Machine(machine_desc, mappings, on_ignored_transition);
 | 
			
		||||
+        this.fsm = new Geary.State.Machine(
 | 
			
		||||
+            machine_desc,
 | 
			
		||||
+            mappings,
 | 
			
		||||
+            on_ignored_transition
 | 
			
		||||
+        );
 | 
			
		||||
+        this.fsm.notify["state"].connect(
 | 
			
		||||
+            () => this.notify_property("protocol_state")
 | 
			
		||||
+        );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     ~ClientSession() {
 | 
			
		||||
@@ -493,7 +546,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
             break;
 | 
			
		||||
 
 | 
			
		||||
             default:
 | 
			
		||||
-                warning("ClientSession ref dropped while still active");
 | 
			
		||||
+                GLib.warning("ClientSession ref dropped while still active");
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
@@ -636,43 +689,6 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         return delim;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    /**
 | 
			
		||||
-     * Returns the current {@link ProtocolState} of the {@link ClientSession} and, if selected,
 | 
			
		||||
-     * the current mailbox.
 | 
			
		||||
-     */
 | 
			
		||||
-    public ProtocolState get_protocol_state() {
 | 
			
		||||
-        switch (fsm.get_state()) {
 | 
			
		||||
-            case State.NOT_CONNECTED:
 | 
			
		||||
-            case State.LOGOUT:
 | 
			
		||||
-            case State.CLOSED:
 | 
			
		||||
-                return ProtocolState.NOT_CONNECTED;
 | 
			
		||||
-
 | 
			
		||||
-            case State.NOAUTH:
 | 
			
		||||
-                return ProtocolState.UNAUTHORIZED;
 | 
			
		||||
-
 | 
			
		||||
-            case State.AUTHORIZED:
 | 
			
		||||
-                return ProtocolState.AUTHORIZED;
 | 
			
		||||
-
 | 
			
		||||
-            case State.SELECTED:
 | 
			
		||||
-                return ProtocolState.SELECTED;
 | 
			
		||||
-
 | 
			
		||||
-            case State.CONNECTING:
 | 
			
		||||
-                return ProtocolState.CONNECTING;
 | 
			
		||||
-
 | 
			
		||||
-            case State.AUTHORIZING:
 | 
			
		||||
-                return ProtocolState.AUTHORIZING;
 | 
			
		||||
-
 | 
			
		||||
-            case State.SELECTING:
 | 
			
		||||
-                return ProtocolState.SELECTING;
 | 
			
		||||
-
 | 
			
		||||
-            case State.CLOSING_MAILBOX:
 | 
			
		||||
-                return ProtocolState.CLOSING_MAILBOX;
 | 
			
		||||
-
 | 
			
		||||
-            default:
 | 
			
		||||
-                assert_not_reached();
 | 
			
		||||
-        }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     // Some commands require waiting for a completion response in order to shift the state machine's
 | 
			
		||||
     // State; this allocates such a wait, returning false if another command is outstanding also
 | 
			
		||||
     // waiting for one to finish
 | 
			
		||||
@@ -1197,7 +1213,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
     public void enable_idle()
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
         if (this.is_idle_supported) {
 | 
			
		||||
-            switch (get_protocol_state()) {
 | 
			
		||||
+            switch (this.protocol_state) {
 | 
			
		||||
             case ProtocolState.AUTHORIZING:
 | 
			
		||||
             case ProtocolState.AUTHORIZED:
 | 
			
		||||
             case ProtocolState.SELECTED:
 | 
			
		||||
@@ -1218,7 +1234,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         unschedule_keepalive();
 | 
			
		||||
 
 | 
			
		||||
         uint seconds;
 | 
			
		||||
-        switch (get_protocol_state()) {
 | 
			
		||||
+        switch (this.protocol_state) {
 | 
			
		||||
             case ProtocolState.NOT_CONNECTED:
 | 
			
		||||
             case ProtocolState.CONNECTING:
 | 
			
		||||
                 return;
 | 
			
		||||
@@ -1555,10 +1571,11 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         MachineParams params = (MachineParams) object;
 | 
			
		||||
 
 | 
			
		||||
         assert(params.cmd is LogoutCommand);
 | 
			
		||||
-        if (!reserve_state_change_cmd(params, state, event))
 | 
			
		||||
-            return state;
 | 
			
		||||
+        if (reserve_state_change_cmd(params, state, event)) {
 | 
			
		||||
+            state = State.LOGOUT;
 | 
			
		||||
+        }
 | 
			
		||||
 
 | 
			
		||||
-        return State.LOGOUT;
 | 
			
		||||
+        return state;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private uint on_logging_out_recv_status(uint state,
 | 
			
		||||
@@ -1625,7 +1642,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         drop_connection();
 | 
			
		||||
-        disconnected(DisconnectReason.LOCAL_CLOSE);
 | 
			
		||||
+        this.disconnected = DisconnectReason.LOCAL_CLOSE;
 | 
			
		||||
 
 | 
			
		||||
         if (disconnect_err != null)
 | 
			
		||||
             throw disconnect_err;
 | 
			
		||||
@@ -1661,6 +1678,8 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private async void do_disconnect(DisconnectReason reason) {
 | 
			
		||||
+        this.disconnected = reason;
 | 
			
		||||
+
 | 
			
		||||
         try {
 | 
			
		||||
             yield this.cx.disconnect_async();
 | 
			
		||||
         } catch (GLib.Error err) {
 | 
			
		||||
@@ -1668,7 +1687,6 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         drop_connection();
 | 
			
		||||
-        disconnected(reason);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     //
 | 
			
		||||
diff --git a/test/engine/imap/transport/imap-client-session-test.vala b/test/engine/imap/transport/imap-client-session-test.vala
 | 
			
		||||
index 2aed9211..c9a4165c 100644
 | 
			
		||||
--- a/test/engine/imap/transport/imap-client-session-test.vala
 | 
			
		||||
+++ b/test/engine/imap/transport/imap-client-session-test.vala
 | 
			
		||||
@@ -44,17 +44,17 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
         this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
 | 
			
		||||
 
 | 
			
		||||
         var test_article = new ClientSession(new_endpoint(), new Quirks());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.connect_async.begin(
 | 
			
		||||
             CONNECT_TIMEOUT, null, this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.connect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == UNAUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == UNAUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.disconnect_async.begin(null, this.async_completion);
 | 
			
		||||
         test_article.disconnect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         TestServer.Result result = this.server.wait_for_script(this.main_loop);
 | 
			
		||||
         assert_true(
 | 
			
		||||
@@ -148,13 +148,13 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
         this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
 | 
			
		||||
 
 | 
			
		||||
         var test_article = new ClientSession(new_endpoint(), new Quirks());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.connect_async.begin(
 | 
			
		||||
             CONNECT_TIMEOUT, null, this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.connect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == UNAUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == UNAUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.login_async.begin(
 | 
			
		||||
             new Credentials(PASSWORD, "test", "password"),
 | 
			
		||||
@@ -162,11 +162,11 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
             this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.login_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == AUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == AUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.disconnect_async.begin(null, this.async_completion);
 | 
			
		||||
         test_article.disconnect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         TestServer.Result result = this.server.wait_for_script(this.main_loop);
 | 
			
		||||
         assert_true(
 | 
			
		||||
@@ -185,17 +185,17 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
         this.server.add_script_line(DISCONNECT, "");
 | 
			
		||||
 
 | 
			
		||||
         var test_article = new ClientSession(new_endpoint(), new Quirks());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.connect_async.begin(
 | 
			
		||||
             CONNECT_TIMEOUT, null, this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.connect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == UNAUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == UNAUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.logout_async.begin(null, this.async_completion);
 | 
			
		||||
         test_article.logout_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         TestServer.Result result = this.server.wait_for_script(this.main_loop);
 | 
			
		||||
         assert_true(
 | 
			
		||||
@@ -216,13 +216,13 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
         this.server.add_script_line(DISCONNECT, "");
 | 
			
		||||
 
 | 
			
		||||
         var test_article = new ClientSession(new_endpoint(), new Quirks());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.connect_async.begin(
 | 
			
		||||
             CONNECT_TIMEOUT, null, this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.connect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == UNAUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == UNAUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.login_async.begin(
 | 
			
		||||
             new Credentials(PASSWORD, "test", "password"),
 | 
			
		||||
@@ -230,11 +230,11 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
             this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.login_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == AUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == AUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.logout_async.begin(null, this.async_completion);
 | 
			
		||||
         test_article.logout_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         TestServer.Result result = this.server.wait_for_script(this.main_loop);
 | 
			
		||||
         assert_true(
 | 
			
		||||
@@ -261,13 +261,13 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
         this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
 | 
			
		||||
 
 | 
			
		||||
         var test_article = new ClientSession(new_endpoint(), new Quirks());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.connect_async.begin(
 | 
			
		||||
             CONNECT_TIMEOUT, null, this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.connect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == UNAUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == UNAUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.initiate_session_async.begin(
 | 
			
		||||
             new Credentials(PASSWORD, "test", "password"),
 | 
			
		||||
@@ -305,13 +305,13 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
         this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
 | 
			
		||||
 
 | 
			
		||||
         var test_article = new ClientSession(new_endpoint(), new Quirks());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.connect_async.begin(
 | 
			
		||||
             CONNECT_TIMEOUT, null, this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.connect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == UNAUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == UNAUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.initiate_session_async.begin(
 | 
			
		||||
             new Credentials(PASSWORD, "test", "password"),
 | 
			
		||||
@@ -368,13 +368,13 @@ class Geary.Imap.ClientSessionTest : TestCase {
 | 
			
		||||
         this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
 | 
			
		||||
 
 | 
			
		||||
         var test_article = new ClientSession(new_endpoint(), new Quirks());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == NOT_CONNECTED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.connect_async.begin(
 | 
			
		||||
             CONNECT_TIMEOUT, null, this.async_completion
 | 
			
		||||
         );
 | 
			
		||||
         test_article.connect_async.end(async_result());
 | 
			
		||||
-        assert_true(test_article.get_protocol_state() == UNAUTHORIZED);
 | 
			
		||||
+        assert_true(test_article.protocol_state == UNAUTHORIZED);
 | 
			
		||||
 
 | 
			
		||||
         test_article.initiate_session_async.begin(
 | 
			
		||||
             new Credentials(PASSWORD, "test", "password"),
 | 
			
		||||
diff --git a/test/integration/imap/client-session.vala b/test/integration/imap/client-session.vala
 | 
			
		||||
index ca813b79..257d7319 100644
 | 
			
		||||
--- a/test/integration/imap/client-session.vala
 | 
			
		||||
+++ b/test/integration/imap/client-session.vala
 | 
			
		||||
@@ -34,7 +34,7 @@ class Integration.Imap.ClientSession : TestCase {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public override void tear_down() throws GLib.Error {
 | 
			
		||||
-        if (this.session.get_protocol_state() != NOT_CONNECTED) {
 | 
			
		||||
+        if (this.session.protocol_state != NOT_CONNECTED) {
 | 
			
		||||
             this.session.disconnect_async.begin(null, this.async_completion);
 | 
			
		||||
             this.session.disconnect_async.end(async_result());
 | 
			
		||||
         }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,79 @@
 | 
			
		||||
From bd85c4f1a82c14fad0f909e5b1058c73d5b56c92 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sun, 27 Sep 2020 19:57:52 +1000
 | 
			
		||||
Subject: [PATCH 028/124] Composer.Widget: Fix criticals when "mailto:" has
 | 
			
		||||
 empty body
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/composer/composer-widget.vala       | 13 +++++++++----
 | 
			
		||||
 test/client/composer/composer-widget-test.vala | 10 ++++++++++
 | 
			
		||||
 2 files changed, 19 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
 | 
			
		||||
index ecc3fbfd..dab8cfd8 100644
 | 
			
		||||
--- a/src/client/composer/composer-widget.vala
 | 
			
		||||
+++ b/src/client/composer/composer-widget.vala
 | 
			
		||||
@@ -575,8 +575,11 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
         Gee.HashMultiMap<string, string> headers = new Gee.HashMultiMap<string, string>();
 | 
			
		||||
         if (mailto.has_prefix(MAILTO_URI_PREFIX)) {
 | 
			
		||||
             // Parse the mailto link.
 | 
			
		||||
+            string? email = null;
 | 
			
		||||
             string[] parts = mailto.substring(MAILTO_URI_PREFIX.length).split("?", 2);
 | 
			
		||||
-            string email = Uri.unescape_string(parts[0]);
 | 
			
		||||
+            if (parts.length > 0) {
 | 
			
		||||
+                email = Uri.unescape_string(parts[0]);
 | 
			
		||||
+            }
 | 
			
		||||
             string[] params = parts.length == 2 ? parts[1].split("&") : new string[0];
 | 
			
		||||
             foreach (string param in params) {
 | 
			
		||||
                 string[] param_parts = param.split("=", 2);
 | 
			
		||||
@@ -587,14 +590,16 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
             }
 | 
			
		||||
 
 | 
			
		||||
             // Assemble the headers.
 | 
			
		||||
-            if (email.length > 0 && headers.contains("to"))
 | 
			
		||||
+            if (!Geary.String.is_empty_or_whitespace(email) &&
 | 
			
		||||
+                headers.contains("to")) {
 | 
			
		||||
                 this.to = "%s,%s".printf(
 | 
			
		||||
                     email, Geary.Collection.first(headers.get("to"))
 | 
			
		||||
                 );
 | 
			
		||||
-            else if (email.length > 0)
 | 
			
		||||
+            } else if (!Geary.String.is_empty_or_whitespace(email)) {
 | 
			
		||||
                 this.to = email;
 | 
			
		||||
-            else if (headers.contains("to"))
 | 
			
		||||
+            } else if (headers.contains("to")) {
 | 
			
		||||
                 this.to = Geary.Collection.first(headers.get("to"));
 | 
			
		||||
+            }
 | 
			
		||||
 
 | 
			
		||||
             if (headers.contains("cc"))
 | 
			
		||||
                 this.cc = Geary.Collection.first(headers.get("cc"));
 | 
			
		||||
diff --git a/test/client/composer/composer-widget-test.vala b/test/client/composer/composer-widget-test.vala
 | 
			
		||||
index c35b52e4..6b31c943 100644
 | 
			
		||||
--- a/test/client/composer/composer-widget-test.vala
 | 
			
		||||
+++ b/test/client/composer/composer-widget-test.vala
 | 
			
		||||
@@ -92,6 +92,7 @@ public class Composer.WidgetTest : TestCase {
 | 
			
		||||
         add_test("load_empty_body", load_empty_body);
 | 
			
		||||
         add_test("load_empty_body_to", load_empty_body_to);
 | 
			
		||||
         add_test("load_mailto", load_mailto);
 | 
			
		||||
+        add_test("load_mailto_empty", load_mailto_empty);
 | 
			
		||||
         add_test("load_context_edit", load_context_edit);
 | 
			
		||||
         add_test("load_context_reply_sender", load_context_reply_sender);
 | 
			
		||||
         add_test("load_context_reply_sender_with_reply_to", load_context_reply_sender_with_reply_to);
 | 
			
		||||
@@ -164,6 +165,15 @@ public class Composer.WidgetTest : TestCase {
 | 
			
		||||
         assert_equal(widget.to, "mailto@example.com");
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public void load_mailto_empty() throws GLib.Error {
 | 
			
		||||
+        var widget = new Widget(this.application, this.config, this.account);
 | 
			
		||||
+
 | 
			
		||||
+        widget.load_mailto.begin("mailto:", this.async_completion);
 | 
			
		||||
+        widget.load_mailto.end(async_result());
 | 
			
		||||
+
 | 
			
		||||
+        assert_equal(widget.to, "");
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     public void load_context_edit() throws GLib.Error {
 | 
			
		||||
         var widget = new Widget(this.application, this.config, this.account);
 | 
			
		||||
         var email = load_email(MESSAGE_WITH_REPLY_TO);
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
From 70186163e8bcf1a0644669fe7c9b2b56dceef9b5 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sun, 27 Sep 2020 22:46:40 +1000
 | 
			
		||||
Subject: [PATCH 029/124] Composer.Widget: Fix critical when immediately
 | 
			
		||||
 detaching a new composer
 | 
			
		||||
 | 
			
		||||
New composers have no associated GLib Application instance, so when the
 | 
			
		||||
main window is already showing a composer and another is opened, the
 | 
			
		||||
new composer has no application to pass its window.
 | 
			
		||||
 | 
			
		||||
Fix by requiring `Composer.detach` be passed an application instance
 | 
			
		||||
and find an appropriate instance at each call site.
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-main-window.vala | 2 +-
 | 
			
		||||
 src/client/composer/composer-widget.vala            | 6 ++----
 | 
			
		||||
 2 files changed, 3 insertions(+), 5 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index e8428459..73b50e33 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -875,7 +875,7 @@ public class Application.MainWindow :
 | 
			
		||||
      */
 | 
			
		||||
     internal void show_composer(Composer.Widget composer) {
 | 
			
		||||
         if (this.has_composer) {
 | 
			
		||||
-            composer.detach();
 | 
			
		||||
+            composer.detach(this.application);
 | 
			
		||||
         } else {
 | 
			
		||||
             // See if the currently displayed conversation contains
 | 
			
		||||
             // any of the composer's referred emails (preferring the
 | 
			
		||||
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
 | 
			
		||||
index dab8cfd8..37e93fb4 100644
 | 
			
		||||
--- a/src/client/composer/composer-widget.vala
 | 
			
		||||
+++ b/src/client/composer/composer-widget.vala
 | 
			
		||||
@@ -785,10 +785,8 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** Detaches the composer and opens it in a new window. */
 | 
			
		||||
-    public void detach() {
 | 
			
		||||
+    public void detach(Application.Client application) {
 | 
			
		||||
         Gtk.Widget? focused_widget = null;
 | 
			
		||||
-        var application = this.container.top_window.application as Application.Client;
 | 
			
		||||
-
 | 
			
		||||
         if (this.container != null) {
 | 
			
		||||
             focused_widget = this.container.top_window.get_focus();
 | 
			
		||||
             this.container.close();
 | 
			
		||||
@@ -2374,7 +2372,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void on_detach() {
 | 
			
		||||
-        detach();
 | 
			
		||||
+        detach(this.container.top_window.application as Application.Client);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void on_add_attachment() {
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,126 @@
 | 
			
		||||
From 6fb365ebd45e283f770cde341c6332af66051ab6 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sun, 27 Sep 2020 23:37:50 +1000
 | 
			
		||||
Subject: [PATCH 030/124] Geary.RFC822.Message: Fix plain text file attachment
 | 
			
		||||
 line ending conversion
 | 
			
		||||
 | 
			
		||||
Since RFC822 requires CRLF for line endings, it's not possible for a MUA
 | 
			
		||||
to determine the correct line ending for text attachments that use the
 | 
			
		||||
default or quoted-printable transfer encoding.
 | 
			
		||||
 | 
			
		||||
As such, always use a binary encoding for all non-body message parts
 | 
			
		||||
(which for now means always use Base64) so that line endings are
 | 
			
		||||
explicitly encoded and hence always decoded correctly.
 | 
			
		||||
 | 
			
		||||
Fixes #1001
 | 
			
		||||
---
 | 
			
		||||
 src/engine/rfc822/rfc822-message.vala | 65 +++++++++++++--------------
 | 
			
		||||
 1 file changed, 30 insertions(+), 35 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala
 | 
			
		||||
index 51563caf..e6cc17a4 100644
 | 
			
		||||
--- a/src/engine/rfc822/rfc822-message.vala
 | 
			
		||||
+++ b/src/engine/rfc822/rfc822-message.vala
 | 
			
		||||
@@ -494,7 +494,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 | 
			
		||||
             FileQueryInfoFlags.NONE
 | 
			
		||||
         );
 | 
			
		||||
 
 | 
			
		||||
-        GMime.Part part = new GMime.Part.with_type("text", "plain");
 | 
			
		||||
+        GMime.Part part = new GMime.Part();
 | 
			
		||||
         part.set_disposition(disposition.serialize());
 | 
			
		||||
         part.set_filename(file.get_basename());
 | 
			
		||||
 
 | 
			
		||||
@@ -504,10 +504,26 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 | 
			
		||||
         );
 | 
			
		||||
         part.set_content_type(content_type);
 | 
			
		||||
 
 | 
			
		||||
+        // Always use a binary encoding since even when attaching
 | 
			
		||||
+        // text/plain parts, the line ending must always be preserved
 | 
			
		||||
+        // and this is not possible without a binary encoding. See
 | 
			
		||||
+        // https://gitlab.gnome.org/GNOME/geary/-/issues/1001
 | 
			
		||||
+        //
 | 
			
		||||
+        // TODO: The actual content encoding should be set based on
 | 
			
		||||
+        // the IMAP/SMTP server's supported encoding. For example, if
 | 
			
		||||
+        // 8-bit or binary is supported, then those should be used
 | 
			
		||||
+        // instead of Base64.
 | 
			
		||||
+        part.set_content_encoding(BASE64);
 | 
			
		||||
+
 | 
			
		||||
         GMime.StreamGIO stream = new GMime.StreamGIO(file);
 | 
			
		||||
         stream.set_owner(false);
 | 
			
		||||
+        part.set_content(
 | 
			
		||||
+            new GMime.DataWrapper.with_stream(
 | 
			
		||||
+                stream, GMime.ContentEncoding.BINARY
 | 
			
		||||
+            )
 | 
			
		||||
+        );
 | 
			
		||||
 
 | 
			
		||||
-        return yield finalise_attachment_part(stream, part, content_type, cancellable);
 | 
			
		||||
+        return part;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -540,50 +556,29 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 | 
			
		||||
                 );
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        GMime.Part part = new GMime.Part.with_type("text", "plain");
 | 
			
		||||
+        GMime.Part part = new GMime.Part();
 | 
			
		||||
         part.set_disposition(disposition.serialize());
 | 
			
		||||
         part.set_filename(basename);
 | 
			
		||||
         part.set_content_type(content_type);
 | 
			
		||||
 
 | 
			
		||||
-        GMime.StreamMem stream = Utils.create_stream_mem(buffer);
 | 
			
		||||
-
 | 
			
		||||
-        return yield finalise_attachment_part(stream, part, content_type, cancellable);
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    /**
 | 
			
		||||
-     * Set encoding and content object on GMime part
 | 
			
		||||
-     */
 | 
			
		||||
-    private async GMime.Part finalise_attachment_part(GMime.Stream stream,
 | 
			
		||||
-                                                      GMime.Part part,
 | 
			
		||||
-                                                      GMime.ContentType content_type,
 | 
			
		||||
-                                                      GLib.Cancellable? cancellable)
 | 
			
		||||
-        throws GLib.Error {
 | 
			
		||||
-
 | 
			
		||||
-        // Text parts should be scanned fully to determine best
 | 
			
		||||
-        // (i.e. most compact) transport encoding to use, but
 | 
			
		||||
-        // that's usually fine since they tend to be
 | 
			
		||||
-        // small. Non-text parts are nearly always going to be
 | 
			
		||||
-        // binary, so we just assume they require Base64.
 | 
			
		||||
+        // Always use a binary encoding since even when attaching
 | 
			
		||||
+        // text/plain parts, the line ending must always be preserved
 | 
			
		||||
+        // and this is not possible without a binary encoding. See
 | 
			
		||||
+        // https://gitlab.gnome.org/GNOME/geary/-/issues/1001
 | 
			
		||||
         //
 | 
			
		||||
-        // XXX We should be setting the content encoding lazily
 | 
			
		||||
-        // though because if sending via a MTA that supports 8-bit
 | 
			
		||||
-        // or binary transfer modes, we can avoid using a content
 | 
			
		||||
-        // encoding altogether.
 | 
			
		||||
-        GMime.ContentEncoding encoding = BASE64;
 | 
			
		||||
-        if (content_type.is_type("text", Mime.ContentType.WILDCARD)) {
 | 
			
		||||
-            encoding = yield Utils.get_best_encoding(
 | 
			
		||||
-                stream,
 | 
			
		||||
-                GMime.EncodingConstraint.7BIT,
 | 
			
		||||
-                cancellable
 | 
			
		||||
-            );
 | 
			
		||||
-        }
 | 
			
		||||
+        // TODO: The actual content encoding should be set based on
 | 
			
		||||
+        // the IMAP/SMTP server's supported encoding. For example, if
 | 
			
		||||
+        // 8-bit or binary is supported, then those should be used
 | 
			
		||||
+        // instead of Base64.
 | 
			
		||||
+        part.set_content_encoding(BASE64);
 | 
			
		||||
 
 | 
			
		||||
-        part.set_content_encoding(encoding);
 | 
			
		||||
+        GMime.StreamMem stream = Utils.create_stream_mem(buffer);
 | 
			
		||||
         part.set_content(
 | 
			
		||||
             new GMime.DataWrapper.with_stream(
 | 
			
		||||
                 stream, GMime.ContentEncoding.BINARY
 | 
			
		||||
             )
 | 
			
		||||
         );
 | 
			
		||||
+
 | 
			
		||||
         return part;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
From b5abd3f9664c396ad57f177750973695c58e8b7f Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Mon, 28 Sep 2020 08:53:35 +1000
 | 
			
		||||
Subject: [PATCH 031/124] build: Fix build failure due to missing client API
 | 
			
		||||
 | 
			
		||||
Don't use client lib vala ags when building the web process extension,
 | 
			
		||||
since that will cause it to also write a VAPI with the same name as
 | 
			
		||||
the client lib, causing the build to fail if the web process side wins
 | 
			
		||||
that race.
 | 
			
		||||
 | 
			
		||||
Fixes #985
 | 
			
		||||
---
 | 
			
		||||
 src/meson.build | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/meson.build b/src/meson.build
 | 
			
		||||
index 87760e74..225777e8 100644
 | 
			
		||||
--- a/src/meson.build
 | 
			
		||||
+++ b/src/meson.build
 | 
			
		||||
@@ -72,7 +72,7 @@ web_process = library('geary-web-process',
 | 
			
		||||
     webkit2gtk_web_extension,
 | 
			
		||||
   ],
 | 
			
		||||
   include_directories: config_h_dir,
 | 
			
		||||
-  vala_args: client_vala_args,
 | 
			
		||||
+  vala_args: geary_vala_args,
 | 
			
		||||
   c_args: geary_c_args,
 | 
			
		||||
   install: true,
 | 
			
		||||
   install_dir: web_extensions_dir
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,62 @@
 | 
			
		||||
From 836a9ad3847d42087c4daeec81e84b7b7936714a Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Mon, 28 Sep 2020 22:26:23 +1000
 | 
			
		||||
Subject: [PATCH 032/124] FormattedConversationData: Fix font settings being
 | 
			
		||||
 ignored under Flatpak
 | 
			
		||||
 | 
			
		||||
Get the interface font from Gtk.Settings instead of GLib.Settings since
 | 
			
		||||
the latter can't actually access desktop settings under Flatpak.
 | 
			
		||||
 | 
			
		||||
Partial fix for #989
 | 
			
		||||
 | 
			
		||||
See also GNOME/glib#2213
 | 
			
		||||
---
 | 
			
		||||
 .../formatted-conversation-data.vala             | 16 +++++++++++++---
 | 
			
		||||
 1 file changed, 13 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/conversation-list/formatted-conversation-data.vala b/src/client/conversation-list/formatted-conversation-data.vala
 | 
			
		||||
index f2b635f8..b21a931f 100644
 | 
			
		||||
--- a/src/client/conversation-list/formatted-conversation-data.vala
 | 
			
		||||
+++ b/src/client/conversation-list/formatted-conversation-data.vala
 | 
			
		||||
@@ -100,6 +100,8 @@ public class FormattedConversationData : Geary.BaseObject {
 | 
			
		||||
     public Geary.Email? preview { get; private set; default = null; }
 | 
			
		||||
 
 | 
			
		||||
     private Application.Configuration config;
 | 
			
		||||
+
 | 
			
		||||
+    private Gtk.Settings? gtk;
 | 
			
		||||
     private Pango.FontDescription font;
 | 
			
		||||
 
 | 
			
		||||
     private Geary.App.Conversation? conversation = null;
 | 
			
		||||
@@ -115,13 +117,13 @@ public class FormattedConversationData : Geary.BaseObject {
 | 
			
		||||
                                      Geary.Email preview,
 | 
			
		||||
                                      Gee.List<Geary.RFC822.MailboxAddress> account_owner_emails) {
 | 
			
		||||
         this.config = config;
 | 
			
		||||
+        this.gtk = Gtk.Settings.get_default();
 | 
			
		||||
         this.conversation = conversation;
 | 
			
		||||
         this.account_owner_emails = account_owner_emails;
 | 
			
		||||
         this.use_to = conversation.base_folder.used_as.is_outgoing();
 | 
			
		||||
 
 | 
			
		||||
-        this.font = Pango.FontDescription.from_string(
 | 
			
		||||
-            this.config.gnome_interface.get_string("font-name")
 | 
			
		||||
-        );
 | 
			
		||||
+        this.gtk.notify["gtk-font-name"].connect(this.update_font);
 | 
			
		||||
+        update_font();
 | 
			
		||||
 
 | 
			
		||||
         // Load preview-related data.
 | 
			
		||||
         update_date_string();
 | 
			
		||||
@@ -472,4 +474,12 @@ public class FormattedConversationData : Geary.BaseObject {
 | 
			
		||||
         return ink_rect;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private void update_font() {
 | 
			
		||||
+        var name = "Cantarell 11";
 | 
			
		||||
+        if (this.gtk != null) {
 | 
			
		||||
+            name = this.gtk.gtk_font_name;
 | 
			
		||||
+        }
 | 
			
		||||
+        this.font = Pango.FontDescription.from_string(name);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
 }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
From bfbc7f5d70f724010a9789ecefca6c1aa9f22962 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Tue, 29 Sep 2020 23:01:38 +1000
 | 
			
		||||
Subject: [PATCH 033/124] client: Fix not all folders being displayed in
 | 
			
		||||
 additional main windows
 | 
			
		||||
 | 
			
		||||
Application.MainWindow: Sort folders already available in an account
 | 
			
		||||
by path so that FolderListTree is able to add them all successfully.
 | 
			
		||||
 | 
			
		||||
Application.FolderContext: Implement Gee.Comparable so instances can
 | 
			
		||||
be sorted.
 | 
			
		||||
 | 
			
		||||
Fixes #1004
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-folder-context.vala | 7 ++++++-
 | 
			
		||||
 src/client/application/application-main-window.vala    | 7 ++++++-
 | 
			
		||||
 2 files changed, 12 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-folder-context.vala b/src/client/application/application-folder-context.vala
 | 
			
		||||
index b85c901b..4ed47cf5 100644
 | 
			
		||||
--- a/src/client/application/application-folder-context.vala
 | 
			
		||||
+++ b/src/client/application/application-folder-context.vala
 | 
			
		||||
@@ -9,7 +9,8 @@
 | 
			
		||||
 /**
 | 
			
		||||
  * Collects application state related to a single folder.
 | 
			
		||||
  */
 | 
			
		||||
-public class Application.FolderContext : Geary.BaseObject {
 | 
			
		||||
+public class Application.FolderContext : Geary.BaseObject,
 | 
			
		||||
+    Gee.Comparable<FolderContext> {
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     /** Specifies different kinds of displayable email counts. */
 | 
			
		||||
@@ -41,6 +42,10 @@ public class Application.FolderContext : Geary.BaseObject {
 | 
			
		||||
         update();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public int compare_to(FolderContext other) {
 | 
			
		||||
+        return this.folder.path.compare_to(other.folder.path);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     private void update() {
 | 
			
		||||
         this.display_name = Util.I18n.to_folder_display_name(this.folder);
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 73b50e33..47749019 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -1010,7 +1010,12 @@ public class Application.MainWindow :
 | 
			
		||||
             to_add.commands.undone.connect(on_command_undo);
 | 
			
		||||
             to_add.commands.redone.connect(on_command_redo);
 | 
			
		||||
 
 | 
			
		||||
-            add_folders(to_add.get_folders());
 | 
			
		||||
+            // Sort the folders so FolderListTree adds them all
 | 
			
		||||
+            // correctly
 | 
			
		||||
+            var added = new Gee.TreeSet<FolderContext>();
 | 
			
		||||
+            added.add_all(to_add.get_folders());
 | 
			
		||||
+
 | 
			
		||||
+            add_folders(added);
 | 
			
		||||
             this.accounts.add(to_add);
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6014
									
								
								mail-client/geary/files/0034-Update-Hebrew-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6014
									
								
								mail-client/geary/files/0034-Update-Hebrew-translation.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,251 @@
 | 
			
		||||
From aaa2934acfb53243d21a4a68ac6486951ae4b045 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 3 Oct 2020 21:06:43 +1000
 | 
			
		||||
Subject: [PATCH 035/124] meson_options.txt: Update to use meson best practices
 | 
			
		||||
 and clean up
 | 
			
		||||
 | 
			
		||||
Convert to use meson features for features. Reorganise and rename
 | 
			
		||||
options for consistency. Make descriptions a bit less redundant.
 | 
			
		||||
---
 | 
			
		||||
 desktop/meson.build    |  2 +-
 | 
			
		||||
 meson.build            | 27 +++++++---------
 | 
			
		||||
 meson_options.txt      | 71 ++++++++++++++++++++++++------------------
 | 
			
		||||
 src/engine/meson.build |  2 +-
 | 
			
		||||
 src/meson.build        |  4 +--
 | 
			
		||||
 test/meson.build       |  2 +-
 | 
			
		||||
 6 files changed, 57 insertions(+), 51 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/desktop/meson.build b/desktop/meson.build
 | 
			
		||||
index f0c8a660..712db358 100644
 | 
			
		||||
--- a/desktop/meson.build
 | 
			
		||||
+++ b/desktop/meson.build
 | 
			
		||||
@@ -77,7 +77,7 @@ endif
 | 
			
		||||
 # Contractor file (Elementary OS)
 | 
			
		||||
 #
 | 
			
		||||
 
 | 
			
		||||
-if install_contractor_file
 | 
			
		||||
+if get_option('contractor').enabled()
 | 
			
		||||
   # Call msgfmt manually since gettext won't otherwise translate the
 | 
			
		||||
   # Description field. See merge req !50.
 | 
			
		||||
   msgfmt = find_program('msgfmt')
 | 
			
		||||
diff --git a/meson.build b/meson.build
 | 
			
		||||
index 240eacaa..82f0439d 100644
 | 
			
		||||
--- a/meson.build
 | 
			
		||||
+++ b/meson.build
 | 
			
		||||
@@ -4,13 +4,6 @@ project('geary', [ 'vala', 'c' ],
 | 
			
		||||
   meson_version: '>= 0.50',
 | 
			
		||||
 )
 | 
			
		||||
 
 | 
			
		||||
-# Build-time configuration options
 | 
			
		||||
-enable_valadoc = get_option('valadoc')
 | 
			
		||||
-install_contractor_file = get_option('contractor')
 | 
			
		||||
-iso_3166_xml = get_option('iso_3166_xml')
 | 
			
		||||
-iso_639_xml = get_option('iso_639_xml')
 | 
			
		||||
-reference_tracking = get_option('ref_tracking')
 | 
			
		||||
-
 | 
			
		||||
 # Build type
 | 
			
		||||
 if get_option('profile') == 'development'
 | 
			
		||||
   profile = '.Devel'
 | 
			
		||||
@@ -92,13 +85,13 @@ libpeas_gtk = dependency('libpeas-gtk-1.0', version: '>= 1.24.0')
 | 
			
		||||
 libsecret = dependency('libsecret-1', version: '>= 0.11')
 | 
			
		||||
 libsoup = dependency('libsoup-2.4', version: '>= 2.48')
 | 
			
		||||
 libunwind_dep = dependency(
 | 
			
		||||
-  'libunwind', version: '>= 1.1', required: not get_option('libunwind_optional')
 | 
			
		||||
+  'libunwind', version: '>= 1.1', required: get_option('libunwind')
 | 
			
		||||
 )
 | 
			
		||||
 libunwind_generic_dep = dependency(
 | 
			
		||||
-  'libunwind-generic', version: '>= 1.1', required: not get_option('libunwind_optional')
 | 
			
		||||
+  'libunwind-generic', version: '>= 1.1', required: get_option('libunwind')
 | 
			
		||||
 )
 | 
			
		||||
 libxml = dependency('libxml-2.0', version: '>= 2.7.8')
 | 
			
		||||
-libytnef = dependency('libytnef', version: '>= 1.9.3', required: get_option('tnef-support'))
 | 
			
		||||
+libytnef = dependency('libytnef', version: '>= 1.9.3', required: get_option('tnef'))
 | 
			
		||||
 posix = valac.find_library('posix')
 | 
			
		||||
 webkit2gtk_web_extension = dependency('webkit2gtk-web-extension-4.0', version: '>=' + target_webkit)
 | 
			
		||||
 
 | 
			
		||||
@@ -153,27 +146,31 @@ endif
 | 
			
		||||
 # Build glue
 | 
			
		||||
 #
 | 
			
		||||
 
 | 
			
		||||
+valadoc = find_program('valadoc', required: get_option('valadoc'))
 | 
			
		||||
+
 | 
			
		||||
 vala_unit_proj = subproject(
 | 
			
		||||
   'vala-unit',
 | 
			
		||||
   default_options: [
 | 
			
		||||
     'install=false',
 | 
			
		||||
-    'valadoc=@0@'.format(enable_valadoc)
 | 
			
		||||
+    'valadoc=@0@'.format(valadoc.found())
 | 
			
		||||
   ]
 | 
			
		||||
 )
 | 
			
		||||
 vala_unit_dep = vala_unit_proj.get_variable('vala_unit_dep')
 | 
			
		||||
 
 | 
			
		||||
-if enable_valadoc
 | 
			
		||||
-  valadoc = find_program('valadoc')
 | 
			
		||||
-endif
 | 
			
		||||
-
 | 
			
		||||
 # Language detection
 | 
			
		||||
+
 | 
			
		||||
 iso_codes_dir = iso_codes.get_pkgconfig_variable('prefix')/'share'/'xml'/'iso-codes'
 | 
			
		||||
+
 | 
			
		||||
+iso_639_xml = get_option('iso_639_xml')
 | 
			
		||||
 if iso_639_xml == ''
 | 
			
		||||
   iso_639_xml = iso_codes_dir / 'iso_639.xml'
 | 
			
		||||
 endif
 | 
			
		||||
+
 | 
			
		||||
+iso_3166_xml = get_option('iso_3166_xml')
 | 
			
		||||
 if iso_3166_xml == ''
 | 
			
		||||
   iso_3166_xml = iso_codes_dir / 'iso_3166.xml'
 | 
			
		||||
 endif
 | 
			
		||||
+
 | 
			
		||||
 files(iso_639_xml, iso_3166_xml) # Check to make sure these exist
 | 
			
		||||
 
 | 
			
		||||
 # Post-install scripts
 | 
			
		||||
diff --git a/meson_options.txt b/meson_options.txt
 | 
			
		||||
index a18438d4..968c2541 100644
 | 
			
		||||
--- a/meson_options.txt
 | 
			
		||||
+++ b/meson_options.txt
 | 
			
		||||
@@ -1,11 +1,18 @@
 | 
			
		||||
 #
 | 
			
		||||
 # General build options
 | 
			
		||||
 #
 | 
			
		||||
+
 | 
			
		||||
 option(
 | 
			
		||||
-  'contractor',
 | 
			
		||||
-  type: 'boolean',
 | 
			
		||||
-  value: false,
 | 
			
		||||
-  description: 'Whether to install the contractor file (Elementary OS-specific).'
 | 
			
		||||
+  'profile',
 | 
			
		||||
+  type: 'combo',
 | 
			
		||||
+  value: 'default',
 | 
			
		||||
+  choices: ['default','development','beta'],
 | 
			
		||||
+  description: 'Specifies the application type to be built'
 | 
			
		||||
+)
 | 
			
		||||
+option(
 | 
			
		||||
+  'revno',
 | 
			
		||||
+  type: 'string',
 | 
			
		||||
+  description: 'Custom revision string (default extracted from "git describe")'
 | 
			
		||||
 )
 | 
			
		||||
 option(
 | 
			
		||||
   'iso_639_xml',
 | 
			
		||||
@@ -19,41 +26,43 @@ option(
 | 
			
		||||
   value: '',
 | 
			
		||||
   description: 'Full path to the ISO 3166 XML file.'
 | 
			
		||||
 )
 | 
			
		||||
-option(
 | 
			
		||||
-  'libunwind_optional',
 | 
			
		||||
-  type: 'boolean',
 | 
			
		||||
-  value: false,
 | 
			
		||||
-  description: 'Determines if libunwind is required.'
 | 
			
		||||
-)
 | 
			
		||||
-option(
 | 
			
		||||
-  'tnef-support',
 | 
			
		||||
-  type: 'boolean',
 | 
			
		||||
-  value: true,
 | 
			
		||||
-  description: 'Whether to support TNEF attachments (requires libytnef).'
 | 
			
		||||
-)
 | 
			
		||||
 option(
 | 
			
		||||
   'valadoc',
 | 
			
		||||
-  type: 'boolean',
 | 
			
		||||
-  value: false,
 | 
			
		||||
-  description: 'Whether to build the documentation (requires valadoc).'
 | 
			
		||||
+  type: 'feature',
 | 
			
		||||
+  value: 'auto',
 | 
			
		||||
+  description: 'Build API documentation'
 | 
			
		||||
 )
 | 
			
		||||
 
 | 
			
		||||
+#
 | 
			
		||||
 # Development options
 | 
			
		||||
+#
 | 
			
		||||
+
 | 
			
		||||
 option(
 | 
			
		||||
-  'profile',
 | 
			
		||||
-  type: 'combo',
 | 
			
		||||
-  value: 'default',
 | 
			
		||||
-  choices: ['default','development','beta'],
 | 
			
		||||
-  description: 'Specifies the application type to be built'
 | 
			
		||||
+  'ref_tracking',
 | 
			
		||||
+  type: 'feature',
 | 
			
		||||
+  value: 'disabled',
 | 
			
		||||
+  description: 'Enable Geary.BaseObject reference tracking'
 | 
			
		||||
+)
 | 
			
		||||
+
 | 
			
		||||
+#
 | 
			
		||||
+# Optional features
 | 
			
		||||
+#
 | 
			
		||||
+
 | 
			
		||||
+option(
 | 
			
		||||
+  'contractor',
 | 
			
		||||
+  type: 'feature',
 | 
			
		||||
+  value: 'disabled',
 | 
			
		||||
+  description: 'Install an Elementary OS a contractor file'
 | 
			
		||||
 )
 | 
			
		||||
 option(
 | 
			
		||||
-  'ref_tracking',
 | 
			
		||||
-  type: 'boolean',
 | 
			
		||||
-  value: false,
 | 
			
		||||
-  description: 'Whether to use explicit reference tracking.'
 | 
			
		||||
+  'libunwind',
 | 
			
		||||
+  type: 'feature',
 | 
			
		||||
+  value: 'enabled',
 | 
			
		||||
+  description: 'Use libunwind for back traces in problem reports.'
 | 
			
		||||
 )
 | 
			
		||||
 option(
 | 
			
		||||
-  'revno',
 | 
			
		||||
-  type: 'string',
 | 
			
		||||
-  description: 'Custom revision string (default extracted from "git describe")'
 | 
			
		||||
+  'tnef',
 | 
			
		||||
+  type: 'feature',
 | 
			
		||||
+  value: 'enabled',
 | 
			
		||||
+  description: 'Support Microsoft-proprietary TNEF attachments.'
 | 
			
		||||
 )
 | 
			
		||||
diff --git a/src/engine/meson.build b/src/engine/meson.build
 | 
			
		||||
index 0efd773e..1133f7b8 100644
 | 
			
		||||
--- a/src/engine/meson.build
 | 
			
		||||
+++ b/src/engine/meson.build
 | 
			
		||||
@@ -349,7 +349,7 @@ if libunwind_dep.found()
 | 
			
		||||
   ]
 | 
			
		||||
 endif
 | 
			
		||||
 
 | 
			
		||||
-if get_option('tnef-support')
 | 
			
		||||
+if libytnef.found()
 | 
			
		||||
   engine_dependencies += libytnef
 | 
			
		||||
   engine_vala_args += [
 | 
			
		||||
     '-D', 'WITH_TNEF_SUPPORT'
 | 
			
		||||
diff --git a/src/meson.build b/src/meson.build
 | 
			
		||||
index 225777e8..14f08c18 100644
 | 
			
		||||
--- a/src/meson.build
 | 
			
		||||
+++ b/src/meson.build
 | 
			
		||||
@@ -33,7 +33,7 @@ endif
 | 
			
		||||
 
 | 
			
		||||
 # Symbols for valac's preprocessor must be defined as compiler args,
 | 
			
		||||
 # not in the code or in config.h
 | 
			
		||||
-if reference_tracking
 | 
			
		||||
+if get_option('ref_tracking').enabled()
 | 
			
		||||
   geary_vala_args += [ '--define=REF_TRACKING' ]
 | 
			
		||||
 endif
 | 
			
		||||
 
 | 
			
		||||
@@ -157,7 +157,7 @@ foreach dir : valadoc_vapi_dirs
 | 
			
		||||
   valadoc_vapidir_args += '--vapidir=@0@'.format(dir)
 | 
			
		||||
 endforeach
 | 
			
		||||
 
 | 
			
		||||
-if enable_valadoc
 | 
			
		||||
+if valadoc.found()
 | 
			
		||||
   docs = custom_target('valadoc',
 | 
			
		||||
     build_by_default: true,
 | 
			
		||||
     depends: [client_lib, engine_lib],
 | 
			
		||||
diff --git a/test/meson.build b/test/meson.build
 | 
			
		||||
index fe3040dd..a32b2a82 100644
 | 
			
		||||
--- a/test/meson.build
 | 
			
		||||
+++ b/test/meson.build
 | 
			
		||||
@@ -118,7 +118,7 @@ test_engine_dependencies += engine_dependencies
 | 
			
		||||
 
 | 
			
		||||
 test_engine_vala_args = geary_vala_args
 | 
			
		||||
 
 | 
			
		||||
-if get_option('tnef-support')
 | 
			
		||||
+if libytnef.found()
 | 
			
		||||
   test_engine_dependencies += libytnef
 | 
			
		||||
   test_engine_vala_args += [
 | 
			
		||||
     '-D', 'WITH_TNEF_SUPPORT'
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,143 @@
 | 
			
		||||
From 23bd2507a7512664802db41b88ad375298d6b7d0 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 3 Oct 2020 21:59:01 +1000
 | 
			
		||||
Subject: [PATCH 036/124] build: Update how build profiles are handled
 | 
			
		||||
 | 
			
		||||
Default to development build profile if a `.git` directory exists, else
 | 
			
		||||
error out of build configuration.
 | 
			
		||||
 | 
			
		||||
This make `auto` the default build profile and if set and a `.git`
 | 
			
		||||
directory is present default to `development`, else raise an error.
 | 
			
		||||
Add some docs to INSTALL describing build profiles and update how they
 | 
			
		||||
are used in the source to match.
 | 
			
		||||
---
 | 
			
		||||
 INSTALL                                       | 26 +++++++++++++++--
 | 
			
		||||
 meson.build                                   | 28 +++++++++++++------
 | 
			
		||||
 meson_options.txt                             |  8 ++++--
 | 
			
		||||
 .../application/application-main-window.vala  |  2 +-
 | 
			
		||||
 4 files changed, 50 insertions(+), 14 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/INSTALL b/INSTALL
 | 
			
		||||
index 6572303f..e445a409 100644
 | 
			
		||||
--- a/INSTALL
 | 
			
		||||
+++ b/INSTALL
 | 
			
		||||
@@ -15,6 +15,28 @@ repository:
 | 
			
		||||
 A convenience Makefile for development only is also provided. To use
 | 
			
		||||
 it, simply invoke make from the top-level directory.
 | 
			
		||||
 
 | 
			
		||||
+Build profiles
 | 
			
		||||
+--------------
 | 
			
		||||
+
 | 
			
		||||
+Geary can be built using a number of different build profiles, which
 | 
			
		||||
+determine things like the application id, the location of stored data,
 | 
			
		||||
+the name of the application and other visual elements that distinguish
 | 
			
		||||
+release builds from other types.
 | 
			
		||||
+
 | 
			
		||||
+These can be set at build configuration time using the Meson `setup`
 | 
			
		||||
+and `configure` commands, using the standard `-Dprofile=…` option. See
 | 
			
		||||
+the `profile` option in `meson_options.txt` for the current list of
 | 
			
		||||
+supported types.
 | 
			
		||||
+
 | 
			
		||||
+Maintainers must select the `release` build profile when packaging
 | 
			
		||||
+non-test release builds, otherwise Geary will using branding and data
 | 
			
		||||
+locations intended for development only.
 | 
			
		||||
+
 | 
			
		||||
+Note that setting the profile does not alter such things as cmopiler
 | 
			
		||||
+options, use the standard Meson `--buildtype` argument for that.
 | 
			
		||||
+
 | 
			
		||||
+If built from
 | 
			
		||||
+
 | 
			
		||||
 Dependencies
 | 
			
		||||
 ------------
 | 
			
		||||
 
 | 
			
		||||
@@ -94,5 +116,5 @@ the initial configuration step:
 | 
			
		||||
     meson --prefix=/usr -C build
 | 
			
		||||
 
 | 
			
		||||
 ---
 | 
			
		||||
-Copyright 2016 Software Freedom Conservancy Inc.  
 | 
			
		||||
-Copyright 2018 Michael Gratton <mike@vee.net>
 | 
			
		||||
+Copyright © 2016 Software Freedom Conservancy Inc.  
 | 
			
		||||
+Copyright © 2018-2020 Michael Gratton <mike@vee.net>
 | 
			
		||||
diff --git a/meson.build b/meson.build
 | 
			
		||||
index 82f0439d..1dc9e3aa 100644
 | 
			
		||||
--- a/meson.build
 | 
			
		||||
+++ b/meson.build
 | 
			
		||||
@@ -4,16 +4,26 @@ project('geary', [ 'vala', 'c' ],
 | 
			
		||||
   meson_version: '>= 0.50',
 | 
			
		||||
 )
 | 
			
		||||
 
 | 
			
		||||
-# Build type
 | 
			
		||||
-if get_option('profile') == 'development'
 | 
			
		||||
-  profile = '.Devel'
 | 
			
		||||
+# Determine the type of build
 | 
			
		||||
+profile = get_option('profile')
 | 
			
		||||
+appid_suffix = ''
 | 
			
		||||
+name_suffix = ''
 | 
			
		||||
+if profile == 'auto'
 | 
			
		||||
+  if run_command('[', '-d', '.git', ']').returncode() == 0
 | 
			
		||||
+    profile = 'development'
 | 
			
		||||
+  else
 | 
			
		||||
+    error('No build profile specified, see INSTALL')
 | 
			
		||||
+  endif
 | 
			
		||||
+endif
 | 
			
		||||
+
 | 
			
		||||
+if profile == 'development'
 | 
			
		||||
+  appid_suffix = '.Devel'
 | 
			
		||||
   name_suffix = ' (Development)'
 | 
			
		||||
-elif get_option('profile') == 'beta'
 | 
			
		||||
-  profile = '.Beta'
 | 
			
		||||
+elif profile == 'beta'
 | 
			
		||||
+  appid_suffix = '.Beta'
 | 
			
		||||
   name_suffix = ' (Beta)'
 | 
			
		||||
-else
 | 
			
		||||
-  profile = ''
 | 
			
		||||
-  name_suffix = ''
 | 
			
		||||
+elif profile != 'release'
 | 
			
		||||
+  error('Unknown build profile specified, see INSTALL')
 | 
			
		||||
 endif
 | 
			
		||||
 
 | 
			
		||||
 # Configurable install dirs
 | 
			
		||||
@@ -120,7 +130,7 @@ libmessagingmenu_dep = dependency('messaging-menu', version: '>= 12.10', require
 | 
			
		||||
 #
 | 
			
		||||
 
 | 
			
		||||
 # Build variables
 | 
			
		||||
-geary_id = 'org.gnome.Geary@0@'.format(profile)
 | 
			
		||||
+geary_id = 'org.gnome.Geary@0@'.format(appid_suffix)
 | 
			
		||||
 geary_version = meson.project_version()
 | 
			
		||||
 revno = get_option('revno')
 | 
			
		||||
 if revno == ''
 | 
			
		||||
diff --git a/meson_options.txt b/meson_options.txt
 | 
			
		||||
index 968c2541..fcb8b9bf 100644
 | 
			
		||||
--- a/meson_options.txt
 | 
			
		||||
+++ b/meson_options.txt
 | 
			
		||||
@@ -5,8 +5,12 @@
 | 
			
		||||
 option(
 | 
			
		||||
   'profile',
 | 
			
		||||
   type: 'combo',
 | 
			
		||||
-  value: 'default',
 | 
			
		||||
-  choices: ['default','development','beta'],
 | 
			
		||||
+  choices: [
 | 
			
		||||
+    'auto',
 | 
			
		||||
+    'development',
 | 
			
		||||
+    'beta',
 | 
			
		||||
+    'release'
 | 
			
		||||
+  ],
 | 
			
		||||
   description: 'Specifies the application type to be built'
 | 
			
		||||
 )
 | 
			
		||||
 option(
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 47749019..aba5fa26 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -487,7 +487,7 @@ public class Application.MainWindow :
 | 
			
		||||
         load_config(application.config);
 | 
			
		||||
         restore_saved_window_state();
 | 
			
		||||
 
 | 
			
		||||
-        if (_PROFILE != "") {
 | 
			
		||||
+        if (_PROFILE != "release") {
 | 
			
		||||
             this.get_style_context().add_class("devel");
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
From 456b6cd55ab4feb5c4c079df2b6aacbcfb69f246 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 3 Oct 2020 22:04:12 +1000
 | 
			
		||||
Subject: [PATCH 037/124] Application.Client: Sort external const
 | 
			
		||||
 alphabetically
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-client.vala | 14 +++++++-------
 | 
			
		||||
 1 file changed, 7 insertions(+), 7 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-client.vala b/src/client/application/application-client.vala
 | 
			
		||||
index 2bf4e094..7a450fa2 100644
 | 
			
		||||
--- a/src/client/application/application-client.vala
 | 
			
		||||
+++ b/src/client/application/application-client.vala
 | 
			
		||||
@@ -7,18 +7,18 @@
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
 // Defined by CMake build script.
 | 
			
		||||
-extern const string _INSTALL_PREFIX;
 | 
			
		||||
-extern const string _GSETTINGS_DIR;
 | 
			
		||||
-extern const string _WEB_EXTENSIONS_DIR;
 | 
			
		||||
-extern const string _PLUGINS_DIR;
 | 
			
		||||
-extern const string _SOURCE_ROOT_DIR;
 | 
			
		||||
-extern const string _BUILD_ROOT_DIR;
 | 
			
		||||
 extern const string GETTEXT_PACKAGE;
 | 
			
		||||
 extern const string _APP_ID;
 | 
			
		||||
+extern const string _BUILD_ROOT_DIR;
 | 
			
		||||
+extern const string _GSETTINGS_DIR;
 | 
			
		||||
+extern const string _INSTALL_PREFIX;
 | 
			
		||||
 extern const string _NAME_SUFFIX;
 | 
			
		||||
+extern const string _PLUGINS_DIR;
 | 
			
		||||
 extern const string _PROFILE;
 | 
			
		||||
-extern const string _VERSION;
 | 
			
		||||
 extern const string _REVNO;
 | 
			
		||||
+extern const string _SOURCE_ROOT_DIR;
 | 
			
		||||
+extern const string _VERSION;
 | 
			
		||||
+extern const string _WEB_EXTENSIONS_DIR;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,317 @@
 | 
			
		||||
From c240884f521da7356d9c5792a7568abc2dba5b38 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 3 Oct 2020 23:31:35 +1000
 | 
			
		||||
Subject: [PATCH 038/124] Rename INSTALLING to BUILDING.md
 | 
			
		||||
 | 
			
		||||
Renamed since most people want to know how to build Geary when they
 | 
			
		||||
get its source, not install it. Use MD extension to get formatting in
 | 
			
		||||
gitlab.
 | 
			
		||||
---
 | 
			
		||||
 BUILDING.md | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 INSTALL     | 120 ---------------------------------------------------
 | 
			
		||||
 README.md   |   9 ++--
 | 
			
		||||
 meson.build |   4 +-
 | 
			
		||||
 4 files changed, 129 insertions(+), 126 deletions(-)
 | 
			
		||||
 create mode 100644 BUILDING.md
 | 
			
		||||
 delete mode 100644 INSTALL
 | 
			
		||||
 | 
			
		||||
diff --git a/BUILDING.md b/BUILDING.md
 | 
			
		||||
new file mode 100644
 | 
			
		||||
index 00000000..c00b1901
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/BUILDING.md
 | 
			
		||||
@@ -0,0 +1,122 @@
 | 
			
		||||
+Building and running Geary
 | 
			
		||||
+==========================
 | 
			
		||||
+
 | 
			
		||||
+Geary uses the [Meson](http://mesonbuild.com) and
 | 
			
		||||
+[Ninja](https://ninja-build.org) build systems. You will need these
 | 
			
		||||
+and a number of other development libraries installed to build
 | 
			
		||||
+Geary. See the Dependencies section below for a list of packages to
 | 
			
		||||
+install.
 | 
			
		||||
+
 | 
			
		||||
+Building, running, tests and documentation
 | 
			
		||||
+------------------------------------------
 | 
			
		||||
+
 | 
			
		||||
+To build Geary, run the following commands from the top-level
 | 
			
		||||
+directory of the source code repository:
 | 
			
		||||
+
 | 
			
		||||
+```
 | 
			
		||||
+meson build
 | 
			
		||||
+ninja -C build
 | 
			
		||||
+```
 | 
			
		||||
+
 | 
			
		||||
+Once built, Geary can be run directly from the build directory without
 | 
			
		||||
+being installed:
 | 
			
		||||
+
 | 
			
		||||
+```
 | 
			
		||||
+./build/src/geary
 | 
			
		||||
+```
 | 
			
		||||
+
 | 
			
		||||
+Note that certain desktop integration (such as being listed in an
 | 
			
		||||
+application menu) requires full installation to work correctly.
 | 
			
		||||
+
 | 
			
		||||
+To run the unit tests, use the Meson `test` command:
 | 
			
		||||
+
 | 
			
		||||
+```
 | 
			
		||||
+meson test -C build
 | 
			
		||||
+```
 | 
			
		||||
+
 | 
			
		||||
+API documentation will be built if `valadoc` is installed.
 | 
			
		||||
+
 | 
			
		||||
+Consult the Meson documentation for information about configuring the
 | 
			
		||||
+build, installing, and so on.
 | 
			
		||||
+
 | 
			
		||||
+Build profiles
 | 
			
		||||
+--------------
 | 
			
		||||
+
 | 
			
		||||
+Geary can be built using a number of different build profiles, which
 | 
			
		||||
+determine things like the application id, the location of stored data,
 | 
			
		||||
+the name of the application, icon and other visual elements.
 | 
			
		||||
+
 | 
			
		||||
+These can be set at build configuration time using the Meson `setup`
 | 
			
		||||
+and `configure` commands, using the standard `-Dprofile=…` option. See
 | 
			
		||||
+the `profile` option in `meson_options.txt` for the current list of
 | 
			
		||||
+supported types.
 | 
			
		||||
+
 | 
			
		||||
+Maintainers must use the `release` build profile when packaging Geary,
 | 
			
		||||
+otherwise when run it will use branding and data locations intended
 | 
			
		||||
+for development only.
 | 
			
		||||
+
 | 
			
		||||
+Note that setting the profile does not alter such things as compiler
 | 
			
		||||
+options, use the standard Meson `--buildtype` argument for that.
 | 
			
		||||
+
 | 
			
		||||
+Consult the Meson documentation for more information about configuring
 | 
			
		||||
+options.
 | 
			
		||||
+
 | 
			
		||||
+Dependencies
 | 
			
		||||
+------------
 | 
			
		||||
+
 | 
			
		||||
+Building Geary requires the following major libraries and tools:
 | 
			
		||||
+
 | 
			
		||||
+ * GTK+ 3
 | 
			
		||||
+ * WebKitGTK+ 2
 | 
			
		||||
+ * SQLite 3
 | 
			
		||||
+ * Vala
 | 
			
		||||
+
 | 
			
		||||
+See the `meson.build` file in the top-level directory for the complete
 | 
			
		||||
+list of required dependencies and minimum versions.
 | 
			
		||||
+
 | 
			
		||||
+Geary also requires SQLite to be built with the compiler flag
 | 
			
		||||
+`-DSQLITE_ENABLE_FTS3`.
 | 
			
		||||
+
 | 
			
		||||
+All required libraries and tools are available from major Linux
 | 
			
		||||
+distribution's package repositories:
 | 
			
		||||
+
 | 
			
		||||
+Installing dependencies on Fedora
 | 
			
		||||
+---------------------------------
 | 
			
		||||
+
 | 
			
		||||
+Install them by running this command:
 | 
			
		||||
+
 | 
			
		||||
+```
 | 
			
		||||
+sudo dnf install meson vala desktop-file-utils enchant2-devel \
 | 
			
		||||
+    folks-devel gcr-devel glib2-devel gmime30-devel \
 | 
			
		||||
+    gnome-online-accounts-devel gspell-devel gsound-devel \
 | 
			
		||||
+    gtk3-devel iso-codes-devel itstool json-glib-devel \
 | 
			
		||||
+    libappstream-glib-devel libgee-devel libhandy1-devel \
 | 
			
		||||
+    libpeas-devel libsecret-devel libunwind-devel libxml2-devel \
 | 
			
		||||
+    libytnef-devel sqlite-devel webkitgtk4-devel
 | 
			
		||||
+```
 | 
			
		||||
+
 | 
			
		||||
+Installing dependencies on Ubuntu/Debian
 | 
			
		||||
+----------------------------------------
 | 
			
		||||
+
 | 
			
		||||
+Install them by running this command:
 | 
			
		||||
+
 | 
			
		||||
+```
 | 
			
		||||
+sudo apt-get install meson build-essential valac \
 | 
			
		||||
+    desktop-file-utils iso-codes gettext itstool \
 | 
			
		||||
+    libappstream-glib-dev libenchant-2-dev libfolks-dev \
 | 
			
		||||
+    libgcr-3-dev libgee-0.8-dev libglib2.0-dev libgmime-3.0-dev \
 | 
			
		||||
+    libgoa-1.0-dev libgspell-1-dev libgsound-dev libgtk-3-dev \
 | 
			
		||||
+    libjson-glib-dev libhandy-1-dev libpeas-dev libsecret-1-dev \
 | 
			
		||||
+    libsqlite3-dev libunwind-dev libwebkit2gtk-4.0-dev libxml2-dev \
 | 
			
		||||
+    libytnef0-dev
 | 
			
		||||
+```
 | 
			
		||||
+
 | 
			
		||||
+And for Ubuntu Messaging Menu integration:
 | 
			
		||||
+
 | 
			
		||||
+```
 | 
			
		||||
+sudo apt-get install libmessaging-menu-dev
 | 
			
		||||
+```
 | 
			
		||||
+
 | 
			
		||||
+---
 | 
			
		||||
+Copyright © 2016 Software Freedom Conservancy Inc.  
 | 
			
		||||
+Copyright © 2018-2020 Michael Gratton <mike@vee.net>
 | 
			
		||||
diff --git a/INSTALL b/INSTALL
 | 
			
		||||
deleted file mode 100644
 | 
			
		||||
index e445a409..00000000
 | 
			
		||||
--- a/INSTALL
 | 
			
		||||
+++ /dev/null
 | 
			
		||||
@@ -1,120 +0,0 @@
 | 
			
		||||
-Building & Installing Geary
 | 
			
		||||
-===========================
 | 
			
		||||
-
 | 
			
		||||
-Building
 | 
			
		||||
---------
 | 
			
		||||
-
 | 
			
		||||
-Geary uses the Meson <http://mesonbuild.com> and Ninja
 | 
			
		||||
-<https://ninja-build.org> build systems. To build Geary, run the
 | 
			
		||||
-following commands from the top-level directory of the source code
 | 
			
		||||
-repository:
 | 
			
		||||
-
 | 
			
		||||
-    meson build
 | 
			
		||||
-    ninja -C build
 | 
			
		||||
-
 | 
			
		||||
-A convenience Makefile for development only is also provided. To use
 | 
			
		||||
-it, simply invoke make from the top-level directory.
 | 
			
		||||
-
 | 
			
		||||
-Build profiles
 | 
			
		||||
---------------
 | 
			
		||||
-
 | 
			
		||||
-Geary can be built using a number of different build profiles, which
 | 
			
		||||
-determine things like the application id, the location of stored data,
 | 
			
		||||
-the name of the application and other visual elements that distinguish
 | 
			
		||||
-release builds from other types.
 | 
			
		||||
-
 | 
			
		||||
-These can be set at build configuration time using the Meson `setup`
 | 
			
		||||
-and `configure` commands, using the standard `-Dprofile=…` option. See
 | 
			
		||||
-the `profile` option in `meson_options.txt` for the current list of
 | 
			
		||||
-supported types.
 | 
			
		||||
-
 | 
			
		||||
-Maintainers must select the `release` build profile when packaging
 | 
			
		||||
-non-test release builds, otherwise Geary will using branding and data
 | 
			
		||||
-locations intended for development only.
 | 
			
		||||
-
 | 
			
		||||
-Note that setting the profile does not alter such things as cmopiler
 | 
			
		||||
-options, use the standard Meson `--buildtype` argument for that.
 | 
			
		||||
-
 | 
			
		||||
-If built from
 | 
			
		||||
-
 | 
			
		||||
-Dependencies
 | 
			
		||||
-------------
 | 
			
		||||
-
 | 
			
		||||
-Building Geary requires the following major libraries and tools:
 | 
			
		||||
-
 | 
			
		||||
- * GTK+ 3
 | 
			
		||||
- * WebKitGTK+ 2
 | 
			
		||||
- * SQLite 3
 | 
			
		||||
- * Vala
 | 
			
		||||
-
 | 
			
		||||
-See the `meson.build` file in the top-level directory for the complete
 | 
			
		||||
-list of required dependencies and minimum versions.
 | 
			
		||||
-
 | 
			
		||||
-Geary also requires SQLite to be built with the compiler flag
 | 
			
		||||
-`-DSQLITE_ENABLE_FTS3`.
 | 
			
		||||
-
 | 
			
		||||
-All required libraries and tools are available from major Linux
 | 
			
		||||
-distribution's package repositories:
 | 
			
		||||
-
 | 
			
		||||
-Installing dependencies on Fedora
 | 
			
		||||
----------------------------------
 | 
			
		||||
-
 | 
			
		||||
-Install them by running this command:
 | 
			
		||||
-
 | 
			
		||||
-    sudo dnf install meson vala desktop-file-utils enchant2-devel \
 | 
			
		||||
-        folks-devel gcr-devel glib2-devel gmime30-devel \
 | 
			
		||||
-        gnome-online-accounts-devel gspell-devel gsound-devel \
 | 
			
		||||
-        gtk3-devel iso-codes-devel itstool json-glib-devel \
 | 
			
		||||
-        libappstream-glib-devel libgee-devel libhandy1-devel \
 | 
			
		||||
-        libpeas-devel libsecret-devel libunwind-devel libxml2-devel \
 | 
			
		||||
-        libytnef-devel sqlite-devel webkitgtk4-devel
 | 
			
		||||
-
 | 
			
		||||
-Installing dependencies on Ubuntu/Debian
 | 
			
		||||
-----------------------------------------
 | 
			
		||||
-
 | 
			
		||||
-Install them by running this command:
 | 
			
		||||
-
 | 
			
		||||
-    sudo apt-get install meson build-essential valac \
 | 
			
		||||
-        desktop-file-utils iso-codes gettext itstool \
 | 
			
		||||
-        libappstream-glib-dev libenchant-2-dev libfolks-dev \
 | 
			
		||||
-        libgcr-3-dev libgee-0.8-dev libglib2.0-dev libgmime-3.0-dev \
 | 
			
		||||
-        libgoa-1.0-dev libgspell-1-dev libgsound-dev libgtk-3-dev \
 | 
			
		||||
-        libjson-glib-dev libhandy-1-dev libpeas-dev libsecret-1-dev \
 | 
			
		||||
-        libsqlite3-dev libunwind-dev libwebkit2gtk-4.0-dev libxml2-dev \
 | 
			
		||||
-        libytnef0-dev
 | 
			
		||||
-
 | 
			
		||||
-And for Ubuntu Messaging Menu integration:
 | 
			
		||||
-
 | 
			
		||||
-    sudo apt-get install libmessaging-menu-dev
 | 
			
		||||
-
 | 
			
		||||
-Running
 | 
			
		||||
--------
 | 
			
		||||
-
 | 
			
		||||
-If you wish to try Geary before installing it, you may execute it directly
 | 
			
		||||
-from its build directory:
 | 
			
		||||
-
 | 
			
		||||
-    ./build/src/geary
 | 
			
		||||
-
 | 
			
		||||
-Note that certain desktop integration (such as being listed in an
 | 
			
		||||
-application menu) requires full installation.
 | 
			
		||||
-
 | 
			
		||||
-Installation
 | 
			
		||||
-------------
 | 
			
		||||
-
 | 
			
		||||
-After Geary has built, install it by invoking the install target:
 | 
			
		||||
-
 | 
			
		||||
-    ninja -C build install
 | 
			
		||||
-
 | 
			
		||||
-After installation, it can be uninstalled in the same way:
 | 
			
		||||
-
 | 
			
		||||
-    ninja -C build uninstall
 | 
			
		||||
-
 | 
			
		||||
-By default, Geary will install under /usr/local. To install to a
 | 
			
		||||
-different directory, set pass the --prefix to meson when performing
 | 
			
		||||
-the initial configuration step:
 | 
			
		||||
-
 | 
			
		||||
-    meson --prefix=/usr -C build
 | 
			
		||||
-
 | 
			
		||||
----
 | 
			
		||||
-Copyright © 2016 Software Freedom Conservancy Inc.  
 | 
			
		||||
-Copyright © 2018-2020 Michael Gratton <mike@vee.net>
 | 
			
		||||
diff --git a/README.md b/README.md
 | 
			
		||||
index d99cd8aa..73c4e595 100644
 | 
			
		||||
--- a/README.md
 | 
			
		||||
+++ b/README.md
 | 
			
		||||
@@ -17,11 +17,12 @@ for more information.
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-Installation & Licensing
 | 
			
		||||
-------------------------
 | 
			
		||||
+Building & Licensing
 | 
			
		||||
+--------------------
 | 
			
		||||
 
 | 
			
		||||
-Please consult the [INSTALL](./INSTALL) and [COPYING](./COPYING) files
 | 
			
		||||
-for more information.
 | 
			
		||||
+Please consult the [BUILDING.md](./BUILDING.md) and
 | 
			
		||||
+[COPYING](./COPYING) files for more information about building Geary
 | 
			
		||||
+and the licence granted by its copyright holders for redistribution.
 | 
			
		||||
 
 | 
			
		||||
 Getting in Touch
 | 
			
		||||
 ----------------
 | 
			
		||||
diff --git a/meson.build b/meson.build
 | 
			
		||||
index 1dc9e3aa..54bccfec 100644
 | 
			
		||||
--- a/meson.build
 | 
			
		||||
+++ b/meson.build
 | 
			
		||||
@@ -12,7 +12,7 @@ if profile == 'auto'
 | 
			
		||||
   if run_command('[', '-d', '.git', ']').returncode() == 0
 | 
			
		||||
     profile = 'development'
 | 
			
		||||
   else
 | 
			
		||||
-    error('No build profile specified, see INSTALL')
 | 
			
		||||
+    error('No build profile specified, see BUILDING.md')
 | 
			
		||||
   endif
 | 
			
		||||
 endif
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ elif profile == 'beta'
 | 
			
		||||
   appid_suffix = '.Beta'
 | 
			
		||||
   name_suffix = ' (Beta)'
 | 
			
		||||
 elif profile != 'release'
 | 
			
		||||
-  error('Unknown build profile specified, see INSTALL')
 | 
			
		||||
+  error('Unknown build profile specified, see BUILDING.md')
 | 
			
		||||
 endif
 | 
			
		||||
 
 | 
			
		||||
 # Configurable install dirs
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
From 436c22a4ada3538f7a624c654557471ef0099530 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 3 Oct 2020 23:33:41 +1000
 | 
			
		||||
Subject: [PATCH 039/124] README.md: Minor improvements
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 README.md | 9 +++++----
 | 
			
		||||
 1 file changed, 5 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/README.md b/README.md
 | 
			
		||||
index 73c4e595..6ffcb86b 100644
 | 
			
		||||
--- a/README.md
 | 
			
		||||
+++ b/README.md
 | 
			
		||||
@@ -6,7 +6,7 @@ Geary: Send and receive email
 | 
			
		||||
 
 | 
			
		||||
 Geary is an email application built around conversations, for the
 | 
			
		||||
 GNOME 3 desktop. It allows you to read, find and send email with a
 | 
			
		||||
-straightforward, modern interface.
 | 
			
		||||
+straight-forward, modern interface.
 | 
			
		||||
 
 | 
			
		||||
 Visit https://wiki.gnome.org/Apps/Geary for more information.
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,8 @@ Getting in Touch
 | 
			
		||||
  * Support and discussion: See the `geary` tag on [GNOME Discourse](https://discourse.gnome.org/tags/c/applications/7/geary)
 | 
			
		||||
  * Matrix channel: [#geary:gnome.org](https://gnome.element.io/#/room/#geary:gnome.org)
 | 
			
		||||
 
 | 
			
		||||
-**Code Of Conduct**
 | 
			
		||||
+Code Of Conduct
 | 
			
		||||
+---------------
 | 
			
		||||
 
 | 
			
		||||
 We follow the [Contributor Covenant](./code-of-conduct.md) as our
 | 
			
		||||
 Code of Conduct. All communications in project spaces are expected to
 | 
			
		||||
@@ -48,5 +49,5 @@ Want to help improve Geary? Here are some ways to contribute:
 | 
			
		||||
  * Donate:        https://wiki.gnome.org/Apps/Geary/Donate
 | 
			
		||||
 
 | 
			
		||||
 ---
 | 
			
		||||
-Copyright 2016 Software Freedom Conservancy Inc.  
 | 
			
		||||
-Copyright 2017-2020 Michael Gratton <mike@vee.net>
 | 
			
		||||
+Copyright © 2016 Software Freedom Conservancy Inc.  
 | 
			
		||||
+Copyright © 2017-2020 Michael Gratton <mike@vee.net>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										582
									
								
								mail-client/geary/files/0041-Update-Indonesian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										582
									
								
								mail-client/geary/files/0041-Update-Indonesian-translation.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,582 @@
 | 
			
		||||
From d2a0694866dffb73c2f42471577fb96d05e69489 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Kukuh Syafaat <kukuhsyafaat@gnome.org>
 | 
			
		||||
Date: Sun, 4 Oct 2020 08:34:11 +0000
 | 
			
		||||
Subject: [PATCH 041/124] Update Indonesian translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/id.po | 198 ++++++++++++++++++++++++++++---------------------------
 | 
			
		||||
 1 file changed, 102 insertions(+), 96 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/id.po b/po/id.po
 | 
			
		||||
index d01d1604..0e195fee 100644
 | 
			
		||||
--- a/po/id.po
 | 
			
		||||
+++ b/po/id.po
 | 
			
		||||
@@ -11,8 +11,8 @@ msgid ""
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary mainline\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
-"POT-Creation-Date: 2020-08-18 09:04+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-08-21 23:43+0700\n"
 | 
			
		||||
+"POT-Creation-Date: 2020-08-27 12:37+0000\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-08-28 22:22+0700\n"
 | 
			
		||||
 "Last-Translator: Kukuh Syafaat <kukuhsyafaat@gnome.org>\n"
 | 
			
		||||
 "Language-Team: Indonesian\n"
 | 
			
		||||
 "Language: id\n"
 | 
			
		||||
@@ -48,7 +48,7 @@ msgstr "Surel"
 | 
			
		||||
 #: desktop/geary-autostart.desktop.in.in:5
 | 
			
		||||
 #: desktop/org.gnome.Geary.appdata.xml.in.in:15
 | 
			
		||||
 #: desktop/org.gnome.Geary.desktop.in.in:5
 | 
			
		||||
-#: src/client/application/application-client.vala:32
 | 
			
		||||
+#: src/client/application/application-client.vala:33
 | 
			
		||||
 msgid "Send and receive email"
 | 
			
		||||
 msgstr "Kirim dan terima surel"
 | 
			
		||||
 
 | 
			
		||||
@@ -813,143 +813,143 @@ msgstr "Berkas telah ada di \"%s\".  Kalau ditimpa isi sebelumnya hilang."
 | 
			
		||||
 msgid "_Replace"
 | 
			
		||||
 msgstr "Timp_a"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-client.vala:33
 | 
			
		||||
+#: src/client/application/application-client.vala:34
 | 
			
		||||
 msgid "Copyright 2016 Software Freedom Conservancy Inc."
 | 
			
		||||
 msgstr "Hak Cipta 2016 Software Freedom Conservancy Inc."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-client.vala:34
 | 
			
		||||
+#: src/client/application/application-client.vala:35
 | 
			
		||||
 msgid "Copyright 2016-2020 Geary Development Team."
 | 
			
		||||
 msgstr "Hak Cipta 2016-2020 Tim Pengembang Geary."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-client.vala:36
 | 
			
		||||
+#: src/client/application/application-client.vala:37
 | 
			
		||||
 msgid "Visit the Geary web site"
 | 
			
		||||
 msgstr "Kunjungi situs web Geary"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:96
 | 
			
		||||
+#: src/client/application/application-client.vala:97
 | 
			
		||||
 msgid "Print debug logging"
 | 
			
		||||
 msgstr "Cetak log awakutu"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:99
 | 
			
		||||
+#: src/client/application/application-client.vala:100
 | 
			
		||||
 msgid "Start with the main window hidden (deprecated)"
 | 
			
		||||
 msgstr "Mulai Geary dengan jendela utama tersembunyi (usang)"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:102
 | 
			
		||||
+#: src/client/application/application-client.vala:103
 | 
			
		||||
 msgid "Enable WebKitGTK Inspector in web views"
 | 
			
		||||
 msgstr "Fungsikan WebKitGTK Inspector dalam tilikan web"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:105
 | 
			
		||||
+#: src/client/application/application-client.vala:106
 | 
			
		||||
 msgid "Log conversation monitoring"
 | 
			
		||||
 msgstr "Catat pemantauan percakapan"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:108
 | 
			
		||||
+#: src/client/application/application-client.vala:109
 | 
			
		||||
 msgid "Log IMAP network deserialization"
 | 
			
		||||
 msgstr "Log deserialisasi jaringan IMAP"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option. "Normalization" can also be called
 | 
			
		||||
 #. / "synchronization".
 | 
			
		||||
-#: src/client/application/application-client.vala:112
 | 
			
		||||
+#: src/client/application/application-client.vala:113
 | 
			
		||||
 msgid "Log folder normalization"
 | 
			
		||||
 msgstr "Catat normalisasi map"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:115
 | 
			
		||||
+#: src/client/application/application-client.vala:116
 | 
			
		||||
 msgid "Log IMAP network activity"
 | 
			
		||||
 msgstr "Log aktivitas jaringan IMAP"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option. The IMAP replay queue is how changes
 | 
			
		||||
 #. / on the server are replicated on the client.  It could
 | 
			
		||||
 #. / also be called the IMAP events queue.
 | 
			
		||||
-#: src/client/application/application-client.vala:120
 | 
			
		||||
+#: src/client/application/application-client.vala:121
 | 
			
		||||
 msgid "Log IMAP replay queue"
 | 
			
		||||
 msgstr "Catat antrian putar ulang IMAP"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:123
 | 
			
		||||
+#: src/client/application/application-client.vala:124
 | 
			
		||||
 msgid "Log SMTP network activity"
 | 
			
		||||
 msgstr "Log aktivitas jaringan SMTP"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:126
 | 
			
		||||
+#: src/client/application/application-client.vala:127
 | 
			
		||||
 msgid "Log database queries (generates lots of messages)"
 | 
			
		||||
 msgstr "Catat kuiri basis data (menimbulkan banyak pesan)"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:129
 | 
			
		||||
+#: src/client/application/application-client.vala:130
 | 
			
		||||
 msgid "Perform a graceful quit"
 | 
			
		||||
 msgstr "Keluar secara anggun"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-client.vala:131
 | 
			
		||||
+#: src/client/application/application-client.vala:132
 | 
			
		||||
 msgid "Open a new window"
 | 
			
		||||
 msgstr "Buka suatu jendela baru"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:134
 | 
			
		||||
+#: src/client/application/application-client.vala:135
 | 
			
		||||
 msgid "Revoke all pinned TLS server certificates"
 | 
			
		||||
 msgstr "Cabut semua sertifikat peladen TLS yang di-pin"
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line option
 | 
			
		||||
-#: src/client/application/application-client.vala:137
 | 
			
		||||
+#: src/client/application/application-client.vala:138
 | 
			
		||||
 msgid "Display program version"
 | 
			
		||||
 msgstr "Tampilkan versi program"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:261
 | 
			
		||||
+#: src/client/application/application-client.vala:262
 | 
			
		||||
 msgid "Geary version"
 | 
			
		||||
 msgstr "Versi Geary"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:263
 | 
			
		||||
+#: src/client/application/application-client.vala:264
 | 
			
		||||
 msgid "Geary revision"
 | 
			
		||||
 msgstr "Revisi Geary"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:265
 | 
			
		||||
+#: src/client/application/application-client.vala:266
 | 
			
		||||
 msgid "GTK version"
 | 
			
		||||
 msgstr "Versi GTK"
 | 
			
		||||
 
 | 
			
		||||
 #. / Applciation runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:272
 | 
			
		||||
+#: src/client/application/application-client.vala:273
 | 
			
		||||
 msgid "GLib version"
 | 
			
		||||
 msgstr "Versi GLib"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:279
 | 
			
		||||
+#: src/client/application/application-client.vala:280
 | 
			
		||||
 msgid "WebKitGTK version"
 | 
			
		||||
 msgstr "Versi WebKitGTK"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:286
 | 
			
		||||
+#: src/client/application/application-client.vala:287
 | 
			
		||||
 msgid "Desktop environment"
 | 
			
		||||
 msgstr "Lingkungan desktop"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: This is the file type displayed for
 | 
			
		||||
 #. attachments with unknown file types.
 | 
			
		||||
-#: src/client/application/application-client.vala:288
 | 
			
		||||
+#: src/client/application/application-client.vala:289
 | 
			
		||||
 #: src/client/components/components-attachment-pane.vala:91
 | 
			
		||||
 msgid "Unknown"
 | 
			
		||||
 msgstr "Tak dikenal"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:318
 | 
			
		||||
+#: src/client/application/application-client.vala:293
 | 
			
		||||
 msgid "Distribution name"
 | 
			
		||||
 msgstr "Nama distribusi"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:323
 | 
			
		||||
+#: src/client/application/application-client.vala:298
 | 
			
		||||
 msgid "Distribution release"
 | 
			
		||||
 msgstr "Rilis distribusi"
 | 
			
		||||
 
 | 
			
		||||
 #. / Application runtime information label
 | 
			
		||||
-#: src/client/application/application-client.vala:331
 | 
			
		||||
+#: src/client/application/application-client.vala:303
 | 
			
		||||
 msgid "Installation prefix"
 | 
			
		||||
 msgstr "Prefiks instalasi"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-client.vala:584
 | 
			
		||||
+#: src/client/application/application-client.vala:558
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "About %s"
 | 
			
		||||
 msgstr "Tentang %s"
 | 
			
		||||
@@ -957,7 +957,7 @@ msgstr "Tentang %s"
 | 
			
		||||
 #. Translators: add your name and email address to receive
 | 
			
		||||
 #. credit in the About dialog For example: Yamada Taro
 | 
			
		||||
 #. <yamada.taro@example.com>
 | 
			
		||||
-#: src/client/application/application-client.vala:588
 | 
			
		||||
+#: src/client/application/application-client.vala:562
 | 
			
		||||
 msgid "translator-credits"
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Andika Triwidada <andika@gmail.com>, 2012, 2013, 2016, 2017, 2019, 2020\n"
 | 
			
		||||
@@ -966,13 +966,13 @@ msgstr ""
 | 
			
		||||
 
 | 
			
		||||
 #. / Warning printed to the console when a deprecated
 | 
			
		||||
 #. / command line option is used.
 | 
			
		||||
-#: src/client/application/application-client.vala:1066
 | 
			
		||||
+#: src/client/application/application-client.vala:1046
 | 
			
		||||
 msgid "The `--hidden` option is deprecated and will be removed in the future."
 | 
			
		||||
 msgstr "Opsi '--hidden' usang dan akan dihapus di masa mendatang."
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line warning, string substitution
 | 
			
		||||
 #. / is the given argument
 | 
			
		||||
-#: src/client/application/application-client.vala:1099
 | 
			
		||||
+#: src/client/application/application-client.vala:1079
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Unrecognised program argument: “%s”"
 | 
			
		||||
 msgstr "Argumen program tidak dikenal: \"%s\""
 | 
			
		||||
@@ -1079,12 +1079,12 @@ msgid_plural "Conversations un-labelled as %s"
 | 
			
		||||
 msgstr[0] "Label %s dihapus dari percakapan"
 | 
			
		||||
 msgstr[1] "Label %s dihapus dari percakapan"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-controller.vala:1297
 | 
			
		||||
+#: src/client/application/application-controller.vala:1320
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Unable to open the database for %s"
 | 
			
		||||
 msgstr "Tak bisa membuka basis data bagi %s"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-controller.vala:1298
 | 
			
		||||
+#: src/client/application/application-controller.vala:1321
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "There was an error opening the local mail database for this account. This is "
 | 
			
		||||
@@ -1108,20 +1108,20 @@ msgstr ""
 | 
			
		||||
 "Membangun ulang basis data akan menghancurkan semua surel lokal dan "
 | 
			
		||||
 "lampirannya. <b>Surat pada peladen Anda tak akan terpengaruh.</b>"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-controller.vala:1300
 | 
			
		||||
+#: src/client/application/application-controller.vala:1323
 | 
			
		||||
 msgid "_Rebuild"
 | 
			
		||||
 msgstr "_Bangun Ulang"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-controller.vala:1300
 | 
			
		||||
+#: src/client/application/application-controller.vala:1323
 | 
			
		||||
 msgid "E_xit"
 | 
			
		||||
 msgstr "_Keluar"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-controller.vala:1310
 | 
			
		||||
+#: src/client/application/application-controller.vala:1333
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Unable to rebuild database for “%s”"
 | 
			
		||||
 msgstr "Tak bisa membangun ulang basis data bagi \"%s\""
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-controller.vala:1311
 | 
			
		||||
+#: src/client/application/application-controller.vala:1334
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "Error during rebuild:\n"
 | 
			
		||||
@@ -1134,34 +1134,34 @@ msgstr ""
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: The label for an in-app notification. The
 | 
			
		||||
 #. / string substitution is a list of recipients of the email.
 | 
			
		||||
-#: src/client/application/application-controller.vala:1478
 | 
			
		||||
+#: src/client/application/application-controller.vala:1501
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email sent to %s"
 | 
			
		||||
 msgstr "Surel dikirim ke %s"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: The label for an in-app notification. The
 | 
			
		||||
 #. / string substitution is a list of recipients of the email.
 | 
			
		||||
-#: src/client/application/application-controller.vala:2509
 | 
			
		||||
+#: src/client/application/application-controller.vala:2491
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email to %s queued for delivery"
 | 
			
		||||
 msgstr "Surel ke %s diantrikan untuk pengiriman"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: The label for an in-app notification. The
 | 
			
		||||
 #. / string substitution is a list of recipients of the email.
 | 
			
		||||
-#: src/client/application/application-controller.vala:2573
 | 
			
		||||
+#: src/client/application/application-controller.vala:2555
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email to %s saved"
 | 
			
		||||
 msgstr "Surel ke %s disimpan"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: A label for an in-app notification.
 | 
			
		||||
-#: src/client/application/application-controller.vala:2588
 | 
			
		||||
-#: src/client/application/application-controller.vala:2646
 | 
			
		||||
+#: src/client/application/application-controller.vala:2570
 | 
			
		||||
+#: src/client/application/application-controller.vala:2628
 | 
			
		||||
 msgid "Composer could not be restored"
 | 
			
		||||
 msgstr "Penyusun tidak dapat dipulihkan"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: The label for an in-app notification. The
 | 
			
		||||
 #. / string substitution is a list of recipients of the email.
 | 
			
		||||
-#: src/client/application/application-controller.vala:2631
 | 
			
		||||
+#: src/client/application/application-controller.vala:2613
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Email to %s discarded"
 | 
			
		||||
 msgstr "Surel ke %s dibuang"
 | 
			
		||||
@@ -1304,7 +1304,7 @@ msgstr "Pemeriksa"
 | 
			
		||||
 #. / Translators: Title for Inspector logs pane
 | 
			
		||||
 #. / Translators: Title for problem report dialog logs pane
 | 
			
		||||
 #: src/client/components/components-inspector.vala:93
 | 
			
		||||
-#: src/client/dialogs/dialogs-problem-details-dialog.vala:102
 | 
			
		||||
+#: src/client/dialogs/dialogs-problem-details-dialog.vala:101
 | 
			
		||||
 msgid "Logs"
 | 
			
		||||
 msgstr "Log"
 | 
			
		||||
 
 | 
			
		||||
@@ -1312,21 +1312,21 @@ msgstr "Log"
 | 
			
		||||
 #. / Translators: Title for problem report system information
 | 
			
		||||
 #. / pane
 | 
			
		||||
 #: src/client/components/components-inspector.vala:97
 | 
			
		||||
-#: src/client/dialogs/dialogs-problem-details-dialog.vala:105
 | 
			
		||||
+#: src/client/dialogs/dialogs-problem-details-dialog.vala:104
 | 
			
		||||
 msgid "System"
 | 
			
		||||
 msgstr "Sistem"
 | 
			
		||||
 
 | 
			
		||||
 #. Button label for saving problem report information
 | 
			
		||||
 #: src/client/components/components-inspector.vala:226
 | 
			
		||||
 #: src/client/components/components-inspector.vala:229
 | 
			
		||||
-#: src/client/dialogs/dialogs-problem-details-dialog.vala:221
 | 
			
		||||
-#: src/client/dialogs/dialogs-problem-details-dialog.vala:224
 | 
			
		||||
-#: ui/problem-details-dialog.ui:42
 | 
			
		||||
+#: src/client/dialogs/dialogs-problem-details-dialog.vala:220
 | 
			
		||||
+#: src/client/dialogs/dialogs-problem-details-dialog.vala:223
 | 
			
		||||
+#: ui/problem-details-dialog.ui:47
 | 
			
		||||
 msgid "Save As"
 | 
			
		||||
 msgstr "Simpan sebagai"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/components/components-inspector.vala:230
 | 
			
		||||
-#: src/client/dialogs/dialogs-problem-details-dialog.vala:225
 | 
			
		||||
+#: src/client/dialogs/dialogs-problem-details-dialog.vala:224
 | 
			
		||||
 #: ui/accounts_editor_servers_pane.ui:17
 | 
			
		||||
 msgid "Cancel"
 | 
			
		||||
 msgstr "Batal"
 | 
			
		||||
@@ -1375,7 +1375,7 @@ msgid "Preferences"
 | 
			
		||||
 msgstr "Preferensi"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Preferences page title
 | 
			
		||||
-#: src/client/components/components-preferences-window.vala:252
 | 
			
		||||
+#: src/client/components/components-preferences-window.vala:250
 | 
			
		||||
 msgid "Plugins"
 | 
			
		||||
 msgstr "Pengaya"
 | 
			
		||||
 
 | 
			
		||||
@@ -1448,6 +1448,22 @@ msgstr "Lihat rincian teknis tentang kesalahan tersebut"
 | 
			
		||||
 msgid "_Retry"
 | 
			
		||||
 msgstr "_Ulangi"
 | 
			
		||||
 
 | 
			
		||||
+#: src/client/components/components-reflow-box.c:454
 | 
			
		||||
+msgid "Spacing"
 | 
			
		||||
+msgstr "Jarak"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-reflow-box.c:455
 | 
			
		||||
+msgid "Spacing between children"
 | 
			
		||||
+msgstr "Jarak antara anak"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-reflow-box.c:470
 | 
			
		||||
+msgid "Row spacing"
 | 
			
		||||
+msgstr "Jarak antar baris"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-reflow-box.c:471
 | 
			
		||||
+msgid "Spacing between rows of children"
 | 
			
		||||
+msgstr "Jarak antar baris anak "
 | 
			
		||||
+
 | 
			
		||||
 #. / Translators: Search entry placeholder text
 | 
			
		||||
 #: src/client/components/components-search-bar.vala:12
 | 
			
		||||
 #: src/client/folder-list/folder-list-search-branch.vala:53
 | 
			
		||||
@@ -1551,7 +1567,7 @@ msgid "_OK"
 | 
			
		||||
 msgstr "_OK"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/components/stock.vala:19
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:388
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:392
 | 
			
		||||
 #: ui/password-dialog.glade:196
 | 
			
		||||
 msgid "_Cancel"
 | 
			
		||||
 msgstr "Ba_tal"
 | 
			
		||||
@@ -1577,7 +1593,7 @@ msgid "_Help"
 | 
			
		||||
 msgstr "_Bantuan"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/components/stock.vala:26
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:387
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:391
 | 
			
		||||
 #: ui/components-attachment-pane-menus.ui:7
 | 
			
		||||
 msgid "_Open"
 | 
			
		||||
 msgstr "_Buka"
 | 
			
		||||
@@ -2038,8 +2054,8 @@ msgstr "Terjadi galat saat memroses sertifikat peladen"
 | 
			
		||||
 #. / Translators: Title for problem report dialog error
 | 
			
		||||
 #. / information pane
 | 
			
		||||
 #. Dialog title for displaying technical details of a problem. Same as the button that invokes it.
 | 
			
		||||
-#: src/client/dialogs/dialogs-problem-details-dialog.vala:100
 | 
			
		||||
-#: ui/problem-details-dialog.ui:12
 | 
			
		||||
+#: src/client/dialogs/dialogs-problem-details-dialog.vala:99
 | 
			
		||||
+#: ui/problem-details-dialog.ui:17
 | 
			
		||||
 msgid "Details"
 | 
			
		||||
 msgstr "Detail"
 | 
			
		||||
 
 | 
			
		||||
@@ -2091,12 +2107,6 @@ msgid_plural "%d results"
 | 
			
		||||
 msgstr[0] "%d hasil"
 | 
			
		||||
 msgstr[1] "%d hasil"
 | 
			
		||||
 
 | 
			
		||||
-#. Translators: This is an internal plugin so this name does not need
 | 
			
		||||
-#. to be tanslated
 | 
			
		||||
-#: src/client/plugin/desktop-notifications/desktop-notifications.plugin.desktop.in:6
 | 
			
		||||
-msgid "Desktop Notifications"
 | 
			
		||||
-msgstr "Pemberitahuan Desktop"
 | 
			
		||||
-
 | 
			
		||||
 #. / Notification body when a message as been received
 | 
			
		||||
 #. / and other unread messages have not been
 | 
			
		||||
 #. / seen. First string substitution is the message
 | 
			
		||||
@@ -2194,17 +2204,11 @@ msgstr "Kirim"
 | 
			
		||||
 #. Translators: Info bar button label for editing a draft
 | 
			
		||||
 #. email
 | 
			
		||||
 #: src/client/plugin/email-templates/email-templates.vala:305
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:332
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:336
 | 
			
		||||
 #: src/client/plugin/special-folders/special-folders.vala:187
 | 
			
		||||
 msgid "Edit"
 | 
			
		||||
 msgstr "Sunting"
 | 
			
		||||
 
 | 
			
		||||
-#. Translators: This is an internal plugin so this name does not need
 | 
			
		||||
-#. to be tanslated
 | 
			
		||||
-#: src/client/plugin/folder-highlight/folder-highlight.plugin.desktop.in:6
 | 
			
		||||
-msgid "Folder Highlight"
 | 
			
		||||
-msgstr "Sorot Folder"
 | 
			
		||||
-
 | 
			
		||||
 #. / Translators: Menu item label for invoking mail
 | 
			
		||||
 #. / merge in composer
 | 
			
		||||
 #. / Translators: File chooser title after invoking mail
 | 
			
		||||
@@ -2212,9 +2216,9 @@ msgstr "Sorot Folder"
 | 
			
		||||
 #. Translators: The name of the folder used to
 | 
			
		||||
 #. display merged email
 | 
			
		||||
 #: src/client/plugin/mail-merge/mail-merge.plugin.desktop.in:5
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:284
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:385
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:484
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:288
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:389
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:488
 | 
			
		||||
 msgid "Mail Merge"
 | 
			
		||||
 msgstr "Gabungan Surat"
 | 
			
		||||
 
 | 
			
		||||
@@ -2237,31 +2241,33 @@ msgstr "Jeda"
 | 
			
		||||
 #. Translators: Info bar description for the mail merge
 | 
			
		||||
 #. folder. The first string substitution the number of email
 | 
			
		||||
 #. already sent, the second is the total number to send.
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:239
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:240
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Sent %u of %u"
 | 
			
		||||
-msgstr "Terkirim %u dari %u"
 | 
			
		||||
+msgid_plural "Sent %u of %u"
 | 
			
		||||
+msgstr[0] "Terkirim %u dari %u"
 | 
			
		||||
+msgstr[1] "Terkirim %u dari %u"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Infobar status label for an email mail merge
 | 
			
		||||
 #. template
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:320
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:324
 | 
			
		||||
 msgid "Mail merge template"
 | 
			
		||||
 msgstr "Templat gabungan surat"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Info bar button label for performing a
 | 
			
		||||
 #. mail-merge on an email template
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:324
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:328
 | 
			
		||||
 msgid "Merge"
 | 
			
		||||
 msgstr "Gabung"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Action bar menu button label for
 | 
			
		||||
 #. / mail-merge plugin
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:373
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:377
 | 
			
		||||
 msgid "Insert field"
 | 
			
		||||
 msgstr "Sisipkan bidang"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: File chooser filer label
 | 
			
		||||
-#: src/client/plugin/mail-merge/mail-merge.vala:392
 | 
			
		||||
+#: src/client/plugin/mail-merge/mail-merge.vala:396
 | 
			
		||||
 msgid "Comma separated values (CSV)"
 | 
			
		||||
 msgstr "Nilai yang dipisahkan koma (CSV)"
 | 
			
		||||
 
 | 
			
		||||
@@ -2278,12 +2284,6 @@ msgstr "Menampilkan pemberitahuan Menu Perpesanan Unity atas surat baru"
 | 
			
		||||
 msgid "%s — New Messages"
 | 
			
		||||
 msgstr "%s - Pesan Baru"
 | 
			
		||||
 
 | 
			
		||||
-#. Translators: This is an internal plugin so this name does not need
 | 
			
		||||
-#. to be tanslated.
 | 
			
		||||
-#: src/client/plugin/notification-badge/notification-badge.plugin.desktop.in:6
 | 
			
		||||
-msgid "Notification Badge"
 | 
			
		||||
-msgstr "Lencana Pemberitahuan"
 | 
			
		||||
-
 | 
			
		||||
 #: src/client/plugin/sent-sound/sent-sound.plugin.desktop.in:4
 | 
			
		||||
 msgid "Sent Sound"
 | 
			
		||||
 msgstr "Suara Terkirim"
 | 
			
		||||
@@ -2292,12 +2292,6 @@ msgstr "Suara Terkirim"
 | 
			
		||||
 msgid "Plays the desktop sent-mail sound when an email is sent"
 | 
			
		||||
 msgstr "Memutar suara surat-terkirim desktopk etika surel dikirim"
 | 
			
		||||
 
 | 
			
		||||
-#. Translators: This is an internal plugin so this name does not need
 | 
			
		||||
-#. to be tanslated.
 | 
			
		||||
-#: src/client/plugin/special-folders/special-folders.plugin.desktop.in:6
 | 
			
		||||
-msgid "Special Folders"
 | 
			
		||||
-msgstr "Folder Khusus"
 | 
			
		||||
-
 | 
			
		||||
 #. Translators: Info bar button label for emptying
 | 
			
		||||
 #. trash/spam folders
 | 
			
		||||
 #: src/client/plugin/special-folders/special-folders.vala:167
 | 
			
		||||
@@ -3130,7 +3124,7 @@ msgstr "Buka lampiran yang dipilih"
 | 
			
		||||
 msgid "Save _All"
 | 
			
		||||
 msgstr "Simpan Semu_a"
 | 
			
		||||
 
 | 
			
		||||
-#: ui/components-inspector-error-view.ui:33
 | 
			
		||||
+#: ui/components-inspector-error-view.ui:31
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "If the problem is serious or persists, please save and send these details to "
 | 
			
		||||
 "one of the <a href=\"https://wiki.gnome.org/Apps/Geary/Contact\">contact "
 | 
			
		||||
@@ -3142,13 +3136,13 @@ msgstr ""
 | 
			
		||||
 "lampirkan ke sebuah <a href=\"https://wiki.gnome.org/Apps/Geary/ReportingABug"
 | 
			
		||||
 "\">laporan kutu baru</a>."
 | 
			
		||||
 
 | 
			
		||||
-#: ui/components-inspector-error-view.ui:49
 | 
			
		||||
+#: ui/components-inspector-error-view.ui:47
 | 
			
		||||
 msgid "Details:"
 | 
			
		||||
 msgstr "Detail:"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
-#: ui/components-inspector.ui:19 ui/problem-details-dialog.ui:19
 | 
			
		||||
+#: ui/components-inspector.ui:19 ui/problem-details-dialog.ui:24
 | 
			
		||||
 msgid "Search for matching log entries"
 | 
			
		||||
 msgstr "Cari entri log yang cocok"
 | 
			
		||||
 
 | 
			
		||||
@@ -3164,13 +3158,13 @@ msgstr "Tambahkan entri penanda ke log"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
-#: ui/components-inspector.ui:81 ui/problem-details-dialog.ui:46
 | 
			
		||||
+#: ui/components-inspector.ui:81 ui/problem-details-dialog.ui:51
 | 
			
		||||
 msgid "Save logs entries and details"
 | 
			
		||||
 msgstr "Simpan entri log dan rincian"
 | 
			
		||||
 
 | 
			
		||||
 #. Tooltip for inspector button
 | 
			
		||||
 #. Tooltip for problem report button
 | 
			
		||||
-#: ui/components-inspector.ui:101 ui/problem-details-dialog.ui:62
 | 
			
		||||
+#: ui/components-inspector.ui:101 ui/problem-details-dialog.ui:67
 | 
			
		||||
 msgid "Copy to clipboard"
 | 
			
		||||
 msgstr "Salin ke papan klip"
 | 
			
		||||
 
 | 
			
		||||
@@ -3731,6 +3725,18 @@ msgstr "Otentik_asikan"
 | 
			
		||||
 msgid "Geary update in progress…"
 | 
			
		||||
 msgstr "Pemutakhiran Geary sedang berlangsung…"
 | 
			
		||||
 
 | 
			
		||||
+#~ msgid "Desktop Notifications"
 | 
			
		||||
+#~ msgstr "Pemberitahuan Desktop"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Folder Highlight"
 | 
			
		||||
+#~ msgstr "Sorot Folder"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Notification Badge"
 | 
			
		||||
+#~ msgstr "Lencana Pemberitahuan"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Special Folders"
 | 
			
		||||
+#~ msgstr "Folder Khusus"
 | 
			
		||||
+
 | 
			
		||||
 #~ msgid "Displays desktop notifications when new email is delivered"
 | 
			
		||||
 #~ msgstr "Menampilkan pemberitahuan desktop ketika ada surat baru terkirim"
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
From d5512753459d6c1324fae48b1e6fc08526515932 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Jordi Mas <jmas@softcatala.org>
 | 
			
		||||
Date: Wed, 7 Oct 2020 08:14:38 +0200
 | 
			
		||||
Subject: [PATCH 043/124] Fix accute in Catalan translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 help/ca/ca.po | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/help/ca/ca.po b/help/ca/ca.po
 | 
			
		||||
index ae243358..dbacd7ea 100644
 | 
			
		||||
--- a/help/ca/ca.po
 | 
			
		||||
+++ b/help/ca/ca.po
 | 
			
		||||
@@ -1508,5 +1508,5 @@ msgid ""
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "En el mode text pla, el text es justificarà automàticament mitjançant salts "
 | 
			
		||||
 "de línies de manera que no tinguin més de 74 caràcters d'ample i, el text "
 | 
			
		||||
-"sagnat es justificarà i se citarà utilitzant el caràcter \">,\" per a cada"
 | 
			
		||||
+"sagnat es justificarà i se citarà utilitzant el caràcter \">\" per a cada"
 | 
			
		||||
 " nivell de cita."
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3431
									
								
								mail-client/geary/files/0044-Update-Greek-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3431
									
								
								mail-client/geary/files/0044-Update-Greek-translation.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										172
									
								
								mail-client/geary/files/0045-Drop-saving-the-paned-width.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								mail-client/geary/files/0045-Drop-saving-the-paned-width.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
From a1f74d24ff11869f108dc42016a648ce45999b70 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Thu, 16 Jan 2020 13:28:13 +0100
 | 
			
		||||
Subject: [PATCH 045/124] Drop saving the paned width
 | 
			
		||||
 | 
			
		||||
This is needed to replace GtkPaned by HdyLeaflet. This breaks syncing
 | 
			
		||||
the size of the headerbar with the rest of the window, it will be fixed
 | 
			
		||||
in a later commit.
 | 
			
		||||
---
 | 
			
		||||
 desktop/org.gnome.Geary.gschema.xml           | 24 -------------------
 | 
			
		||||
 .../application-configuration.vala            | 22 -----------------
 | 
			
		||||
 .../application/application-main-window.vala  | 17 -------------
 | 
			
		||||
 src/client/components/main-toolbar.vala       |  9 -------
 | 
			
		||||
 4 files changed, 72 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/desktop/org.gnome.Geary.gschema.xml b/desktop/org.gnome.Geary.gschema.xml
 | 
			
		||||
index bbbadc36..9850dffd 100644
 | 
			
		||||
--- a/desktop/org.gnome.Geary.gschema.xml
 | 
			
		||||
+++ b/desktop/org.gnome.Geary.gschema.xml
 | 
			
		||||
@@ -21,24 +21,6 @@
 | 
			
		||||
         <description>The last recorded height of the application window.</description>
 | 
			
		||||
     </key>
 | 
			
		||||
 
 | 
			
		||||
-    <key name="folder-list-pane-position" type="i">
 | 
			
		||||
-        <default>100</default>
 | 
			
		||||
-        <summary>Position of folder list pane</summary>
 | 
			
		||||
-        <description>Position of the folder list Paned grabber.</description>
 | 
			
		||||
-    </key>
 | 
			
		||||
-
 | 
			
		||||
-    <key name="folder-list-pane-position-horizontal" type="i">
 | 
			
		||||
-        <default>-1</default>
 | 
			
		||||
-        <summary>Position of folder list pane when horizontal</summary>
 | 
			
		||||
-        <description>Position of the folder list Paned grabber in the horizontal orientation.</description>
 | 
			
		||||
-    </key>
 | 
			
		||||
-
 | 
			
		||||
-    <key name="folder-list-pane-position-vertical" type="i">
 | 
			
		||||
-        <default>200</default>
 | 
			
		||||
-        <summary>Position of folder list pane when vertical</summary>
 | 
			
		||||
-        <description>Position of the folder list Paned grabber in the vertical orientation.</description>
 | 
			
		||||
-    </key>
 | 
			
		||||
-
 | 
			
		||||
     <key name="folder-list-pane-horizontal" type="b">
 | 
			
		||||
         <default>true</default>
 | 
			
		||||
         <summary>Orientation of the folder list pane</summary>
 | 
			
		||||
@@ -51,12 +33,6 @@
 | 
			
		||||
         <description>True if the formatting toolbar in the composer is shown.</description>
 | 
			
		||||
     </key>
 | 
			
		||||
 
 | 
			
		||||
-    <key name="messages-pane-position" type="i">
 | 
			
		||||
-        <default>250</default>
 | 
			
		||||
-        <summary>Position of message list pane</summary>
 | 
			
		||||
-        <description>Position of the message list Paned grabber.</description>
 | 
			
		||||
-    </key>
 | 
			
		||||
-
 | 
			
		||||
     <key name="autoselect" type="b">
 | 
			
		||||
         <default>true</default>
 | 
			
		||||
         <summary>Autoselect next message</summary>
 | 
			
		||||
diff --git a/src/client/application/application-configuration.vala b/src/client/application/application-configuration.vala
 | 
			
		||||
index 00c359c9..51a11bbf 100644
 | 
			
		||||
--- a/src/client/application/application-configuration.vala
 | 
			
		||||
+++ b/src/client/application/application-configuration.vala
 | 
			
		||||
@@ -20,11 +20,7 @@ public class Application.Configuration : Geary.BaseObject {
 | 
			
		||||
     public const string CONVERSATION_VIEWER_ZOOM_KEY = "conversation-viewer-zoom";
 | 
			
		||||
     public const string DISPLAY_PREVIEW_KEY = "display-preview";
 | 
			
		||||
     public const string FOLDER_LIST_PANE_HORIZONTAL_KEY = "folder-list-pane-horizontal";
 | 
			
		||||
-    public const string FOLDER_LIST_PANE_POSITION_HORIZONTAL_KEY = "folder-list-pane-position-horizontal";
 | 
			
		||||
-    public const string FOLDER_LIST_PANE_POSITION_KEY = "folder-list-pane-position";
 | 
			
		||||
-    public const string FOLDER_LIST_PANE_POSITION_VERTICAL_KEY = "folder-list-pane-position-vertical";
 | 
			
		||||
     public const string FORMATTING_TOOLBAR_VISIBLE = "formatting-toolbar-visible";
 | 
			
		||||
-    public const string MESSAGES_PANE_POSITION_KEY = "messages-pane-position";
 | 
			
		||||
     public const string OPTIONAL_PLUGINS = "optional-plugins";
 | 
			
		||||
     public const string SEARCH_STRATEGY_KEY = "search-strategy";
 | 
			
		||||
     public const string SINGLE_KEY_SHORTCUTS = "single-key-shortcuts";
 | 
			
		||||
@@ -90,19 +86,6 @@ public class Application.Configuration : Geary.BaseObject {
 | 
			
		||||
         get { return settings.get_boolean(WINDOW_MAXIMIZE_KEY); }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public int folder_list_pane_position_old {
 | 
			
		||||
-        get { return settings.get_int(FOLDER_LIST_PANE_POSITION_KEY); }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    public int folder_list_pane_position_horizontal {
 | 
			
		||||
-        get { return settings.get_int(FOLDER_LIST_PANE_POSITION_HORIZONTAL_KEY); }
 | 
			
		||||
-        set { settings.set_int(FOLDER_LIST_PANE_POSITION_HORIZONTAL_KEY, value); }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    public int folder_list_pane_position_vertical {
 | 
			
		||||
-        get { return settings.get_int(FOLDER_LIST_PANE_POSITION_VERTICAL_KEY); }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     public bool folder_list_pane_horizontal {
 | 
			
		||||
         get { return settings.get_boolean(FOLDER_LIST_PANE_HORIZONTAL_KEY); }
 | 
			
		||||
     }
 | 
			
		||||
@@ -112,11 +95,6 @@ public class Application.Configuration : Geary.BaseObject {
 | 
			
		||||
         set { settings.set_boolean(FORMATTING_TOOLBAR_VISIBLE, value); }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public int messages_pane_position {
 | 
			
		||||
-        get { return settings.get_int(MESSAGES_PANE_POSITION_KEY); }
 | 
			
		||||
-        set { settings.set_int(MESSAGES_PANE_POSITION_KEY, value); }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     public bool autoselect {
 | 
			
		||||
         get { return settings.get_boolean(AUTOSELECT_KEY); }
 | 
			
		||||
     }
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 47749019..48f8bae6 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -1130,15 +1130,10 @@ public class Application.MainWindow :
 | 
			
		||||
         // This code both loads AND saves the pane positions with live updating. This is more
 | 
			
		||||
         // resilient against crashes because the value in dconf changes *immediately*, and
 | 
			
		||||
         // stays saved in the event of a crash.
 | 
			
		||||
-        config.bind(Configuration.MESSAGES_PANE_POSITION_KEY, this.conversations_paned, "position");
 | 
			
		||||
         config.bind(Configuration.WINDOW_WIDTH_KEY, this, "window-width");
 | 
			
		||||
         config.bind(Configuration.WINDOW_HEIGHT_KEY, this, "window-height");
 | 
			
		||||
         config.bind(Configuration.WINDOW_MAXIMIZE_KEY, this, "window-maximized");
 | 
			
		||||
         // Update to layout
 | 
			
		||||
-        if (config.folder_list_pane_position_horizontal == -1) {
 | 
			
		||||
-            config.folder_list_pane_position_horizontal = config.folder_list_pane_position_old;
 | 
			
		||||
-            config.messages_pane_position += config.folder_list_pane_position_old;
 | 
			
		||||
-        }
 | 
			
		||||
         config.settings.changed[
 | 
			
		||||
             Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY
 | 
			
		||||
         ].connect(on_change_orientation);
 | 
			
		||||
@@ -1655,23 +1650,11 @@ public class Application.MainWindow :
 | 
			
		||||
         this.folder_paned.orientation = horizontal ? Gtk.Orientation.HORIZONTAL :
 | 
			
		||||
             Gtk.Orientation.VERTICAL;
 | 
			
		||||
 
 | 
			
		||||
-        int folder_list_width =
 | 
			
		||||
-            this.application.config.folder_list_pane_position_horizontal;
 | 
			
		||||
         if (horizontal) {
 | 
			
		||||
-            if (!initial)
 | 
			
		||||
-                this.conversations_paned.position += folder_list_width;
 | 
			
		||||
             this.folder_box.pack_start(status_bar, false, false);
 | 
			
		||||
         } else {
 | 
			
		||||
-            if (!initial)
 | 
			
		||||
-                this.conversations_paned.position -= folder_list_width;
 | 
			
		||||
             this.conversation_list_box.pack_start(status_bar, false, false);
 | 
			
		||||
         }
 | 
			
		||||
-
 | 
			
		||||
-        this.application.config.bind(
 | 
			
		||||
-            horizontal
 | 
			
		||||
-            ? Configuration.FOLDER_LIST_PANE_POSITION_HORIZONTAL_KEY
 | 
			
		||||
-            : Configuration.FOLDER_LIST_PANE_POSITION_VERTICAL_KEY,
 | 
			
		||||
-            this.folder_paned, "position");
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void update_headerbar() {
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index 31f87df6..aa263253 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -59,15 +59,6 @@ public class MainToolbar : Gtk.Box {
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public MainToolbar(Application.Configuration config) {
 | 
			
		||||
-        // Sync headerbar width with left pane
 | 
			
		||||
-        config.bind(
 | 
			
		||||
-            Application.Configuration.MESSAGES_PANE_POSITION_KEY,
 | 
			
		||||
-            this,
 | 
			
		||||
-            "left-pane-width",
 | 
			
		||||
-            SettingsBindFlags.GET
 | 
			
		||||
-        );
 | 
			
		||||
-        this.bind_property("left-pane-width", this.folder_header, "width-request", BindingFlags.SYNC_CREATE);
 | 
			
		||||
-
 | 
			
		||||
         if (config.desktop_environment != UNITY) {
 | 
			
		||||
             this.bind_property("account", this.folder_header, "title", BindingFlags.SYNC_CREATE);
 | 
			
		||||
             this.bind_property("folder", this.folder_header, "subtitle", BindingFlags.SYNC_CREATE);
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										150
									
								
								mail-client/geary/files/0046-Drop-the-2-panes-mode.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								mail-client/geary/files/0046-Drop-the-2-panes-mode.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
From fb311e1c822fb41782c7ff07525c77732a52a971 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Thu, 16 Jan 2020 13:17:58 +0100
 | 
			
		||||
Subject: [PATCH 046/124] Drop the 2-panes mode
 | 
			
		||||
 | 
			
		||||
This won't be needed to save horizontal space when using HdyLeaflet, and
 | 
			
		||||
it would make porting to it harder.
 | 
			
		||||
---
 | 
			
		||||
 desktop/org.gnome.Geary.gschema.xml           |  6 -----
 | 
			
		||||
 .../application-configuration.vala            |  5 ----
 | 
			
		||||
 .../application/application-main-window.vala  | 27 ++-----------------
 | 
			
		||||
 .../components-preferences-window.vala        | 16 -----------
 | 
			
		||||
 4 files changed, 2 insertions(+), 52 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/desktop/org.gnome.Geary.gschema.xml b/desktop/org.gnome.Geary.gschema.xml
 | 
			
		||||
index 9850dffd..89354dc2 100644
 | 
			
		||||
--- a/desktop/org.gnome.Geary.gschema.xml
 | 
			
		||||
+++ b/desktop/org.gnome.Geary.gschema.xml
 | 
			
		||||
@@ -21,12 +21,6 @@
 | 
			
		||||
         <description>The last recorded height of the application window.</description>
 | 
			
		||||
     </key>
 | 
			
		||||
 
 | 
			
		||||
-    <key name="folder-list-pane-horizontal" type="b">
 | 
			
		||||
-        <default>true</default>
 | 
			
		||||
-        <summary>Orientation of the folder list pane</summary>
 | 
			
		||||
-        <description>True if the folder list Paned is in the horizontal orientation.</description>
 | 
			
		||||
-    </key>
 | 
			
		||||
-
 | 
			
		||||
     <key name="formatting-toolbar-visible" type="b">
 | 
			
		||||
         <default>false</default>
 | 
			
		||||
         <summary>Show/hide formatting toolbar</summary>
 | 
			
		||||
diff --git a/src/client/application/application-configuration.vala b/src/client/application/application-configuration.vala
 | 
			
		||||
index 51a11bbf..48542df6 100644
 | 
			
		||||
--- a/src/client/application/application-configuration.vala
 | 
			
		||||
+++ b/src/client/application/application-configuration.vala
 | 
			
		||||
@@ -19,7 +19,6 @@ public class Application.Configuration : Geary.BaseObject {
 | 
			
		||||
     public const string COMPOSE_AS_HTML_KEY = "compose-as-html";
 | 
			
		||||
     public const string CONVERSATION_VIEWER_ZOOM_KEY = "conversation-viewer-zoom";
 | 
			
		||||
     public const string DISPLAY_PREVIEW_KEY = "display-preview";
 | 
			
		||||
-    public const string FOLDER_LIST_PANE_HORIZONTAL_KEY = "folder-list-pane-horizontal";
 | 
			
		||||
     public const string FORMATTING_TOOLBAR_VISIBLE = "formatting-toolbar-visible";
 | 
			
		||||
     public const string OPTIONAL_PLUGINS = "optional-plugins";
 | 
			
		||||
     public const string SEARCH_STRATEGY_KEY = "search-strategy";
 | 
			
		||||
@@ -86,10 +85,6 @@ public class Application.Configuration : Geary.BaseObject {
 | 
			
		||||
         get { return settings.get_boolean(WINDOW_MAXIMIZE_KEY); }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public bool folder_list_pane_horizontal {
 | 
			
		||||
-        get { return settings.get_boolean(FOLDER_LIST_PANE_HORIZONTAL_KEY); }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     public bool formatting_toolbar_visible {
 | 
			
		||||
         get { return settings.get_boolean(FORMATTING_TOOLBAR_VISIBLE); }
 | 
			
		||||
         set { settings.set_boolean(FORMATTING_TOOLBAR_VISIBLE, value); }
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 48f8bae6..0bec6614 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -511,7 +511,8 @@ public class Application.MainWindow :
 | 
			
		||||
         });
 | 
			
		||||
 
 | 
			
		||||
         setup_layout(application.config);
 | 
			
		||||
-        on_change_orientation();
 | 
			
		||||
+        this.folder_paned.orientation = Gtk.Orientation.HORIZONTAL;
 | 
			
		||||
+        this.folder_box.pack_start(status_bar, false, false);
 | 
			
		||||
 
 | 
			
		||||
         update_command_actions();
 | 
			
		||||
         update_conversation_actions(NONE);
 | 
			
		||||
@@ -1133,10 +1134,6 @@ public class Application.MainWindow :
 | 
			
		||||
         config.bind(Configuration.WINDOW_WIDTH_KEY, this, "window-width");
 | 
			
		||||
         config.bind(Configuration.WINDOW_HEIGHT_KEY, this, "window-height");
 | 
			
		||||
         config.bind(Configuration.WINDOW_MAXIMIZE_KEY, this, "window-maximized");
 | 
			
		||||
-        // Update to layout
 | 
			
		||||
-        config.settings.changed[
 | 
			
		||||
-            Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY
 | 
			
		||||
-        ].connect(on_change_orientation);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void restore_saved_window_state() {
 | 
			
		||||
@@ -1637,26 +1634,6 @@ public class Application.MainWindow :
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_change_orientation() {
 | 
			
		||||
-        bool horizontal = this.application.config.folder_list_pane_horizontal;
 | 
			
		||||
-        bool initial = true;
 | 
			
		||||
-
 | 
			
		||||
-        if (this.status_bar.parent != null) {
 | 
			
		||||
-            this.status_bar.parent.remove(status_bar);
 | 
			
		||||
-            initial = false;
 | 
			
		||||
-        }
 | 
			
		||||
-
 | 
			
		||||
-        GLib.Settings.unbind(this.folder_paned, "position");
 | 
			
		||||
-        this.folder_paned.orientation = horizontal ? Gtk.Orientation.HORIZONTAL :
 | 
			
		||||
-            Gtk.Orientation.VERTICAL;
 | 
			
		||||
-
 | 
			
		||||
-        if (horizontal) {
 | 
			
		||||
-            this.folder_box.pack_start(status_bar, false, false);
 | 
			
		||||
-        } else {
 | 
			
		||||
-            this.conversation_list_box.pack_start(status_bar, false, false);
 | 
			
		||||
-        }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     private void update_headerbar() {
 | 
			
		||||
         update_title();
 | 
			
		||||
         if (this.selected_folder != null) {
 | 
			
		||||
diff --git a/src/client/components/components-preferences-window.vala b/src/client/components/components-preferences-window.vala
 | 
			
		||||
index b1bdfd7b..ea978a3a 100644
 | 
			
		||||
--- a/src/client/components/components-preferences-window.vala
 | 
			
		||||
+++ b/src/client/components/components-preferences-window.vala
 | 
			
		||||
@@ -136,16 +136,6 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
 | 
			
		||||
         display_preview_row.activatable_widget = display_preview;
 | 
			
		||||
         display_preview_row.add(display_preview);
 | 
			
		||||
 
 | 
			
		||||
-        var three_pane_view = new Gtk.Switch();
 | 
			
		||||
-        three_pane_view.valign = CENTER;
 | 
			
		||||
-
 | 
			
		||||
-        var three_pane_view_row = new Hdy.ActionRow();
 | 
			
		||||
-        /// Translators: Preferences label
 | 
			
		||||
-        three_pane_view_row.title = _("Use _three pane view");
 | 
			
		||||
-        three_pane_view_row.use_underline = true;
 | 
			
		||||
-        three_pane_view_row.activatable_widget = three_pane_view;
 | 
			
		||||
-        three_pane_view_row.add(three_pane_view);
 | 
			
		||||
-
 | 
			
		||||
         var single_key_shortucts = new Gtk.Switch();
 | 
			
		||||
         single_key_shortucts.valign = CENTER;
 | 
			
		||||
 
 | 
			
		||||
@@ -180,7 +170,6 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
 | 
			
		||||
         //group.description = _("General application preferences");
 | 
			
		||||
         group.add(autoselect_row);
 | 
			
		||||
         group.add(display_preview_row);
 | 
			
		||||
-        group.add(three_pane_view_row);
 | 
			
		||||
         group.add(single_key_shortucts_row);
 | 
			
		||||
         group.add(startup_notifications_row);
 | 
			
		||||
 
 | 
			
		||||
@@ -210,11 +199,6 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
 | 
			
		||||
                 display_preview,
 | 
			
		||||
                 "state"
 | 
			
		||||
             );
 | 
			
		||||
-            config.bind(
 | 
			
		||||
-                Application.Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY,
 | 
			
		||||
-                three_pane_view,
 | 
			
		||||
-                "state"
 | 
			
		||||
-            );
 | 
			
		||||
             config.bind(
 | 
			
		||||
                 Application.Configuration.SINGLE_KEY_SHORTCUTS,
 | 
			
		||||
                 single_key_shortucts,
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,186 @@
 | 
			
		||||
From 850efb72380b3e2adc9f29af45a16bc1bd6e884b Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Fri, 17 Jan 2020 18:51:39 +0100
 | 
			
		||||
Subject: [PATCH 047/124] application-main-window: Move the conversations
 | 
			
		||||
 searchbar
 | 
			
		||||
 | 
			
		||||
Move it at above the conversations but not above the folders. This is
 | 
			
		||||
needed to properly split the 3 panes.
 | 
			
		||||
---
 | 
			
		||||
 .../application/application-main-window.vala  |   4 +-
 | 
			
		||||
 ui/application-main-window.ui                 | 105 +++++++-----------
 | 
			
		||||
 2 files changed, 44 insertions(+), 65 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 0bec6614..43289e33 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -317,8 +317,6 @@ public class Application.MainWindow :
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.Box main_layout;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
-    private Gtk.Box search_bar_box;
 | 
			
		||||
-    [GtkChild]
 | 
			
		||||
     private Gtk.Paned folder_paned;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.Paned conversations_paned;
 | 
			
		||||
@@ -1210,7 +1208,7 @@ public class Application.MainWindow :
 | 
			
		||||
         // Search bar
 | 
			
		||||
         this.search_bar = new SearchBar(this.application.engine);
 | 
			
		||||
         this.search_bar.search_text_changed.connect(on_search);
 | 
			
		||||
-        this.search_bar_box.pack_start(this.search_bar, false, false, 0);
 | 
			
		||||
+        this.conversation_list_box.pack_start(this.search_bar, false, false, 0);
 | 
			
		||||
 
 | 
			
		||||
         // Folder list
 | 
			
		||||
         this.folder_list.folder_selected.connect(on_folder_selected);
 | 
			
		||||
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
 | 
			
		||||
index f429a5ee..4a948294 100644
 | 
			
		||||
--- a/ui/application-main-window.ui
 | 
			
		||||
+++ b/ui/application-main-window.ui
 | 
			
		||||
@@ -28,100 +28,81 @@
 | 
			
		||||
                 <property name="visible">True</property>
 | 
			
		||||
                 <property name="can_focus">True</property>
 | 
			
		||||
                 <child>
 | 
			
		||||
-                  <object class="GtkBox" id="search_bar_box">
 | 
			
		||||
+                  <object class="GtkPaned" id="folder_paned">
 | 
			
		||||
                     <property name="visible">True</property>
 | 
			
		||||
-                    <property name="can_focus">False</property>
 | 
			
		||||
-                    <property name="orientation">vertical</property>
 | 
			
		||||
+                    <property name="can_focus">True</property>
 | 
			
		||||
                     <child>
 | 
			
		||||
-                      <object class="GtkPaned" id="folder_paned">
 | 
			
		||||
+                      <object class="GtkBox" id="folder_box">
 | 
			
		||||
                         <property name="visible">True</property>
 | 
			
		||||
-                        <property name="can_focus">True</property>
 | 
			
		||||
+                        <property name="can_focus">False</property>
 | 
			
		||||
+                        <property name="orientation">vertical</property>
 | 
			
		||||
                         <child>
 | 
			
		||||
-                          <object class="GtkBox" id="folder_box">
 | 
			
		||||
+                          <object class="GtkFrame" id="folder_frame">
 | 
			
		||||
                             <property name="visible">True</property>
 | 
			
		||||
                             <property name="can_focus">False</property>
 | 
			
		||||
-                            <property name="orientation">vertical</property>
 | 
			
		||||
+                            <property name="label_xalign">0</property>
 | 
			
		||||
+                            <property name="shadow_type">in</property>
 | 
			
		||||
                             <child>
 | 
			
		||||
-                              <object class="GtkFrame" id="folder_frame">
 | 
			
		||||
+                              <object class="GtkScrolledWindow" id="folder_list_scrolled">
 | 
			
		||||
+                                <property name="width_request">100</property>
 | 
			
		||||
                                 <property name="visible">True</property>
 | 
			
		||||
-                                <property name="can_focus">False</property>
 | 
			
		||||
-                                <property name="label_xalign">0</property>
 | 
			
		||||
-                                <property name="shadow_type">in</property>
 | 
			
		||||
-                                <child>
 | 
			
		||||
-                                  <object class="GtkScrolledWindow" id="folder_list_scrolled">
 | 
			
		||||
-                                    <property name="width_request">100</property>
 | 
			
		||||
-                                    <property name="visible">True</property>
 | 
			
		||||
-                                    <property name="can_focus">True</property>
 | 
			
		||||
-                                    <property name="hscrollbar_policy">never</property>
 | 
			
		||||
-                                  </object>
 | 
			
		||||
-                                </child>
 | 
			
		||||
-                                <style>
 | 
			
		||||
-                                  <class name="geary-folder-frame"/>
 | 
			
		||||
-                                </style>
 | 
			
		||||
+                                <property name="can_focus">True</property>
 | 
			
		||||
+                                <property name="hscrollbar_policy">never</property>
 | 
			
		||||
                               </object>
 | 
			
		||||
-                              <packing>
 | 
			
		||||
-                                <property name="expand">True</property>
 | 
			
		||||
-                                <property name="fill">True</property>
 | 
			
		||||
-                                <property name="position">0</property>
 | 
			
		||||
-                              </packing>
 | 
			
		||||
                             </child>
 | 
			
		||||
+                            <style>
 | 
			
		||||
+                              <class name="geary-folder-frame"/>
 | 
			
		||||
+                            </style>
 | 
			
		||||
                           </object>
 | 
			
		||||
                           <packing>
 | 
			
		||||
-                            <property name="resize">False</property>
 | 
			
		||||
-                            <property name="shrink">False</property>
 | 
			
		||||
+                            <property name="expand">True</property>
 | 
			
		||||
+                            <property name="fill">True</property>
 | 
			
		||||
+                            <property name="position">0</property>
 | 
			
		||||
                           </packing>
 | 
			
		||||
                         </child>
 | 
			
		||||
+                      </object>
 | 
			
		||||
+                      <packing>
 | 
			
		||||
+                        <property name="resize">False</property>
 | 
			
		||||
+                        <property name="shrink">False</property>
 | 
			
		||||
+                      </packing>
 | 
			
		||||
+                    </child>
 | 
			
		||||
+                    <child>
 | 
			
		||||
+                      <object class="GtkBox" id="conversation_list_box">
 | 
			
		||||
+                        <property name="visible">True</property>
 | 
			
		||||
+                        <property name="can_focus">False</property>
 | 
			
		||||
+                        <property name="orientation">vertical</property>
 | 
			
		||||
                         <child>
 | 
			
		||||
-                          <object class="GtkBox" id="conversation_list_box">
 | 
			
		||||
+                          <object class="GtkFrame" id="conversation_frame">
 | 
			
		||||
                             <property name="visible">True</property>
 | 
			
		||||
                             <property name="can_focus">False</property>
 | 
			
		||||
-                            <property name="orientation">vertical</property>
 | 
			
		||||
+                            <property name="label_xalign">0</property>
 | 
			
		||||
+                            <property name="shadow_type">in</property>
 | 
			
		||||
                             <child>
 | 
			
		||||
-                              <object class="GtkFrame">
 | 
			
		||||
+                              <object class="GtkScrolledWindow" id="conversation_list_scrolled">
 | 
			
		||||
+                                <property name="width_request">250</property>
 | 
			
		||||
                                 <property name="visible">True</property>
 | 
			
		||||
-                                <property name="can_focus">False</property>
 | 
			
		||||
-                                <property name="label_xalign">0</property>
 | 
			
		||||
-                                <property name="shadow_type">in</property>
 | 
			
		||||
-                                <child>
 | 
			
		||||
-                                  <object class="GtkScrolledWindow" id="conversation_list_scrolled">
 | 
			
		||||
-                                    <property name="width_request">250</property>
 | 
			
		||||
-                                    <property name="visible">True</property>
 | 
			
		||||
-                                    <property name="can_focus">True</property>
 | 
			
		||||
-                                  </object>
 | 
			
		||||
-                                </child>
 | 
			
		||||
-                                <style>
 | 
			
		||||
-                                  <class name="geary-conversation-frame"/>
 | 
			
		||||
-                                </style>
 | 
			
		||||
+                                <property name="can_focus">True</property>
 | 
			
		||||
                               </object>
 | 
			
		||||
-                              <packing>
 | 
			
		||||
-                                <property name="expand">True</property>
 | 
			
		||||
-                                <property name="fill">True</property>
 | 
			
		||||
-                                <property name="pack_type">end</property>
 | 
			
		||||
-                                <property name="position">0</property>
 | 
			
		||||
-                              </packing>
 | 
			
		||||
                             </child>
 | 
			
		||||
                             <style>
 | 
			
		||||
-                              <class name="geary-conversation-list-box"/>
 | 
			
		||||
+                              <class name="geary-conversation-frame"/>
 | 
			
		||||
                             </style>
 | 
			
		||||
                           </object>
 | 
			
		||||
                           <packing>
 | 
			
		||||
-                            <property name="resize">True</property>
 | 
			
		||||
-                            <property name="shrink">False</property>
 | 
			
		||||
+                            <property name="expand">True</property>
 | 
			
		||||
+                            <property name="fill">True</property>
 | 
			
		||||
+                            <property name="pack_type">end</property>
 | 
			
		||||
+                            <property name="position">0</property>
 | 
			
		||||
                           </packing>
 | 
			
		||||
                         </child>
 | 
			
		||||
-                        <style>
 | 
			
		||||
-                          <class name="geary-sidebar-pane-separator"/>
 | 
			
		||||
-                        </style>
 | 
			
		||||
                       </object>
 | 
			
		||||
                       <packing>
 | 
			
		||||
-                        <property name="expand">True</property>
 | 
			
		||||
-                        <property name="fill">True</property>
 | 
			
		||||
-                        <property name="pack_type">end</property>
 | 
			
		||||
-                        <property name="position">0</property>
 | 
			
		||||
+                        <property name="resize">True</property>
 | 
			
		||||
+                        <property name="shrink">False</property>
 | 
			
		||||
                       </packing>
 | 
			
		||||
                     </child>
 | 
			
		||||
                     <style>
 | 
			
		||||
-                      <class name="sidebar"/>
 | 
			
		||||
+                      <class name="geary-sidebar-pane-separator"/>
 | 
			
		||||
                     </style>
 | 
			
		||||
                   </object>
 | 
			
		||||
                   <packing>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,206 @@
 | 
			
		||||
From 94ab7e5ac6b282e07edf8966da5c69e4fdba0cc8 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Sat, 18 Jan 2020 09:16:32 +0100
 | 
			
		||||
Subject: [PATCH 048/124] main-toolbar: Split the folder header
 | 
			
		||||
 | 
			
		||||
Split it into a folder header and a conversations header. This is needed
 | 
			
		||||
to properly split the 3 panes.
 | 
			
		||||
 | 
			
		||||
Fixes https://gitlab.gnome.org/GNOME/geary/issues/442.
 | 
			
		||||
---
 | 
			
		||||
 src/client/components/main-toolbar.vala |  12 ++-
 | 
			
		||||
 ui/main-toolbar.ui                      | 108 +++++++++++++++---------
 | 
			
		||||
 2 files changed, 77 insertions(+), 43 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index aa263253..4ee02079 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -28,10 +28,14 @@ public class MainToolbar : Gtk.Box {
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.HeaderBar folder_header;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
-    private Gtk.ToggleButton search_conversations_button;
 | 
			
		||||
-    [GtkChild]
 | 
			
		||||
     private Gtk.MenuButton main_menu_button;
 | 
			
		||||
 
 | 
			
		||||
+    // Conversations header elements
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.HeaderBar conversations_header;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.ToggleButton search_conversations_button;
 | 
			
		||||
+
 | 
			
		||||
     // Conversation header elements
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.HeaderBar conversation_header;
 | 
			
		||||
@@ -60,8 +64,8 @@ public class MainToolbar : Gtk.Box {
 | 
			
		||||
 
 | 
			
		||||
     public MainToolbar(Application.Configuration config) {
 | 
			
		||||
         if (config.desktop_environment != UNITY) {
 | 
			
		||||
-            this.bind_property("account", this.folder_header, "title", BindingFlags.SYNC_CREATE);
 | 
			
		||||
-            this.bind_property("folder", this.folder_header, "subtitle", BindingFlags.SYNC_CREATE);
 | 
			
		||||
+            this.bind_property("account", this.conversations_header, "title", BindingFlags.SYNC_CREATE);
 | 
			
		||||
+            this.bind_property("folder", this.conversations_header, "subtitle", BindingFlags.SYNC_CREATE);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         // Assemble the main/mark menus
 | 
			
		||||
diff --git a/ui/main-toolbar.ui b/ui/main-toolbar.ui
 | 
			
		||||
index 874f5b4b..732a01b9 100644
 | 
			
		||||
--- a/ui/main-toolbar.ui
 | 
			
		||||
+++ b/ui/main-toolbar.ui
 | 
			
		||||
@@ -11,68 +11,97 @@
 | 
			
		||||
     <property name="visible">True</property>
 | 
			
		||||
     <property name="can_focus">False</property>
 | 
			
		||||
     <child>
 | 
			
		||||
-      <object class="GtkHeaderBar" id="folder_header">
 | 
			
		||||
+      <object class="GtkBox">
 | 
			
		||||
         <property name="visible">True</property>
 | 
			
		||||
         <property name="can_focus">False</property>
 | 
			
		||||
-        <property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
 | 
			
		||||
         <child>
 | 
			
		||||
-          <object class="GtkButton" id="compose_new_message_button">
 | 
			
		||||
+          <object class="GtkHeaderBar" id="folder_header">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
-            <property name="can_focus">True</property>
 | 
			
		||||
-            <property name="focus_on_click">False</property>
 | 
			
		||||
-            <property name="receives_default">False</property>
 | 
			
		||||
-            <property name="tooltip_text" translatable="yes" context="tooltip">Compose Message</property>
 | 
			
		||||
-            <property name="action_name">app.compose</property>
 | 
			
		||||
-            <property name="always_show_image">True</property>
 | 
			
		||||
+            <property name="can_focus">False</property>
 | 
			
		||||
+            <property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
 | 
			
		||||
+            <property name="title">Mail</property>
 | 
			
		||||
             <child>
 | 
			
		||||
-              <object class="GtkImage" id="compose_new_message_image">
 | 
			
		||||
+              <object class="GtkMenuButton" id="main_menu_button">
 | 
			
		||||
                 <property name="visible">True</property>
 | 
			
		||||
-                <property name="can_focus">False</property>
 | 
			
		||||
-                <property name="icon_name">text-editor-symbolic</property>
 | 
			
		||||
+                <property name="can_focus">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="main_menu_image">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">False</property>
 | 
			
		||||
+                    <property name="icon_name">open-menu-symbolic</property>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
               </object>
 | 
			
		||||
+              <packing>
 | 
			
		||||
+                <property name="pack_type">end</property>
 | 
			
		||||
+                <property name="position">1</property>
 | 
			
		||||
+              </packing>
 | 
			
		||||
             </child>
 | 
			
		||||
           </object>
 | 
			
		||||
         </child>
 | 
			
		||||
         <child>
 | 
			
		||||
-          <object class="GtkMenuButton" id="main_menu_button">
 | 
			
		||||
+          <object class="GtkSeparator" id="folder_separator">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
-            <property name="can_focus">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="main_menu_image">
 | 
			
		||||
-                <property name="visible">True</property>
 | 
			
		||||
-                <property name="can_focus">False</property>
 | 
			
		||||
-                <property name="icon_name">open-menu-symbolic</property>
 | 
			
		||||
-              </object>
 | 
			
		||||
-            </child>
 | 
			
		||||
+            <property name="can_focus">False</property>
 | 
			
		||||
+            <property name="orientation">vertical</property>
 | 
			
		||||
+            <style>
 | 
			
		||||
+              <class name="sidebar"/>
 | 
			
		||||
+            </style>
 | 
			
		||||
           </object>
 | 
			
		||||
           <packing>
 | 
			
		||||
-            <property name="pack_type">end</property>
 | 
			
		||||
+            <property name="expand">False</property>
 | 
			
		||||
+            <property name="fill">True</property>
 | 
			
		||||
             <property name="position">1</property>
 | 
			
		||||
           </packing>
 | 
			
		||||
         </child>
 | 
			
		||||
         <child>
 | 
			
		||||
-          <object class="GtkToggleButton" id="search_conversations_button">
 | 
			
		||||
+          <object class="GtkHeaderBar" id="conversations_header">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
-            <property name="can_focus">True</property>
 | 
			
		||||
-            <property name="focus_on_click">False</property>
 | 
			
		||||
-            <property name="receives_default">False</property>
 | 
			
		||||
-            <property name="tooltip_text" translatable="yes">Toggle search bar</property>
 | 
			
		||||
-            <property name="always_show_image">True</property>
 | 
			
		||||
+            <property name="can_focus">False</property>
 | 
			
		||||
+            <property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
 | 
			
		||||
             <child>
 | 
			
		||||
-              <object class="GtkImage" id="search_conversations_image">
 | 
			
		||||
+              <object class="GtkButton" id="compose_new_message_button">
 | 
			
		||||
                 <property name="visible">True</property>
 | 
			
		||||
-                <property name="can_focus">False</property>
 | 
			
		||||
-                <property name="icon_name">preferences-system-search-symbolic</property>
 | 
			
		||||
+                <property name="can_focus">True</property>
 | 
			
		||||
+                <property name="focus_on_click">False</property>
 | 
			
		||||
+                <property name="receives_default">False</property>
 | 
			
		||||
+                <property name="tooltip_text" translatable="yes" context="tooltip">Compose Message</property>
 | 
			
		||||
+                <property name="action_name">app.compose</property>
 | 
			
		||||
+                <property name="always_show_image">True</property>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkImage" id="compose_new_message_image">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">False</property>
 | 
			
		||||
+                    <property name="icon_name">text-editor-symbolic</property>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
               </object>
 | 
			
		||||
             </child>
 | 
			
		||||
+            <child>
 | 
			
		||||
+              <object class="GtkToggleButton" id="search_conversations_button">
 | 
			
		||||
+                <property name="visible">True</property>
 | 
			
		||||
+                <property name="can_focus">True</property>
 | 
			
		||||
+                <property name="focus_on_click">False</property>
 | 
			
		||||
+                <property name="receives_default">False</property>
 | 
			
		||||
+                <property name="tooltip_text" translatable="yes">Toggle search bar</property>
 | 
			
		||||
+                <property name="always_show_image">True</property>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkImage" id="search_conversations_image">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">False</property>
 | 
			
		||||
+                    <property name="icon_name">preferences-system-search-symbolic</property>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
+              </object>
 | 
			
		||||
+              <packing>
 | 
			
		||||
+                <property name="pack_type">end</property>
 | 
			
		||||
+                <property name="position">3</property>
 | 
			
		||||
+              </packing>
 | 
			
		||||
+            </child>
 | 
			
		||||
           </object>
 | 
			
		||||
-          <packing>
 | 
			
		||||
-            <property name="pack_type">end</property>
 | 
			
		||||
-            <property name="position">3</property>
 | 
			
		||||
-          </packing>
 | 
			
		||||
         </child>
 | 
			
		||||
       </object>
 | 
			
		||||
       <packing>
 | 
			
		||||
@@ -82,7 +111,7 @@
 | 
			
		||||
       </packing>
 | 
			
		||||
     </child>
 | 
			
		||||
     <child>
 | 
			
		||||
-      <object class="GtkSeparator" id="header_separator">
 | 
			
		||||
+      <object class="GtkSeparator" id="conversations_separator">
 | 
			
		||||
         <property name="visible">True</property>
 | 
			
		||||
         <property name="can_focus">False</property>
 | 
			
		||||
         <property name="orientation">vertical</property>
 | 
			
		||||
@@ -342,6 +371,7 @@
 | 
			
		||||
   <object class="HdyHeaderGroup" id="header_group">
 | 
			
		||||
     <headerbars>
 | 
			
		||||
       <headerbar name="folder_header"/>
 | 
			
		||||
+      <headerbar name="conversations_header"/>
 | 
			
		||||
       <headerbar name="conversation_header"/>
 | 
			
		||||
     </headerbars>
 | 
			
		||||
   </object>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
From 7d4a61d431e072dbcacda2d089b587fe52257da6 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Thu, 16 Jan 2020 13:50:03 +0100
 | 
			
		||||
Subject: [PATCH 049/124] main-toolbar: Add add_to_size_groups()
 | 
			
		||||
 | 
			
		||||
This will be used to sync requests of the panes.
 | 
			
		||||
---
 | 
			
		||||
 src/client/components/main-toolbar.vala | 18 ++++++++++++++++++
 | 
			
		||||
 1 file changed, 18 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index 4ee02079..6ea472a8 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -30,12 +30,18 @@ public class MainToolbar : Gtk.Box {
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.MenuButton main_menu_button;
 | 
			
		||||
 
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.Separator folder_separator;
 | 
			
		||||
+
 | 
			
		||||
     // Conversations header elements
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.HeaderBar conversations_header;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.ToggleButton search_conversations_button;
 | 
			
		||||
 
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.Separator conversations_separator;
 | 
			
		||||
+
 | 
			
		||||
     // Conversation header elements
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.HeaderBar conversation_header;
 | 
			
		||||
@@ -105,6 +111,18 @@ public class MainToolbar : Gtk.Box {
 | 
			
		||||
         update_conversation_buttons();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public void add_to_size_groups(Gtk.SizeGroup folder_group,
 | 
			
		||||
+                                   Gtk.SizeGroup folder_separator_group,
 | 
			
		||||
+                                   Gtk.SizeGroup conversations_group,
 | 
			
		||||
+                                   Gtk.SizeGroup conversations_separator_group,
 | 
			
		||||
+                                   Gtk.SizeGroup conversation_group) {
 | 
			
		||||
+        folder_group.add_widget(folder_header);
 | 
			
		||||
+        folder_separator_group.add_widget(folder_separator);
 | 
			
		||||
+        conversations_group.add_widget(conversations_header);
 | 
			
		||||
+        conversations_separator_group.add_widget(conversations_separator);
 | 
			
		||||
+        conversation_group.add_widget(conversation_header);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     // Updates tooltip text depending on number of conversations selected.
 | 
			
		||||
     private void update_conversation_buttons() {
 | 
			
		||||
         this.mark_message_button.tooltip_text = ngettext(
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
From edfb1a2cf371ab743cbf804cbc4d34b7e4cfb8c6 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Thu, 16 Jan 2020 13:52:03 +0100
 | 
			
		||||
Subject: [PATCH 050/124] application-main-window: Sync the pane size request
 | 
			
		||||
 | 
			
		||||
Bind each pane's elements minimum size requests via size groups.
 | 
			
		||||
---
 | 
			
		||||
 .../application/application-main-window.vala  | 17 +++++++++++++++
 | 
			
		||||
 ui/application-main-window.ui                 | 21 +++++++++++++++++++
 | 
			
		||||
 2 files changed, 38 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 43289e33..4c6d1038 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -328,6 +328,17 @@ public class Application.MainWindow :
 | 
			
		||||
     private Gtk.Box conversation_list_box;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.ScrolledWindow conversation_list_scrolled;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.SizeGroup folder_size_group;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.SizeGroup folder_separator_size_group;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.SizeGroup conversations_size_group;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.SizeGroup conversations_separator_size_group;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.SizeGroup conversation_size_group;
 | 
			
		||||
+
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.Overlay overlay;
 | 
			
		||||
 
 | 
			
		||||
@@ -1239,9 +1250,15 @@ public class Application.MainWindow :
 | 
			
		||||
         );
 | 
			
		||||
 
 | 
			
		||||
         this.conversations_paned.pack2(this.conversation_viewer, true, false);
 | 
			
		||||
+        this.conversation_size_group.add_widget(this.conversation_viewer);
 | 
			
		||||
 
 | 
			
		||||
         // Main toolbar
 | 
			
		||||
         this.main_toolbar = new MainToolbar(config);
 | 
			
		||||
+        this.main_toolbar.add_to_size_groups(this.folder_size_group,
 | 
			
		||||
+                                             this.folder_separator_size_group,
 | 
			
		||||
+                                             this.conversations_size_group,
 | 
			
		||||
+                                             this.conversations_separator_size_group,
 | 
			
		||||
+                                             this.conversation_size_group);
 | 
			
		||||
         this.main_toolbar.move_folder_menu.folder_selected.connect(on_move_conversation);
 | 
			
		||||
         this.main_toolbar.copy_folder_menu.folder_selected.connect(on_copy_conversation);
 | 
			
		||||
         this.main_toolbar.bind_property("search-open", this.search_bar, "search-mode-enabled",
 | 
			
		||||
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
 | 
			
		||||
index 4a948294..872f31bd 100644
 | 
			
		||||
--- a/ui/application-main-window.ui
 | 
			
		||||
+++ b/ui/application-main-window.ui
 | 
			
		||||
@@ -138,4 +138,25 @@
 | 
			
		||||
       <class name="geary-main-window"/>
 | 
			
		||||
     </style>
 | 
			
		||||
   </template>
 | 
			
		||||
+  <object class="GtkSizeGroup" id="folder_size_group">
 | 
			
		||||
+    <property name="mode">horizontal</property>
 | 
			
		||||
+    <widgets>
 | 
			
		||||
+      <widget name="folder_box"/>
 | 
			
		||||
+    </widgets>
 | 
			
		||||
+  </object>
 | 
			
		||||
+  <object class="GtkSizeGroup" id="folder_separator_size_group">
 | 
			
		||||
+    <property name="mode">horizontal</property>
 | 
			
		||||
+  </object>
 | 
			
		||||
+  <object class="GtkSizeGroup" id="conversations_size_group">
 | 
			
		||||
+    <property name="mode">horizontal</property>
 | 
			
		||||
+    <widgets>
 | 
			
		||||
+      <widget name="conversation_list_box"/>
 | 
			
		||||
+    </widgets>
 | 
			
		||||
+  </object>
 | 
			
		||||
+  <object class="GtkSizeGroup" id="conversations_separator_size_group">
 | 
			
		||||
+    <property name="mode">horizontal</property>
 | 
			
		||||
+  </object>
 | 
			
		||||
+  <object class="GtkSizeGroup" id="conversation_size_group">
 | 
			
		||||
+    <property name="mode">horizontal</property>
 | 
			
		||||
+  </object>
 | 
			
		||||
 </interface>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										338
									
								
								mail-client/geary/files/0051-Use-leaflets-in-the-UI.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										338
									
								
								mail-client/geary/files/0051-Use-leaflets-in-the-UI.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,338 @@
 | 
			
		||||
From 12a7101ba55bb646161e9997485036744121f542 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Thu, 24 Oct 2019 14:36:04 +0200
 | 
			
		||||
Subject: [PATCH 051/124] Use leaflets in the UI
 | 
			
		||||
 | 
			
		||||
There is no way to navigate into the app, but it's a start.
 | 
			
		||||
 | 
			
		||||
v2: replace expand with child vexpand
 | 
			
		||||
---
 | 
			
		||||
 .../application/application-main-window.vala  |  8 +--
 | 
			
		||||
 src/client/components/main-toolbar.vala       |  5 +-
 | 
			
		||||
 .../conversation-viewer.vala                  |  4 ++
 | 
			
		||||
 ui/application-main-window.ui                 | 52 ++++++++++++++-----
 | 
			
		||||
 ui/geary.css                                  | 11 ++++
 | 
			
		||||
 ui/main-toolbar.ui                            | 33 +++++++-----
 | 
			
		||||
 6 files changed, 81 insertions(+), 32 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 4c6d1038..b56079cf 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -317,9 +317,9 @@ public class Application.MainWindow :
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.Box main_layout;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
-    private Gtk.Paned folder_paned;
 | 
			
		||||
+    private Hdy.Leaflet main_leaflet;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
-    private Gtk.Paned conversations_paned;
 | 
			
		||||
+    private Hdy.Leaflet conversations_leaflet;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.Box folder_box;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
@@ -520,7 +520,6 @@ public class Application.MainWindow :
 | 
			
		||||
         });
 | 
			
		||||
 
 | 
			
		||||
         setup_layout(application.config);
 | 
			
		||||
-        this.folder_paned.orientation = Gtk.Orientation.HORIZONTAL;
 | 
			
		||||
         this.folder_box.pack_start(status_bar, false, false);
 | 
			
		||||
 
 | 
			
		||||
         update_command_actions();
 | 
			
		||||
@@ -1249,8 +1248,9 @@ public class Application.MainWindow :
 | 
			
		||||
             on_conversation_view_added
 | 
			
		||||
         );
 | 
			
		||||
 
 | 
			
		||||
-        this.conversations_paned.pack2(this.conversation_viewer, true, false);
 | 
			
		||||
+        this.conversation_viewer.hexpand = true;
 | 
			
		||||
         this.conversation_size_group.add_widget(this.conversation_viewer);
 | 
			
		||||
+        this.main_leaflet.add_with_properties(this.conversation_viewer, "name", "conversation", null);
 | 
			
		||||
 
 | 
			
		||||
         // Main toolbar
 | 
			
		||||
         this.main_toolbar = new MainToolbar(config);
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index 6ea472a8..286546d5 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
 
 | 
			
		||||
 // Draws the main toolbar.
 | 
			
		||||
 [GtkTemplate (ui = "/org/gnome/Geary/main-toolbar.ui")]
 | 
			
		||||
-public class MainToolbar : Gtk.Box {
 | 
			
		||||
+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
 | 
			
		||||
@@ -97,7 +97,8 @@ public class MainToolbar : Gtk.Box {
 | 
			
		||||
     public void set_conversation_header(Gtk.HeaderBar header) {
 | 
			
		||||
         conversation_header.hide();
 | 
			
		||||
         this.header_group.add_gtk_header_bar(header);
 | 
			
		||||
-        pack_start(header, true, true);
 | 
			
		||||
+        header.hexpand = true;
 | 
			
		||||
+        add(header);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void remove_conversation_header(Gtk.HeaderBar header) {
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-viewer.vala b/src/client/conversation-viewer/conversation-viewer.vala
 | 
			
		||||
index f04a1d26..eec5f6a4 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-viewer.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-viewer.vala
 | 
			
		||||
@@ -68,6 +68,10 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
 | 
			
		||||
     public signal void conversation_removed(ConversationListBox list);
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+    static construct {
 | 
			
		||||
+        set_css_name("geary-conversation-viewer");
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     /**
 | 
			
		||||
      * Constructs a new conversation view instance.
 | 
			
		||||
      */
 | 
			
		||||
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
 | 
			
		||||
index 872f31bd..f7bb884e 100644
 | 
			
		||||
--- a/ui/application-main-window.ui
 | 
			
		||||
+++ b/ui/application-main-window.ui
 | 
			
		||||
@@ -24,13 +24,18 @@
 | 
			
		||||
             <property name="can_focus">False</property>
 | 
			
		||||
             <property name="orientation">vertical</property>
 | 
			
		||||
             <child>
 | 
			
		||||
-              <object class="GtkPaned" id="conversations_paned">
 | 
			
		||||
+              <object class="HdyLeaflet" id="main_leaflet">
 | 
			
		||||
                 <property name="visible">True</property>
 | 
			
		||||
                 <property name="can_focus">True</property>
 | 
			
		||||
+                <property name="can_swipe_back">True</property>
 | 
			
		||||
+                <property name="transition_type">over</property>
 | 
			
		||||
                 <child>
 | 
			
		||||
-                  <object class="GtkPaned" id="folder_paned">
 | 
			
		||||
+                  <object class="HdyLeaflet" id="conversations_leaflet">
 | 
			
		||||
                     <property name="visible">True</property>
 | 
			
		||||
                     <property name="can_focus">True</property>
 | 
			
		||||
+                    <property name="hexpand_set">True</property>
 | 
			
		||||
+                    <property name="can_swipe_back">True</property>
 | 
			
		||||
+                    <property name="transition_type">over</property>
 | 
			
		||||
                     <child>
 | 
			
		||||
                       <object class="GtkBox" id="folder_box">
 | 
			
		||||
                         <property name="visible">True</property>
 | 
			
		||||
@@ -40,6 +45,7 @@
 | 
			
		||||
                           <object class="GtkFrame" id="folder_frame">
 | 
			
		||||
                             <property name="visible">True</property>
 | 
			
		||||
                             <property name="can_focus">False</property>
 | 
			
		||||
+                            <property name="vexpand">True</property>
 | 
			
		||||
                             <property name="label_xalign">0</property>
 | 
			
		||||
                             <property name="shadow_type">in</property>
 | 
			
		||||
                             <child>
 | 
			
		||||
@@ -55,15 +61,26 @@
 | 
			
		||||
                             </style>
 | 
			
		||||
                           </object>
 | 
			
		||||
                           <packing>
 | 
			
		||||
-                            <property name="expand">True</property>
 | 
			
		||||
                             <property name="fill">True</property>
 | 
			
		||||
                             <property name="position">0</property>
 | 
			
		||||
                           </packing>
 | 
			
		||||
                         </child>
 | 
			
		||||
                       </object>
 | 
			
		||||
                       <packing>
 | 
			
		||||
-                        <property name="resize">False</property>
 | 
			
		||||
-                        <property name="shrink">False</property>
 | 
			
		||||
+                        <property name="name">folder</property>
 | 
			
		||||
+                      </packing>
 | 
			
		||||
+                    </child>
 | 
			
		||||
+                    <child>
 | 
			
		||||
+                      <object class="GtkSeparator" id="folder_separator">
 | 
			
		||||
+                        <property name="visible">True</property>
 | 
			
		||||
+                        <property name="can_focus">False</property>
 | 
			
		||||
+                        <property name="orientation">vertical</property>
 | 
			
		||||
+                        <style>
 | 
			
		||||
+                          <class name="sidebar"/>
 | 
			
		||||
+                        </style>
 | 
			
		||||
+                      </object>
 | 
			
		||||
+                      <packing>
 | 
			
		||||
+                        <property name="navigatable">False</property>
 | 
			
		||||
                       </packing>
 | 
			
		||||
                     </child>
 | 
			
		||||
                     <child>
 | 
			
		||||
@@ -97,22 +114,27 @@
 | 
			
		||||
                         </child>
 | 
			
		||||
                       </object>
 | 
			
		||||
                       <packing>
 | 
			
		||||
-                        <property name="resize">True</property>
 | 
			
		||||
-                        <property name="shrink">False</property>
 | 
			
		||||
+                        <property name="name">conversations</property>
 | 
			
		||||
                       </packing>
 | 
			
		||||
                     </child>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                  <packing>
 | 
			
		||||
+                    <property name="name">conversations</property>
 | 
			
		||||
+                  </packing>
 | 
			
		||||
+                </child>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkSeparator" id="conversations_separator">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">False</property>
 | 
			
		||||
+                    <property name="orientation">vertical</property>
 | 
			
		||||
                     <style>
 | 
			
		||||
                       <class name="geary-sidebar-pane-separator"/>
 | 
			
		||||
                     </style>
 | 
			
		||||
                   </object>
 | 
			
		||||
                   <packing>
 | 
			
		||||
-                    <property name="resize">False</property>
 | 
			
		||||
-                    <property name="shrink">False</property>
 | 
			
		||||
+                    <property name="navigatable">False</property>
 | 
			
		||||
                   </packing>
 | 
			
		||||
                 </child>
 | 
			
		||||
-                <child>
 | 
			
		||||
-                  <placeholder/>
 | 
			
		||||
-                </child>
 | 
			
		||||
               </object>
 | 
			
		||||
               <packing>
 | 
			
		||||
                 <property name="expand">True</property>
 | 
			
		||||
@@ -146,6 +168,9 @@
 | 
			
		||||
   </object>
 | 
			
		||||
   <object class="GtkSizeGroup" id="folder_separator_size_group">
 | 
			
		||||
     <property name="mode">horizontal</property>
 | 
			
		||||
+    <widgets>
 | 
			
		||||
+      <widget name="folder_separator"/>
 | 
			
		||||
+    </widgets>
 | 
			
		||||
   </object>
 | 
			
		||||
   <object class="GtkSizeGroup" id="conversations_size_group">
 | 
			
		||||
     <property name="mode">horizontal</property>
 | 
			
		||||
@@ -155,6 +180,9 @@
 | 
			
		||||
   </object>
 | 
			
		||||
   <object class="GtkSizeGroup" id="conversations_separator_size_group">
 | 
			
		||||
     <property name="mode">horizontal</property>
 | 
			
		||||
+    <widgets>
 | 
			
		||||
+      <widget name="conversations_separator"/>
 | 
			
		||||
+    </widgets>
 | 
			
		||||
   </object>
 | 
			
		||||
   <object class="GtkSizeGroup" id="conversation_size_group">
 | 
			
		||||
     <property name="mode">horizontal</property>
 | 
			
		||||
diff --git a/ui/geary.css b/ui/geary.css
 | 
			
		||||
index 0ddfab30..2d1d48c3 100644
 | 
			
		||||
--- a/ui/geary.css
 | 
			
		||||
+++ b/ui/geary.css
 | 
			
		||||
@@ -12,12 +12,23 @@
 | 
			
		||||
   border-left-width: 0;
 | 
			
		||||
   border-top-width: 0;
 | 
			
		||||
   border-right-width: 0;
 | 
			
		||||
+  min-width: 300px;
 | 
			
		||||
 }
 | 
			
		||||
 .geary-conversation-frame > border {
 | 
			
		||||
   border-left-width: 0;
 | 
			
		||||
   border-top-width: 0;
 | 
			
		||||
   border-right-width: 0;
 | 
			
		||||
+  min-width: 360px;
 | 
			
		||||
 }
 | 
			
		||||
+
 | 
			
		||||
+treeview.sidebar {
 | 
			
		||||
+  border: none;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+geary-conversation-viewer {
 | 
			
		||||
+  min-width: 360px;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* For 3-pane mode only */
 | 
			
		||||
 .geary-sidebar-pane-separator.vertical .conversation-frame > border {
 | 
			
		||||
   border-bottom-width: 0;
 | 
			
		||||
diff --git a/ui/main-toolbar.ui b/ui/main-toolbar.ui
 | 
			
		||||
index 732a01b9..441cd146 100644
 | 
			
		||||
--- a/ui/main-toolbar.ui
 | 
			
		||||
+++ b/ui/main-toolbar.ui
 | 
			
		||||
@@ -7,13 +7,18 @@
 | 
			
		||||
     <property name="can_focus">False</property>
 | 
			
		||||
     <property name="icon_name">mail-archive-symbolic</property>
 | 
			
		||||
   </object>
 | 
			
		||||
-  <template class="MainToolbar" parent="GtkBox">
 | 
			
		||||
+  <template class="MainToolbar" parent="HdyLeaflet">
 | 
			
		||||
     <property name="visible">True</property>
 | 
			
		||||
     <property name="can_focus">False</property>
 | 
			
		||||
+    <property name="can_swipe_back">True</property>
 | 
			
		||||
+    <property name="transition_type">over</property>
 | 
			
		||||
     <child>
 | 
			
		||||
-      <object class="GtkBox">
 | 
			
		||||
+      <object class="HdyLeaflet" id="conversations_leaflet">
 | 
			
		||||
         <property name="visible">True</property>
 | 
			
		||||
         <property name="can_focus">False</property>
 | 
			
		||||
+        <property name="can_swipe_back">True</property>
 | 
			
		||||
+        <property name="transition_type">over</property>
 | 
			
		||||
+        <property name="hexpand_set">True</property>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkHeaderBar" id="folder_header">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
@@ -41,6 +46,9 @@
 | 
			
		||||
               </packing>
 | 
			
		||||
             </child>
 | 
			
		||||
           </object>
 | 
			
		||||
+          <packing>
 | 
			
		||||
+            <property name="name">folder</property>
 | 
			
		||||
+          </packing>
 | 
			
		||||
         </child>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkSeparator" id="folder_separator">
 | 
			
		||||
@@ -52,15 +60,14 @@
 | 
			
		||||
             </style>
 | 
			
		||||
           </object>
 | 
			
		||||
           <packing>
 | 
			
		||||
-            <property name="expand">False</property>
 | 
			
		||||
-            <property name="fill">True</property>
 | 
			
		||||
-            <property name="position">1</property>
 | 
			
		||||
+            <property name="navigatable">False</property>
 | 
			
		||||
           </packing>
 | 
			
		||||
         </child>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkHeaderBar" id="conversations_header">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
             <property name="can_focus">False</property>
 | 
			
		||||
+            <property name="hexpand">True</property>
 | 
			
		||||
             <property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
 | 
			
		||||
             <child>
 | 
			
		||||
               <object class="GtkButton" id="compose_new_message_button">
 | 
			
		||||
@@ -102,12 +109,13 @@
 | 
			
		||||
               </packing>
 | 
			
		||||
             </child>
 | 
			
		||||
           </object>
 | 
			
		||||
+          <packing>
 | 
			
		||||
+            <property name="name">conversations</property>
 | 
			
		||||
+          </packing>
 | 
			
		||||
         </child>
 | 
			
		||||
       </object>
 | 
			
		||||
       <packing>
 | 
			
		||||
-        <property name="expand">False</property>
 | 
			
		||||
-        <property name="fill">True</property>
 | 
			
		||||
-        <property name="position">0</property>
 | 
			
		||||
+        <property name="name">conversations</property>
 | 
			
		||||
       </packing>
 | 
			
		||||
     </child>
 | 
			
		||||
     <child>
 | 
			
		||||
@@ -120,15 +128,14 @@
 | 
			
		||||
         </style>
 | 
			
		||||
       </object>
 | 
			
		||||
       <packing>
 | 
			
		||||
-        <property name="expand">False</property>
 | 
			
		||||
-        <property name="fill">True</property>
 | 
			
		||||
-        <property name="position">1</property>
 | 
			
		||||
+        <property name="navigatable">False</property>
 | 
			
		||||
       </packing>
 | 
			
		||||
     </child>
 | 
			
		||||
     <child>
 | 
			
		||||
       <object class="GtkHeaderBar" id="conversation_header">
 | 
			
		||||
         <property name="visible">True</property>
 | 
			
		||||
         <property name="can_focus">False</property>
 | 
			
		||||
+        <property name="hexpand">True</property>
 | 
			
		||||
         <property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkBox" id="reply_forward_buttons">
 | 
			
		||||
@@ -362,9 +369,7 @@
 | 
			
		||||
         </child>
 | 
			
		||||
       </object>
 | 
			
		||||
       <packing>
 | 
			
		||||
-        <property name="expand">True</property>
 | 
			
		||||
-        <property name="fill">True</property>
 | 
			
		||||
-        <property name="position">2</property>
 | 
			
		||||
+        <property name="name">conversation</property>
 | 
			
		||||
       </packing>
 | 
			
		||||
     </child>
 | 
			
		||||
   </template>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
From 2139636d82b67414dd22170894bb61d2e9d1b415 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Sat, 18 Jan 2020 12:58:18 +0100
 | 
			
		||||
Subject: [PATCH 052/124] main-toolbar: Add add_to_swipe_groups()
 | 
			
		||||
 | 
			
		||||
This will be used to sync the swipe state of the leaflets.
 | 
			
		||||
---
 | 
			
		||||
 src/client/components/main-toolbar.vala | 9 +++++++++
 | 
			
		||||
 1 file changed, 9 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index 286546d5..c7bdab8f 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -24,6 +24,9 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
     public int selected_conversations { get; set; }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Hdy.Leaflet conversations_leaflet;
 | 
			
		||||
+
 | 
			
		||||
     // Folder header elements
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.HeaderBar folder_header;
 | 
			
		||||
@@ -124,6 +127,12 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
         conversation_group.add_widget(conversation_header);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public void add_to_swipe_groups(Hdy.SwipeGroup conversations_group,
 | 
			
		||||
+                                    Hdy.SwipeGroup conversation_group) {
 | 
			
		||||
+        conversations_group.add_swipeable(this.conversations_leaflet);
 | 
			
		||||
+        conversation_group.add_swipeable(this);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     // Updates tooltip text depending on number of conversations selected.
 | 
			
		||||
     private void update_conversation_buttons() {
 | 
			
		||||
         this.mark_message_button.tooltip_text = ngettext(
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
From 28e319267446fe96c070b85d6a20096f787fcdcc Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Sat, 18 Jan 2020 13:04:10 +0100
 | 
			
		||||
Subject: [PATCH 053/124] application-main-window: Sync the leaflets' swipe
 | 
			
		||||
 state
 | 
			
		||||
 | 
			
		||||
This keeps the swiping state of the leaflets in sync.
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-main-window.vala |  6 ++++++
 | 
			
		||||
 ui/application-main-window.ui                       | 10 ++++++++++
 | 
			
		||||
 2 files changed, 16 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index b56079cf..3af1b6aa 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -338,6 +338,10 @@ public class Application.MainWindow :
 | 
			
		||||
     private Gtk.SizeGroup conversations_separator_size_group;
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.SizeGroup conversation_size_group;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Hdy.SwipeGroup conversations_swipe_group;
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Hdy.SwipeGroup conversation_swipe_group;
 | 
			
		||||
 
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.Overlay overlay;
 | 
			
		||||
@@ -1259,6 +1263,8 @@ public class Application.MainWindow :
 | 
			
		||||
                                              this.conversations_size_group,
 | 
			
		||||
                                              this.conversations_separator_size_group,
 | 
			
		||||
                                              this.conversation_size_group);
 | 
			
		||||
+        this.main_toolbar.add_to_swipe_groups(this.conversations_swipe_group,
 | 
			
		||||
+                                              this.conversation_swipe_group);
 | 
			
		||||
         this.main_toolbar.move_folder_menu.folder_selected.connect(on_move_conversation);
 | 
			
		||||
         this.main_toolbar.copy_folder_menu.folder_selected.connect(on_copy_conversation);
 | 
			
		||||
         this.main_toolbar.bind_property("search-open", this.search_bar, "search-mode-enabled",
 | 
			
		||||
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
 | 
			
		||||
index f7bb884e..fe66491b 100644
 | 
			
		||||
--- a/ui/application-main-window.ui
 | 
			
		||||
+++ b/ui/application-main-window.ui
 | 
			
		||||
@@ -187,4 +187,14 @@
 | 
			
		||||
   <object class="GtkSizeGroup" id="conversation_size_group">
 | 
			
		||||
     <property name="mode">horizontal</property>
 | 
			
		||||
   </object>
 | 
			
		||||
+  <object class="HdySwipeGroup" id="conversations_swipe_group">
 | 
			
		||||
+    <swipeables>
 | 
			
		||||
+      <swipeable name="conversations_leaflet"/>
 | 
			
		||||
+    </swipeables>
 | 
			
		||||
+  </object>
 | 
			
		||||
+  <object class="HdySwipeGroup" id="conversation_swipe_group">
 | 
			
		||||
+    <swipeables>
 | 
			
		||||
+      <swipeable name="main_leaflet"/>
 | 
			
		||||
+    </swipeables>
 | 
			
		||||
+  </object>
 | 
			
		||||
 </interface>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
From 115b055e7b3dd267c44efacaf3fc7272a81d9d96 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Mon, 5 Oct 2020 17:20:14 +0200
 | 
			
		||||
Subject: [PATCH 054/124] main-window: Add leaflet navigation with Alt+Arrow
 | 
			
		||||
 keys
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../application/application-main-window.vala  | 35 +++++++++++++++++--
 | 
			
		||||
 1 file changed, 33 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 3af1b6aa..bb5a9404 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -1797,7 +1797,20 @@ public class Application.MainWindow :
 | 
			
		||||
 
 | 
			
		||||
     private void focus_next_pane() {
 | 
			
		||||
         var focus = get_focus();
 | 
			
		||||
-        if (focus != null) {
 | 
			
		||||
+
 | 
			
		||||
+        if (main_leaflet.folded) {
 | 
			
		||||
+            if (main_leaflet.visible_child_name == "conversations") {
 | 
			
		||||
+                if (conversations_leaflet.folded &&
 | 
			
		||||
+                    conversations_leaflet.visible_child_name == "folder" ||
 | 
			
		||||
+                    focus == this.folder_list) {
 | 
			
		||||
+                    conversations_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
 | 
			
		||||
+                    focus = this.conversation_list_view;
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    main_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
 | 
			
		||||
+                    focus = this.conversation_viewer.visible_child;
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+        } else if (focus != null) {
 | 
			
		||||
             if (focus == this.folder_list ||
 | 
			
		||||
                 focus.is_ancestor(this.folder_list)) {
 | 
			
		||||
                 focus = this.conversation_list_view;
 | 
			
		||||
@@ -1819,7 +1832,25 @@ public class Application.MainWindow :
 | 
			
		||||
 
 | 
			
		||||
     private void focus_previous_pane() {
 | 
			
		||||
         var focus = get_focus();
 | 
			
		||||
-        if (focus != null) {
 | 
			
		||||
+
 | 
			
		||||
+        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);
 | 
			
		||||
+                        focus = this.folder_list;
 | 
			
		||||
+                    }
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    if (focus == this.conversation_list_view)
 | 
			
		||||
+                        focus = this.folder_list;
 | 
			
		||||
+                    else
 | 
			
		||||
+                        focus = this.conversation_list_view;
 | 
			
		||||
+                }
 | 
			
		||||
+            } else {
 | 
			
		||||
+                main_leaflet.navigate(Hdy.NavigationDirection.BACK);
 | 
			
		||||
+                focus = this.conversation_list_view;
 | 
			
		||||
+            }
 | 
			
		||||
+        } else if (focus != null) {
 | 
			
		||||
             if (focus == this.folder_list ||
 | 
			
		||||
                 focus.is_ancestor(this.folder_list)) {
 | 
			
		||||
                 focus = this.conversation_viewer.visible_child;
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,103 @@
 | 
			
		||||
From 28a19775b8689f08c4e6c280e9414547d23d42c7 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Wed, 30 Sep 2020 17:38:24 +0200
 | 
			
		||||
Subject: [PATCH 055/124] main-toolbar: Add back buttons for leaflet navigation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../application/application-main-window.vala  |  2 +
 | 
			
		||||
 ui/main-toolbar.ui                            | 52 +++++++++++++++++++
 | 
			
		||||
 2 files changed, 54 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index bb5a9404..c3cf2d58 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -31,6 +31,7 @@ public class Application.MainWindow :
 | 
			
		||||
     public const string ACTION_TOGGLE_JUNK = "toggle-conversation-junk";
 | 
			
		||||
     public const string ACTION_TRASH_CONVERSATION = "trash-conversation";
 | 
			
		||||
     public const string ACTION_ZOOM = "zoom";
 | 
			
		||||
+    public const string ACTION_NAVIGATION_BACK = "navigation-back";
 | 
			
		||||
 
 | 
			
		||||
     private const ActionEntry[] EDIT_ACTIONS = {
 | 
			
		||||
         { Action.Edit.UNDO, on_undo },
 | 
			
		||||
@@ -42,6 +43,7 @@ public class Application.MainWindow :
 | 
			
		||||
 
 | 
			
		||||
         { ACTION_FIND_IN_CONVERSATION, on_find_in_conversation_action },
 | 
			
		||||
         { ACTION_SEARCH, on_search_activated },
 | 
			
		||||
+        { ACTION_NAVIGATION_BACK, focus_previous_pane},
 | 
			
		||||
         // Message actions
 | 
			
		||||
         { ACTION_REPLY_CONVERSATION, on_reply_conversation },
 | 
			
		||||
         { ACTION_REPLY_ALL_CONVERSATION, on_reply_all_conversation },
 | 
			
		||||
diff --git a/ui/main-toolbar.ui b/ui/main-toolbar.ui
 | 
			
		||||
index 441cd146..871aba25 100644
 | 
			
		||||
--- a/ui/main-toolbar.ui
 | 
			
		||||
+++ b/ui/main-toolbar.ui
 | 
			
		||||
@@ -69,6 +69,32 @@
 | 
			
		||||
             <property name="can_focus">False</property>
 | 
			
		||||
             <property name="hexpand">True</property>
 | 
			
		||||
             <property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
 | 
			
		||||
+            <child>
 | 
			
		||||
+              <object class="GtkButton" id="conversations_back">
 | 
			
		||||
+                <property name="can_focus">False</property>
 | 
			
		||||
+                <property name="receives_default">False</property>
 | 
			
		||||
+                <property name="valign">center</property>
 | 
			
		||||
+                <property name="use-underline">True</property>
 | 
			
		||||
+                <property name="visible" bind-source="conversations_leaflet" 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-conversations-back">
 | 
			
		||||
+                    <property name="accessible-name" translatable="yes">Back</property>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
+                <child>
 | 
			
		||||
+                  <object class="GtkImage" id="conversations_back_image">
 | 
			
		||||
+                    <property name="visible">True</property>
 | 
			
		||||
+                    <property name="can_focus">False</property>
 | 
			
		||||
+                    <property name="icon_name">go-previous-symbolic</property>
 | 
			
		||||
+                    <property name="icon_size">1</property>
 | 
			
		||||
+                  </object>
 | 
			
		||||
+                </child>
 | 
			
		||||
+              </object>
 | 
			
		||||
+            </child>
 | 
			
		||||
             <child>
 | 
			
		||||
               <object class="GtkButton" id="compose_new_message_button">
 | 
			
		||||
                 <property name="visible">True</property>
 | 
			
		||||
@@ -137,6 +163,32 @@
 | 
			
		||||
         <property name="can_focus">False</property>
 | 
			
		||||
         <property name="hexpand">True</property>
 | 
			
		||||
         <property name="show_close_button" bind-source="MainToolbar" bind-property="show_close_button" bind-flags="sync-create"/>
 | 
			
		||||
+        <child>
 | 
			
		||||
+          <object class="GtkButton" id="conversation_back">
 | 
			
		||||
+            <property name="can_focus">False</property>
 | 
			
		||||
+            <property name="receives_default">False</property>
 | 
			
		||||
+            <property name="valign">center</property>
 | 
			
		||||
+            <property name="use-underline">True</property>
 | 
			
		||||
+            <property name="visible" bind-source="MainToolbar" 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="can_focus">False</property>
 | 
			
		||||
+                <property name="icon_name">go-previous-symbolic</property>
 | 
			
		||||
+                <property name="icon_size">1</property>
 | 
			
		||||
+              </object>
 | 
			
		||||
+            </child>
 | 
			
		||||
+          </object>
 | 
			
		||||
+        </child>
 | 
			
		||||
         <child>
 | 
			
		||||
           <object class="GtkBox" id="reply_forward_buttons">
 | 
			
		||||
             <property name="visible">True</property>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,132 @@
 | 
			
		||||
From 49823ec05414e11275f313fb0ca5a48fcab7ddda Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Tue, 6 Oct 2020 10:41:33 +0200
 | 
			
		||||
Subject: [PATCH 056/124] application-main-window: add navigation via signle
 | 
			
		||||
 click on folder/conversation
 | 
			
		||||
 | 
			
		||||
Opening a conversation in a new window is currently disabled, because we
 | 
			
		||||
need a new key/button combination.
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-main-window.vala   | 11 +++++++++++
 | 
			
		||||
 .../conversation-list/conversation-list-view.vala     |  1 +
 | 
			
		||||
 src/client/folder-list/folder-list-tree.vala          | 10 ++++++++++
 | 
			
		||||
 src/client/sidebar/sidebar-tree.vala                  | 11 +++++++++++
 | 
			
		||||
 4 files changed, 33 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index c3cf2d58..97960660 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -1230,6 +1230,7 @@ public class Application.MainWindow :
 | 
			
		||||
         this.folder_list.folder_selected.connect(on_folder_selected);
 | 
			
		||||
         this.folder_list.move_conversation.connect(on_move_conversation);
 | 
			
		||||
         this.folder_list.copy_conversation.connect(on_copy_conversation);
 | 
			
		||||
+        this.folder_list.folder_activated.connect(on_folder_activated);
 | 
			
		||||
         this.folder_list_scrolled.add(this.folder_list);
 | 
			
		||||
 
 | 
			
		||||
         // Conversation list
 | 
			
		||||
@@ -2135,7 +2136,16 @@ public class Application.MainWindow :
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private void on_folder_activated(Geary.Folder? folder) {
 | 
			
		||||
+        if (folder != null)
 | 
			
		||||
+            focus_next_pane();
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     private void on_conversation_activated(Geary.App.Conversation activated) {
 | 
			
		||||
+        if (main_leaflet.folded) {
 | 
			
		||||
+            focus_next_pane();
 | 
			
		||||
+        }
 | 
			
		||||
+        /* TODO: find correct UX for opening the conversation in a new window
 | 
			
		||||
         if (this.selected_folder != null) {
 | 
			
		||||
             if (this.selected_folder.used_as != DRAFTS) {
 | 
			
		||||
                 this.application.new_window.begin(
 | 
			
		||||
@@ -2154,6 +2164,7 @@ public class Application.MainWindow :
 | 
			
		||||
                 );
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
+        */
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void on_find_in_conversation_action() {
 | 
			
		||||
diff --git a/src/client/conversation-list/conversation-list-view.vala b/src/client/conversation-list/conversation-list-view.vala
 | 
			
		||||
index a4d5cca6..dcced90d 100644
 | 
			
		||||
--- a/src/client/conversation-list/conversation-list-view.vala
 | 
			
		||||
+++ b/src/client/conversation-list/conversation-list-view.vala
 | 
			
		||||
@@ -42,6 +42,7 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
 | 
			
		||||
         base_ref();
 | 
			
		||||
         set_show_expanders(false);
 | 
			
		||||
         set_headers_visible(false);
 | 
			
		||||
+        set_activate_on_single_click(true);
 | 
			
		||||
 
 | 
			
		||||
         this.config = config;
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/client/folder-list/folder-list-tree.vala b/src/client/folder-list/folder-list-tree.vala
 | 
			
		||||
index fb91347e..f820d12f 100644
 | 
			
		||||
--- a/src/client/folder-list/folder-list-tree.vala
 | 
			
		||||
+++ b/src/client/folder-list/folder-list-tree.vala
 | 
			
		||||
@@ -16,6 +16,7 @@ public class FolderList.Tree : Sidebar.Tree, Geary.BaseInterface {
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public signal void folder_selected(Geary.Folder? folder);
 | 
			
		||||
+    public signal void folder_activated(Geary.Folder? folder);
 | 
			
		||||
     public signal void copy_conversation(Geary.Folder folder);
 | 
			
		||||
     public signal void move_conversation(Geary.Folder folder);
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +31,9 @@ public class FolderList.Tree : Sidebar.Tree, Geary.BaseInterface {
 | 
			
		||||
     public Tree() {
 | 
			
		||||
         base(TARGET_ENTRY_LIST, Gdk.DragAction.COPY | Gdk.DragAction.MOVE, drop_handler);
 | 
			
		||||
         base_ref();
 | 
			
		||||
+        set_activate_on_single_click(true);
 | 
			
		||||
         entry_selected.connect(on_entry_selected);
 | 
			
		||||
+        entry_activated.connect(on_entry_activated);
 | 
			
		||||
 
 | 
			
		||||
         // GtkTreeView binds Ctrl+N to "move cursor to next".  Not so interested in that, so we'll
 | 
			
		||||
         // remove it.
 | 
			
		||||
@@ -87,6 +90,13 @@ public class FolderList.Tree : Sidebar.Tree, Geary.BaseInterface {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private void on_entry_activated(Sidebar.SelectableEntry selectable) {
 | 
			
		||||
+        AbstractFolderEntry? entry = selectable as AbstractFolderEntry;
 | 
			
		||||
+        if (entry != null) {
 | 
			
		||||
+            folder_activated(entry.folder);
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     public void set_user_folders_root_name(Geary.Account account, string name) {
 | 
			
		||||
         if (account_branches.has_key(account))
 | 
			
		||||
             account_branches.get(account).user_folder_group.rename(name);
 | 
			
		||||
diff --git a/src/client/sidebar/sidebar-tree.vala b/src/client/sidebar/sidebar-tree.vala
 | 
			
		||||
index a5f95092..78d73e98 100644
 | 
			
		||||
--- a/src/client/sidebar/sidebar-tree.vala
 | 
			
		||||
+++ b/src/client/sidebar/sidebar-tree.vala
 | 
			
		||||
@@ -80,6 +80,8 @@ public class Sidebar.Tree : Gtk.TreeView {
 | 
			
		||||
 
 | 
			
		||||
     public signal void entry_selected(Sidebar.SelectableEntry selectable);
 | 
			
		||||
 
 | 
			
		||||
+    public signal void entry_activated(Sidebar.SelectableEntry selectable);
 | 
			
		||||
+
 | 
			
		||||
     public signal void selected_entry_removed(Sidebar.SelectableEntry removed);
 | 
			
		||||
 
 | 
			
		||||
     public signal void branch_added(Sidebar.Branch branch);
 | 
			
		||||
@@ -298,6 +300,15 @@ public class Sidebar.Tree : Gtk.TreeView {
 | 
			
		||||
         return true;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public override void row_activated(Gtk.TreePath path, Gtk.TreeViewColumn column) {
 | 
			
		||||
+      EntryWrapper? wrapper = get_wrapper_at_path(path);
 | 
			
		||||
+      if (wrapper != null) {
 | 
			
		||||
+          Sidebar.SelectableEntry? selectable = wrapper.entry as Sidebar.SelectableEntry;
 | 
			
		||||
+          if (selectable != null)
 | 
			
		||||
+              entry_activated(selectable);
 | 
			
		||||
+      }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     public override void cursor_changed() {
 | 
			
		||||
         Gtk.TreePath? path = get_selected_path();
 | 
			
		||||
         if (path == null) {
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										35
									
								
								mail-client/geary/files/0057-toolbar-header-group.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								mail-client/geary/files/0057-toolbar-header-group.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
From d97d86cbc73dc0dc565494c1083b5052457afe04 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Adrien Plazas <kekun.plazas@laposte.net>
 | 
			
		||||
Date: Wed, 16 Sep 2020 13:19:00 +0200
 | 
			
		||||
Subject: [PATCH 057/124] toolbar header group
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 ui/main-toolbar.ui | 9 ++++++++-
 | 
			
		||||
 1 file changed, 8 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/ui/main-toolbar.ui b/ui/main-toolbar.ui
 | 
			
		||||
index 871aba25..5d58af6f 100644
 | 
			
		||||
--- a/ui/main-toolbar.ui
 | 
			
		||||
+++ b/ui/main-toolbar.ui
 | 
			
		||||
@@ -425,10 +425,17 @@
 | 
			
		||||
       </packing>
 | 
			
		||||
     </child>
 | 
			
		||||
   </template>
 | 
			
		||||
-  <object class="HdyHeaderGroup" id="header_group">
 | 
			
		||||
+  <object class="HdyHeaderGroup" id="conversations_header_group">
 | 
			
		||||
+    <property name="decorate-all" bind-source="conversations_leaflet" bind-property="folded" bind-flags="sync-create"/>
 | 
			
		||||
     <headerbars>
 | 
			
		||||
       <headerbar name="folder_header"/>
 | 
			
		||||
       <headerbar name="conversations_header"/>
 | 
			
		||||
+    </headerbars>
 | 
			
		||||
+  </object>
 | 
			
		||||
+  <object class="HdyHeaderGroup" id="header_group">
 | 
			
		||||
+    <property name="decorate-all" bind-source="MainToolbar" bind-property="folded" bind-flags="sync-create"/>
 | 
			
		||||
+    <headerbars>
 | 
			
		||||
+      <headerbar name="conversations_header_group"/>
 | 
			
		||||
       <headerbar name="conversation_header"/>
 | 
			
		||||
     </headerbars>
 | 
			
		||||
   </object>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,72 @@
 | 
			
		||||
From 1f2896e9a7ba02c0a909c91bb551e596d2d72230 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Thu, 1 Oct 2020 10:40:41 +0200
 | 
			
		||||
Subject: [PATCH 058/124] composer: Switch leaflet to composer when folded
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-main-window.vala |  2 ++
 | 
			
		||||
 src/client/components/main-toolbar.vala             | 13 +++++++++++--
 | 
			
		||||
 2 files changed, 13 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 97960660..c2b0954b 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -916,6 +916,8 @@ public class Application.MainWindow :
 | 
			
		||||
             } else {
 | 
			
		||||
                 this.conversation_viewer.do_compose(composer);
 | 
			
		||||
             }
 | 
			
		||||
+            // Show the correct leaflet
 | 
			
		||||
+            this.main_leaflet.set_visible_child_name("conversation");
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
 | 
			
		||||
index c7bdab8f..0ecb599a 100644
 | 
			
		||||
--- a/src/client/components/main-toolbar.vala
 | 
			
		||||
+++ b/src/client/components/main-toolbar.vala
 | 
			
		||||
@@ -64,6 +64,8 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Hdy.HeaderGroup header_group;
 | 
			
		||||
 
 | 
			
		||||
+    Gtk.SizeGroup conversation_group;
 | 
			
		||||
+
 | 
			
		||||
     private bool show_trash_button = true;
 | 
			
		||||
 
 | 
			
		||||
     // Load these at construction time
 | 
			
		||||
@@ -98,16 +100,22 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void set_conversation_header(Gtk.HeaderBar header) {
 | 
			
		||||
-        conversation_header.hide();
 | 
			
		||||
+        remove(conversation_header);
 | 
			
		||||
         this.header_group.add_gtk_header_bar(header);
 | 
			
		||||
         header.hexpand = true;
 | 
			
		||||
+        conversation_group.remove_widget(conversation_header);
 | 
			
		||||
+        conversation_group.add_widget(header);
 | 
			
		||||
         add(header);
 | 
			
		||||
+        child_set(header, "name", "conversation", null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void remove_conversation_header(Gtk.HeaderBar header) {
 | 
			
		||||
         remove(header);
 | 
			
		||||
         this.header_group.remove_gtk_header_bar(header);
 | 
			
		||||
-        conversation_header.show();
 | 
			
		||||
+        conversation_group.remove_widget(header);
 | 
			
		||||
+        conversation_group.add_widget(conversation_header);
 | 
			
		||||
+        add(conversation_header);
 | 
			
		||||
+        child_set(conversation_header, "name", "conversation", null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void update_trash_button(bool show_trash) {
 | 
			
		||||
@@ -125,6 +133,7 @@ public class MainToolbar : Hdy.Leaflet {
 | 
			
		||||
         conversations_group.add_widget(conversations_header);
 | 
			
		||||
         conversations_separator_group.add_widget(conversations_separator);
 | 
			
		||||
         conversation_group.add_widget(conversation_header);
 | 
			
		||||
+        this.conversation_group = conversation_group;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void add_to_swipe_groups(Hdy.SwipeGroup conversations_group,
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,163 @@
 | 
			
		||||
From 0b743ab0d396cbbaad5aebaebed235ecd0f1a564 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Tue, 6 Oct 2020 13:34:30 +0200
 | 
			
		||||
Subject: [PATCH 059/124] conversation-list: use shift+activate to open
 | 
			
		||||
 conversation in new window
 | 
			
		||||
 | 
			
		||||
Open on shift+double click and shift+space/enter the selected
 | 
			
		||||
conversation in a new window.
 | 
			
		||||
---
 | 
			
		||||
 .../application/application-main-window.vala  | 14 ++---
 | 
			
		||||
 .../conversation-list-view.vala               | 61 ++++++++++++++++---
 | 
			
		||||
 2 files changed, 58 insertions(+), 17 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index c2b0954b..01b7b9c6 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -2143,17 +2143,16 @@ public class Application.MainWindow :
 | 
			
		||||
             focus_next_pane();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_conversation_activated(Geary.App.Conversation activated) {
 | 
			
		||||
-        if (main_leaflet.folded) {
 | 
			
		||||
-            focus_next_pane();
 | 
			
		||||
-        }
 | 
			
		||||
-        /* TODO: find correct UX for opening the conversation in a new window
 | 
			
		||||
-        if (this.selected_folder != null) {
 | 
			
		||||
+    private void on_conversation_activated(Geary.App.Conversation activated, bool single) {
 | 
			
		||||
+        if (single) {
 | 
			
		||||
+            if (main_leaflet.folded)
 | 
			
		||||
+                focus_next_pane();
 | 
			
		||||
+        } else if (this.selected_folder != null) {
 | 
			
		||||
             if (this.selected_folder.used_as != DRAFTS) {
 | 
			
		||||
                 this.application.new_window.begin(
 | 
			
		||||
                     this.selected_folder,
 | 
			
		||||
                     this.conversation_list_view.copy_selected()
 | 
			
		||||
-                );
 | 
			
		||||
+                    );
 | 
			
		||||
             } else {
 | 
			
		||||
                 // TODO: Determine how to map between conversations
 | 
			
		||||
                 // and drafts correctly.
 | 
			
		||||
@@ -2166,7 +2165,6 @@ public class Application.MainWindow :
 | 
			
		||||
                 );
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
-        */
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void on_find_in_conversation_action() {
 | 
			
		||||
diff --git a/src/client/conversation-list/conversation-list-view.vala b/src/client/conversation-list/conversation-list-view.vala
 | 
			
		||||
index dcced90d..0baa66b4 100644
 | 
			
		||||
--- a/src/client/conversation-list/conversation-list-view.vala
 | 
			
		||||
+++ b/src/client/conversation-list/conversation-list-view.vala
 | 
			
		||||
@@ -17,6 +17,7 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
 | 
			
		||||
     private Geary.Scheduler.Scheduled? scheduled_update_visible_conversations = null;
 | 
			
		||||
     private Gee.Set<Geary.App.Conversation> selected = new Gee.HashSet<Geary.App.Conversation>();
 | 
			
		||||
     private Geary.IdleManager selection_update;
 | 
			
		||||
+    private Gtk.GestureMultiPress gesture;
 | 
			
		||||
 
 | 
			
		||||
     // Determines if the next folder scan should avoid selecting a
 | 
			
		||||
     // conversation when autoselect is enabled
 | 
			
		||||
@@ -26,7 +27,7 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
 | 
			
		||||
     public signal void conversations_selected(Gee.Set<Geary.App.Conversation> selected);
 | 
			
		||||
 
 | 
			
		||||
     // Signal for when a conversation has been double-clicked, or selected and enter is pressed.
 | 
			
		||||
-    public signal void conversation_activated(Geary.App.Conversation activated);
 | 
			
		||||
+    public signal void conversation_activated(Geary.App.Conversation activated, bool single = false);
 | 
			
		||||
 
 | 
			
		||||
     public virtual signal void load_more() {
 | 
			
		||||
         enable_load_more = false;
 | 
			
		||||
@@ -42,7 +43,6 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
 | 
			
		||||
         base_ref();
 | 
			
		||||
         set_show_expanders(false);
 | 
			
		||||
         set_headers_visible(false);
 | 
			
		||||
-        set_activate_on_single_click(true);
 | 
			
		||||
 
 | 
			
		||||
         this.config = config;
 | 
			
		||||
 
 | 
			
		||||
@@ -53,11 +53,13 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
 | 
			
		||||
         Gtk.TreeSelection selection = get_selection();
 | 
			
		||||
         selection.set_mode(Gtk.SelectionMode.MULTIPLE);
 | 
			
		||||
         style_updated.connect(on_style_changed);
 | 
			
		||||
-        row_activated.connect(on_row_activated);
 | 
			
		||||
 
 | 
			
		||||
         notify["vadjustment"].connect(on_vadjustment_changed);
 | 
			
		||||
 
 | 
			
		||||
+        key_press_event.connect(on_key_press);
 | 
			
		||||
         button_press_event.connect(on_button_press);
 | 
			
		||||
+        gesture = new Gtk.GestureMultiPress(this);
 | 
			
		||||
+        gesture.pressed.connect(on_gesture_pressed);
 | 
			
		||||
 
 | 
			
		||||
         // Set up drag and drop.
 | 
			
		||||
         Gtk.drag_source_set(this, Gdk.ModifierType.BUTTON1_MASK, FolderList.Tree.TARGET_ENTRY_LIST,
 | 
			
		||||
@@ -270,6 +272,53 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
 | 
			
		||||
         return parent.get_vadjustment();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private void on_gesture_pressed(int n_press, double x, double y) {
 | 
			
		||||
+        if (gesture.get_current_button() != Gdk.BUTTON_PRIMARY)
 | 
			
		||||
+            return;
 | 
			
		||||
+
 | 
			
		||||
+        Gtk.TreePath? path;
 | 
			
		||||
+        get_path_at_pos((int) x, (int) y, out path, null, null, null);
 | 
			
		||||
+
 | 
			
		||||
+        // If the user clicked in an empty area, do nothing.
 | 
			
		||||
+        if (path == null)
 | 
			
		||||
+            return;
 | 
			
		||||
+
 | 
			
		||||
+        Geary.App.Conversation? c = get_model().get_conversation_at_path(path);
 | 
			
		||||
+        if (c == null)
 | 
			
		||||
+            return;
 | 
			
		||||
+
 | 
			
		||||
+        Gdk.Event event = gesture.get_last_event(gesture.get_current_sequence());
 | 
			
		||||
+        Gdk.ModifierType modifiers = Gtk.accelerator_get_default_mod_mask();
 | 
			
		||||
+
 | 
			
		||||
+        Gdk.ModifierType state_mask;
 | 
			
		||||
+        event.get_state(out state_mask);
 | 
			
		||||
+
 | 
			
		||||
+        if ((state_mask & modifiers) == 0 && n_press == 1) {
 | 
			
		||||
+            conversation_activated(c, true);
 | 
			
		||||
+        } else if ((state_mask & modifiers) == Gdk.ModifierType.SHIFT_MASK && n_press == 2) {
 | 
			
		||||
+            conversation_activated(c);
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    private bool on_key_press(Gdk.EventKey event) {
 | 
			
		||||
+        if (this.selected.size != 1)
 | 
			
		||||
+            return false;
 | 
			
		||||
+
 | 
			
		||||
+        Geary.App.Conversation? c = this.selected.to_array()[0];
 | 
			
		||||
+        if (c == null)
 | 
			
		||||
+            return false;
 | 
			
		||||
+
 | 
			
		||||
+        Gdk.ModifierType modifiers = Gtk.accelerator_get_default_mod_mask();
 | 
			
		||||
+
 | 
			
		||||
+        if (event.keyval == Gdk.Key.Return ||
 | 
			
		||||
+            event.keyval == Gdk.Key.ISO_Enter ||
 | 
			
		||||
+            event.keyval == Gdk.Key.KP_Enter ||
 | 
			
		||||
+            event.keyval == Gdk.Key.space ||
 | 
			
		||||
+            event.keyval == Gdk.Key.KP_Space)
 | 
			
		||||
+            conversation_activated(c, !((event.state & modifiers) == Gdk.ModifierType.SHIFT_MASK));
 | 
			
		||||
+        return false;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     private bool on_button_press(Gdk.EventButton event) {
 | 
			
		||||
         // Get the coordinates on the cell as well as the clicked path.
 | 
			
		||||
         int cell_x;
 | 
			
		||||
@@ -576,12 +625,6 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
 | 
			
		||||
         return false;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_row_activated(Gtk.TreePath path) {
 | 
			
		||||
-        Geary.App.Conversation? c = get_model().get_conversation_at_path(path);
 | 
			
		||||
-        if (c != null)
 | 
			
		||||
-            conversation_activated(c);
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     // Enable/disable hover effect on all selected cells.
 | 
			
		||||
     private void set_hover_selected(bool hover) {
 | 
			
		||||
         ConversationListCellRenderer.set_hover_selected(hover);
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,65 @@
 | 
			
		||||
From d6c546e2d555d20e1dd259117822b4d4c8b7152c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Tue, 6 Oct 2020 17:31:49 +0200
 | 
			
		||||
Subject: [PATCH 060/124] composer: close the composer when navigating back
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-main-window.vala | 11 +++++++++++
 | 
			
		||||
 src/client/composer/composer-widget.vala            |  5 +++++
 | 
			
		||||
 ui/application-main-window.ui                       |  2 ++
 | 
			
		||||
 3 files changed, 18 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 01b7b9c6..e1e55d0e 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -1955,6 +1955,17 @@ public class Application.MainWindow :
 | 
			
		||||
         return Gdk.EVENT_STOP;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    [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_offline_infobar_response() {
 | 
			
		||||
         this.info_bars.remove(this.offline_infobar);
 | 
			
		||||
     }
 | 
			
		||||
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
 | 
			
		||||
index 37e93fb4..17430021 100644
 | 
			
		||||
--- a/src/client/composer/composer-widget.vala
 | 
			
		||||
+++ b/src/client/composer/composer-widget.vala
 | 
			
		||||
@@ -1361,6 +1361,11 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    /* Activate the close action */
 | 
			
		||||
+    public void activate_close_action() {
 | 
			
		||||
+        this.actions.activate_action(ACTION_CLOSE, null);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     internal void set_mode(PresentationMode new_mode) {
 | 
			
		||||
         this.current_mode = new_mode;
 | 
			
		||||
         this.header.set_mode(new_mode);
 | 
			
		||||
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
 | 
			
		||||
index fe66491b..cbaacbcf 100644
 | 
			
		||||
--- a/ui/application-main-window.ui
 | 
			
		||||
+++ b/ui/application-main-window.ui
 | 
			
		||||
@@ -29,6 +29,8 @@
 | 
			
		||||
                 <property name="can_focus">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"/>
 | 
			
		||||
                 <child>
 | 
			
		||||
                   <object class="HdyLeaflet" id="conversations_leaflet">
 | 
			
		||||
                     <property name="visible">True</property>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
From f8f223da46716a0a888ef5a5a0840fb69dbc7067 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Wed, 7 Oct 2020 10:36:50 +0200
 | 
			
		||||
Subject: [PATCH 061/124] main-window: Block forward navigation when viewer is
 | 
			
		||||
 empty
 | 
			
		||||
 | 
			
		||||
Empty viewer includes: - no selected conversation
 | 
			
		||||
                       - no conversation in folder
 | 
			
		||||
                       - selected more then one conversation
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-main-window.vala | 7 +++++--
 | 
			
		||||
 1 file changed, 5 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index e1e55d0e..3b7c29e7 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -1811,8 +1811,11 @@ public class Application.MainWindow :
 | 
			
		||||
                     conversations_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
 | 
			
		||||
                     focus = this.conversation_list_view;
 | 
			
		||||
                 } else {
 | 
			
		||||
-                    main_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
 | 
			
		||||
-                    focus = this.conversation_viewer.visible_child;
 | 
			
		||||
+                    if (this.main_toolbar.selected_conversations == 1 &&
 | 
			
		||||
+                        this.selected_folder.properties.email_total > 0) {
 | 
			
		||||
+                        main_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
 | 
			
		||||
+                        focus = this.conversation_viewer.visible_child;
 | 
			
		||||
+                    }
 | 
			
		||||
                 }
 | 
			
		||||
             }
 | 
			
		||||
         } else if (focus != null) {
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2102
									
								
								mail-client/geary/files/0062-Update-Swedish-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2102
									
								
								mail-client/geary/files/0062-Update-Swedish-translation.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
From 51b8c501be7d952e0023a72b24c91254b98fc48c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 10 Oct 2020 23:55:02 +1100
 | 
			
		||||
Subject: [PATCH 063/124] Util.Email: Use a single unambiguous date format for
 | 
			
		||||
 reply quote dates
 | 
			
		||||
 | 
			
		||||
Rather than using the UI pref for 12/24h clocks, use a single format
 | 
			
		||||
string that should be reasonably unambiguous and that includes the
 | 
			
		||||
time zone.
 | 
			
		||||
 | 
			
		||||
Fixes #888
 | 
			
		||||
---
 | 
			
		||||
 src/client/composer/composer-widget.vala |  9 +--
 | 
			
		||||
 src/client/util/util-email.vala          | 78 ++++++++++++++----------
 | 
			
		||||
 2 files changed, 49 insertions(+), 38 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
 | 
			
		||||
index 37e93fb4..503727a9 100644
 | 
			
		||||
--- a/src/client/composer/composer-widget.vala
 | 
			
		||||
+++ b/src/client/composer/composer-widget.vala
 | 
			
		||||
@@ -740,7 +740,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
             );
 | 
			
		||||
             add_recipients_and_ids(type, full_context);
 | 
			
		||||
             complete_quote = Util.Email.quote_email_for_reply(
 | 
			
		||||
-                full_context, quote, this.config.clock_format, HTML
 | 
			
		||||
+                full_context, quote, HTML
 | 
			
		||||
             );
 | 
			
		||||
             if (!Geary.String.is_empty(quote)) {
 | 
			
		||||
                 this.top_posting = false;
 | 
			
		||||
@@ -1291,12 +1291,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
         // Always use reply styling, since forward styling doesn't
 | 
			
		||||
         // work for inline quotes
 | 
			
		||||
         this.editor.body.insert_html(
 | 
			
		||||
-            Util.Email.quote_email_for_reply(
 | 
			
		||||
-                referred,
 | 
			
		||||
-                to_quote,
 | 
			
		||||
-                this.config.clock_format,
 | 
			
		||||
-                Geary.RFC822.TextFormat.HTML
 | 
			
		||||
-            )
 | 
			
		||||
+            Util.Email.quote_email_for_reply(referred, to_quote, HTML)
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/client/util/util-email.vala b/src/client/util/util-email.vala
 | 
			
		||||
index a18a45cf..4a1754a7 100644
 | 
			
		||||
--- a/src/client/util/util-email.vala
 | 
			
		||||
+++ b/src/client/util/util-email.vala
 | 
			
		||||
@@ -177,41 +177,57 @@ namespace Util.Email {
 | 
			
		||||
      */
 | 
			
		||||
     public string quote_email_for_reply(Geary.Email email,
 | 
			
		||||
                                         string? quote,
 | 
			
		||||
-                                        Util.Date.ClockFormat clock_format,
 | 
			
		||||
                                         Geary.RFC822.TextFormat format) {
 | 
			
		||||
-        if (email.body == null && quote == null)
 | 
			
		||||
-            return "";
 | 
			
		||||
-
 | 
			
		||||
         string quoted = "";
 | 
			
		||||
+        if (email.body != null || quote != null) {
 | 
			
		||||
+            /// GLib g_date_time_format format string for the date and
 | 
			
		||||
+            /// time that a message being replied to was
 | 
			
		||||
+            /// received. This should be roughly similar to an RFC
 | 
			
		||||
+            /// 822-style date header value with optional additional
 | 
			
		||||
+            /// punctuation for readability. Note that this date may
 | 
			
		||||
+            /// be sent to someone in a different locale than the
 | 
			
		||||
+            /// sender, so should be unambiguous (for example, do not
 | 
			
		||||
+            /// use mm/dd/yyyy since it could be confused with
 | 
			
		||||
+            /// dd/mm/yyyy) and must include the time zone.
 | 
			
		||||
+            string date_format = _("%a, %b %-e %Y at %X %Z");
 | 
			
		||||
 
 | 
			
		||||
-        string DATE_FORMAT = Util.Date.get_full_date(clock_format);
 | 
			
		||||
-
 | 
			
		||||
-        if (email.date != null && email.from != null) {
 | 
			
		||||
-            /// The quoted header for a message being replied to.
 | 
			
		||||
-            /// %1$s will be substituted for the date, and %2$s will be substituted for
 | 
			
		||||
-            /// the original sender.
 | 
			
		||||
-            string QUOTED_LABEL = _("On %1$s, %2$s wrote:");
 | 
			
		||||
-            quoted += QUOTED_LABEL.printf(email.date.value.format(DATE_FORMAT),
 | 
			
		||||
-                                          Geary.RFC822.Utils.email_addresses_for_reply(email.from, format));
 | 
			
		||||
-
 | 
			
		||||
-        } else if (email.from != null) {
 | 
			
		||||
-            /// The quoted header for a message being replied to (in case the date is not known).
 | 
			
		||||
-            /// %s will be replaced by the original sender.
 | 
			
		||||
-            string QUOTED_LABEL = _("%s wrote:");
 | 
			
		||||
-            quoted += QUOTED_LABEL.printf(Geary.RFC822.Utils.email_addresses_for_reply(email.from, format));
 | 
			
		||||
-
 | 
			
		||||
-        } else if (email.date != null) {
 | 
			
		||||
-            /// The quoted header for a message being replied to (in case the sender is not known).
 | 
			
		||||
-            /// %s will be replaced by the original date
 | 
			
		||||
-            string QUOTED_LABEL = _("On %s:");
 | 
			
		||||
-            quoted += QUOTED_LABEL.printf(email.date.value.format(DATE_FORMAT));
 | 
			
		||||
-        }
 | 
			
		||||
+            if (email.date != null && email.from != null) {
 | 
			
		||||
+                /// The quoted header for a message being replied to.
 | 
			
		||||
+                /// %1$s will be substituted for the date, and %2$s
 | 
			
		||||
+                /// will be substituted for the original sender.
 | 
			
		||||
+                string QUOTED_LABEL = _("On %1$s, %2$s wrote:");
 | 
			
		||||
+                quoted += QUOTED_LABEL.printf(
 | 
			
		||||
+                    email.date.value.format(date_format),
 | 
			
		||||
+                    Geary.RFC822.Utils.email_addresses_for_reply(
 | 
			
		||||
+                        email.from, format
 | 
			
		||||
+                    )
 | 
			
		||||
+                );
 | 
			
		||||
+            } else if (email.from != null) {
 | 
			
		||||
+                /// The quoted header for a message being replied to
 | 
			
		||||
+                /// (in case the date is not known).  %s will be
 | 
			
		||||
+                /// replaced by the original sender.
 | 
			
		||||
+                string QUOTED_LABEL = _("%s wrote:");
 | 
			
		||||
+                quoted += QUOTED_LABEL.printf(
 | 
			
		||||
+                    Geary.RFC822.Utils.email_addresses_for_reply(
 | 
			
		||||
+                        email.from, format
 | 
			
		||||
+                    )
 | 
			
		||||
+                );
 | 
			
		||||
+            } else if (email.date != null) {
 | 
			
		||||
+                /// The quoted header for a message being replied to
 | 
			
		||||
+                /// (in case the sender is not known).  %s will be
 | 
			
		||||
+                /// replaced by the original date
 | 
			
		||||
+                string QUOTED_LABEL = _("On %s:");
 | 
			
		||||
+                quoted += QUOTED_LABEL.printf(
 | 
			
		||||
+                    email.date.value.format(date_format)
 | 
			
		||||
+                );
 | 
			
		||||
+            }
 | 
			
		||||
 
 | 
			
		||||
-        quoted += "<br />";
 | 
			
		||||
-        try {
 | 
			
		||||
-            quoted += quote_body(email, quote, true, format);
 | 
			
		||||
-        } catch (Error err) {
 | 
			
		||||
-            debug("Failed to quote body for replying: %s".printf(err.message));
 | 
			
		||||
+            quoted += "<br />";
 | 
			
		||||
+            try {
 | 
			
		||||
+                quoted += quote_body(email, quote, true, format);
 | 
			
		||||
+            } catch (Error err) {
 | 
			
		||||
+                debug("Failed to quote body for replying: %s".printf(err.message));
 | 
			
		||||
+            }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         return quoted;
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,49 @@
 | 
			
		||||
From 4be51e01c02f57fe68121603888ca012000d845d Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 10 Oct 2020 23:57:11 +1100
 | 
			
		||||
Subject: [PATCH 064/124] Util.Date: Remove now unused function
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/util/util-date.vala | 28 ----------------------------
 | 
			
		||||
 1 file changed, 28 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/util/util-date.vala b/src/client/util/util-date.vala
 | 
			
		||||
index 88948916..322a4cf2 100644
 | 
			
		||||
--- a/src/client/util/util-date.vala
 | 
			
		||||
+++ b/src/client/util/util-date.vala
 | 
			
		||||
@@ -208,32 +208,4 @@ public string get_clock_format(ClockFormat clock_format) {
 | 
			
		||||
     return xlat_pretty_clocks[clock_format.to_index()];
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-public string get_full_date(ClockFormat clock_format) {
 | 
			
		||||
-    var value = "";
 | 
			
		||||
-    switch (clock_format) {
 | 
			
		||||
-    case TWELVE_HOURS:
 | 
			
		||||
-        /// 12 hours format for datetime that a message being replied
 | 
			
		||||
-        /// to was received See
 | 
			
		||||
-        /// http://developer.gnome.org/glib/2.32/glib-GDateTime.html#g-date-time-format
 | 
			
		||||
-        value = _("%a, %b %-e, %Y at %l:%M %P");
 | 
			
		||||
-        break;
 | 
			
		||||
-    case TWENTY_FOUR_HOURS:
 | 
			
		||||
-        /// 24 hours format for the datetime that a message being
 | 
			
		||||
-        /// replied to was received See
 | 
			
		||||
-        /// http://developer.gnome.org/glib/2.32/glib-GDateTime.html#g-date-time-format
 | 
			
		||||
-        value = _("%a, %b %-e, %Y at %H:%M");
 | 
			
		||||
-        break;
 | 
			
		||||
-    case LOCALE_DEFAULT:
 | 
			
		||||
-        /// Format for the datetime that a message being replied to
 | 
			
		||||
-        /// was received See
 | 
			
		||||
-        /// http://developer.gnome.org/glib/2.32/glib-GDateTime.html#g-date-time-format
 | 
			
		||||
-        value = _("%a, %b %-e, %Y at %X");
 | 
			
		||||
-        break;
 | 
			
		||||
-    case TOTAL:
 | 
			
		||||
-        // noop
 | 
			
		||||
-        break;
 | 
			
		||||
-    }
 | 
			
		||||
-    return value;
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
 }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,187 @@
 | 
			
		||||
From 70a40893a3f41483fbc607512d311f4c0c44c79a Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Julian Sparber <julian@sparber.net>
 | 
			
		||||
Date: Thu, 8 Oct 2020 14:50:58 +0200
 | 
			
		||||
Subject: [PATCH 066/124] action-bar: Add an action bar to the conversations
 | 
			
		||||
 list (2-panel)
 | 
			
		||||
 | 
			
		||||
This moves the actions from the headerbar to the action bar at the
 | 
			
		||||
bottom of the conversations list when multiple conversations are
 | 
			
		||||
selected. This changes is needed so that the user can still interact
 | 
			
		||||
with the conversations when folded.
 | 
			
		||||
This also hides the actions from the Headerbar and action bar when
 | 
			
		||||
no conversation is selected.
 | 
			
		||||
---
 | 
			
		||||
 po/POTFILES.in                                |  2 +
 | 
			
		||||
 .../application/application-main-window.vala  | 19 +++++++++
 | 
			
		||||
 .../components-conversation-action-bar.vala   | 39 +++++++++++++++++++
 | 
			
		||||
 src/client/meson.build                        |  1 +
 | 
			
		||||
 ui/components-conversation-action-bar.ui      | 22 +++++++++++
 | 
			
		||||
 ui/org.gnome.Geary.gresource.xml              |  1 +
 | 
			
		||||
 6 files changed, 84 insertions(+)
 | 
			
		||||
 create mode 100644 src/client/components/components-conversation-action-bar.vala
 | 
			
		||||
 create mode 100644 ui/components-conversation-action-bar.ui
 | 
			
		||||
 | 
			
		||||
diff --git a/po/POTFILES.in b/po/POTFILES.in
 | 
			
		||||
index 7ef4e050..68e3ca34 100644
 | 
			
		||||
--- a/po/POTFILES.in
 | 
			
		||||
+++ b/po/POTFILES.in
 | 
			
		||||
@@ -40,6 +40,7 @@ src/client/client-action.vala
 | 
			
		||||
 src/client/components/client-web-view.vala
 | 
			
		||||
 src/client/components/components-attachment-pane.vala
 | 
			
		||||
 src/client/components/components-conversation-actions.vala
 | 
			
		||||
+src/client/components/components-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
 | 
			
		||||
@@ -457,6 +458,7 @@ 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-in-app-notification.ui
 | 
			
		||||
 ui/components-inspector-error-view.ui
 | 
			
		||||
 ui/components-inspector-log-view.ui
 | 
			
		||||
diff --git a/src/client/application/application-main-window.vala b/src/client/application/application-main-window.vala
 | 
			
		||||
index 20fc3758..0e6a89e1 100644
 | 
			
		||||
--- a/src/client/application/application-main-window.vala
 | 
			
		||||
+++ b/src/client/application/application-main-window.vala
 | 
			
		||||
@@ -351,6 +351,8 @@ public class Application.MainWindow :
 | 
			
		||||
     [GtkChild]
 | 
			
		||||
     private Gtk.Overlay overlay;
 | 
			
		||||
 
 | 
			
		||||
+    private Components.ConversationActionBar action_bar;
 | 
			
		||||
+
 | 
			
		||||
     private Components.InfoBarStack info_bars =
 | 
			
		||||
         new Components.InfoBarStack(SINGLE);
 | 
			
		||||
 
 | 
			
		||||
@@ -1308,6 +1310,12 @@ public class Application.MainWindow :
 | 
			
		||||
         this.spinner.set_progress_monitor(progress_monitor);
 | 
			
		||||
         this.status_bar.add(this.spinner);
 | 
			
		||||
         this.status_bar.show_all();
 | 
			
		||||
+
 | 
			
		||||
+        // Action bar
 | 
			
		||||
+        this.action_bar = new Components.ConversationActionBar();
 | 
			
		||||
+        this.conversation_list_box.add_with_properties(action_bar,
 | 
			
		||||
+                                                       "pack-type", Gtk.PackType.END,
 | 
			
		||||
+                                                       "position", 0);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /** {@inheritDoc} */
 | 
			
		||||
@@ -1740,6 +1748,17 @@ public class Application.MainWindow :
 | 
			
		||||
         );
 | 
			
		||||
 
 | 
			
		||||
         this.update_context_dependent_actions.begin(sensitive);
 | 
			
		||||
+        switch (count) {
 | 
			
		||||
+            case NONE:
 | 
			
		||||
+                    conversation_actions.take_ownership(null);
 | 
			
		||||
+                break;
 | 
			
		||||
+            case SINGLE:
 | 
			
		||||
+                this.main_toolbar.add_conversation_actions(this.conversation_actions);
 | 
			
		||||
+                break;
 | 
			
		||||
+            case MULTIPLE:
 | 
			
		||||
+                this.action_bar.add_conversation_actions(this.conversation_actions);
 | 
			
		||||
+                break;
 | 
			
		||||
+        }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private async void update_context_dependent_actions(bool sensitive) {
 | 
			
		||||
diff --git a/src/client/components/components-conversation-action-bar.vala b/src/client/components/components-conversation-action-bar.vala
 | 
			
		||||
new file mode 100644
 | 
			
		||||
index 00000000..cb574521
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/src/client/components/components-conversation-action-bar.vala
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * 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 {
 | 
			
		||||
+    private ulong owner_notify;
 | 
			
		||||
+
 | 
			
		||||
+    [GtkChild]
 | 
			
		||||
+    private Gtk.Box action_box;
 | 
			
		||||
+
 | 
			
		||||
+    public ConversationActionBar() {
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    /**
 | 
			
		||||
+     * This takes ownership of the ConversationActions and places some of
 | 
			
		||||
+     * the buttons into the ActionBar.
 | 
			
		||||
+     */
 | 
			
		||||
+    public void add_conversation_actions(Components.ConversationActions actions) {
 | 
			
		||||
+        if (actions.owner == this)
 | 
			
		||||
+          return;
 | 
			
		||||
+
 | 
			
		||||
+        actions.take_ownership(this);
 | 
			
		||||
+        action_box.pack_start(actions.mark_copy_move_buttons, false, false);
 | 
			
		||||
+        action_box.pack_end(actions.archive_trash_delete_buttons, false, false);
 | 
			
		||||
+        reveal_child = true;
 | 
			
		||||
+        this.owner_notify = actions.notify["owner"].connect(() => {
 | 
			
		||||
+           if (actions.owner != this) {
 | 
			
		||||
+             reveal_child = false;
 | 
			
		||||
+             actions.disconnect (this.owner_notify);
 | 
			
		||||
+           }
 | 
			
		||||
+        });
 | 
			
		||||
+    }
 | 
			
		||||
+}
 | 
			
		||||
diff --git a/src/client/meson.build b/src/client/meson.build
 | 
			
		||||
index ed0d6b33..c0eb0c16 100644
 | 
			
		||||
--- a/src/client/meson.build
 | 
			
		||||
+++ b/src/client/meson.build
 | 
			
		||||
@@ -49,6 +49,7 @@ client_vala_sources = files(
 | 
			
		||||
   'components/client-web-view.vala',
 | 
			
		||||
   'components/components-attachment-pane.vala',
 | 
			
		||||
   'components/components-conversation-actions.vala',
 | 
			
		||||
+  'components/components-conversation-action-bar.vala',
 | 
			
		||||
   'components/components-entry-undo.vala',
 | 
			
		||||
   'components/components-info-bar-stack.vala',
 | 
			
		||||
   'components/components-info-bar.vala',
 | 
			
		||||
diff --git a/ui/components-conversation-action-bar.ui b/ui/components-conversation-action-bar.ui
 | 
			
		||||
new file mode 100644
 | 
			
		||||
index 00000000..ae49683f
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/ui/components-conversation-action-bar.ui
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
+<?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="can_focus">False</property>
 | 
			
		||||
+    <property name="icon_name">mail-archive-symbolic</property>
 | 
			
		||||
+  </object>
 | 
			
		||||
+  <template class="ComponentsConversationActionBar" parent="GtkRevealer">
 | 
			
		||||
+    <property name="visible">True</property>
 | 
			
		||||
+    <property name="can_focus">False</property>
 | 
			
		||||
+    <property name="transition_type">slide-up</property>
 | 
			
		||||
+    <child>
 | 
			
		||||
+      <object class="GtkBox" id="action_box">
 | 
			
		||||
+        <property name="visible">True</property>
 | 
			
		||||
+        <property name="can_focus">False</property>
 | 
			
		||||
+        <property name="hexpand">True</property>
 | 
			
		||||
+        <property name="margin">6</property>
 | 
			
		||||
+      </object>
 | 
			
		||||
+    </child>
 | 
			
		||||
+  </template>
 | 
			
		||||
+</interface>
 | 
			
		||||
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
index 481bbff4..e064d331 100644
 | 
			
		||||
--- a/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
+++ b/ui/org.gnome.Geary.gresource.xml
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
     <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-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-inspector.ui</file>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
From 0010550ad6f7d053b83f1857215294ce2b69f833 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Mon, 12 Oct 2020 23:22:47 +1100
 | 
			
		||||
Subject: [PATCH 067/124] Application.Client: Work around libhandy bug when
 | 
			
		||||
 opening main windows
 | 
			
		||||
 | 
			
		||||
GNOME/libhandy#305
 | 
			
		||||
---
 | 
			
		||||
 src/client/application/application-client.vala | 9 +++++++++
 | 
			
		||||
 1 file changed, 9 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/application/application-client.vala b/src/client/application/application-client.vala
 | 
			
		||||
index 2bf4e094..46469086 100644
 | 
			
		||||
--- a/src/client/application/application-client.vala
 | 
			
		||||
+++ b/src/client/application/application-client.vala
 | 
			
		||||
@@ -892,6 +892,15 @@ public class Application.Client : Gtk.Application {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private MainWindow new_main_window(bool select_first_inbox) {
 | 
			
		||||
+        // Work around warning caused by GNOME/libhandy#305 which
 | 
			
		||||
+        // makes it a pita to run with G_DEBUG=fatal-warnings. Remove
 | 
			
		||||
+        // once the fix for that issue has been released and packaged.
 | 
			
		||||
+        GLib.Test.expect_message(
 | 
			
		||||
+            "GLib-GObject",
 | 
			
		||||
+            LEVEL_WARNING,
 | 
			
		||||
+            "g_object_weak_unref: couldn't find weak ref *"
 | 
			
		||||
+        );
 | 
			
		||||
+
 | 
			
		||||
         MainWindow window = new MainWindow(this);
 | 
			
		||||
         this.controller.register_window(window);
 | 
			
		||||
         window.focus_in_event.connect(on_main_window_focus_in);
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,330 @@
 | 
			
		||||
From 1ba2bd0f5ba655b38aff63d6332b0bb52c704119 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Wed, 26 Aug 2020 15:20:12 +1000
 | 
			
		||||
Subject: [PATCH 069/124] Util.JS: Support converting between JSC.Value and
 | 
			
		||||
 GLib.Variant objects
 | 
			
		||||
 | 
			
		||||
Add `variant_to_value` and `value_to_variant` methods, document them
 | 
			
		||||
and add tests.
 | 
			
		||||
---
 | 
			
		||||
 src/client/util/util-js.vala       | 159 +++++++++++++++++++++++++++++
 | 
			
		||||
 test/client/util/util-js-test.vala | 125 +++++++++++++++++++++++
 | 
			
		||||
 2 files changed, 284 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/util/util-js.vala b/src/client/util/util-js.vala
 | 
			
		||||
index 52c9428b..2f05a3e2 100644
 | 
			
		||||
--- a/src/client/util/util-js.vala
 | 
			
		||||
+++ b/src/client/util/util-js.vala
 | 
			
		||||
@@ -127,6 +127,165 @@ namespace Util.JS {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Converts a JS value to a GLib variant.
 | 
			
		||||
+     *
 | 
			
		||||
+     * Simple value objects (string, number, and Boolean values),
 | 
			
		||||
+     * arrays of these, and objects with these types as properties are
 | 
			
		||||
+     * supported. Arrays are converted to arrays of variants, and
 | 
			
		||||
+     * objects to dictionaries containing string keys and variant
 | 
			
		||||
+     * values. Null or undefined values are returned as an empty maybe
 | 
			
		||||
+     * variant type, since it is not possible to determine the actual
 | 
			
		||||
+     * type.
 | 
			
		||||
+     *
 | 
			
		||||
+     * Throws a type error if the given value's type is not supported.
 | 
			
		||||
+     */
 | 
			
		||||
+    public inline GLib.Variant value_to_variant(JSC.Value value)
 | 
			
		||||
+        throws Error {
 | 
			
		||||
+        if (value.is_null() || value.is_undefined()) {
 | 
			
		||||
+            return new GLib.Variant.maybe(GLib.VariantType.VARIANT, null);
 | 
			
		||||
+        }
 | 
			
		||||
+        if (value.is_boolean()) {
 | 
			
		||||
+            return new GLib.Variant.boolean(value.to_boolean());
 | 
			
		||||
+        }
 | 
			
		||||
+        if (value.is_number()) {
 | 
			
		||||
+            return new GLib.Variant.double(value.to_double());
 | 
			
		||||
+        }
 | 
			
		||||
+        if (value.is_string()) {
 | 
			
		||||
+            return new GLib.Variant.string(value.to_string());
 | 
			
		||||
+        }
 | 
			
		||||
+        if (value.is_array()) {
 | 
			
		||||
+            int len = to_int32(value.object_get_property("length"));
 | 
			
		||||
+            GLib.Variant[] values = new GLib.Variant[len];
 | 
			
		||||
+            for (int i = 0; i < len; i++) {
 | 
			
		||||
+                values[i] = new GLib.Variant.variant(
 | 
			
		||||
+                    value_to_variant(value.object_get_property_at_index(i))
 | 
			
		||||
+                );
 | 
			
		||||
+            }
 | 
			
		||||
+            return new GLib.Variant.array(GLib.VariantType.VARIANT, values);
 | 
			
		||||
+        }
 | 
			
		||||
+        if (value.is_object()) {
 | 
			
		||||
+            GLib.VariantDict dict = new GLib.VariantDict();
 | 
			
		||||
+            string[] names = value.object_enumerate_properties();
 | 
			
		||||
+            if (names != null) {
 | 
			
		||||
+                foreach (var name in names) {
 | 
			
		||||
+                    try {
 | 
			
		||||
+                        dict.insert_value(
 | 
			
		||||
+                            name,
 | 
			
		||||
+                            new GLib.Variant.variant(
 | 
			
		||||
+                                value_to_variant(
 | 
			
		||||
+                                    value.object_get_property(name)
 | 
			
		||||
+                                )
 | 
			
		||||
+                            )
 | 
			
		||||
+                        );
 | 
			
		||||
+                    } catch (Error.TYPE err) {
 | 
			
		||||
+                        // ignored
 | 
			
		||||
+                    }
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+            return dict.end();
 | 
			
		||||
+        }
 | 
			
		||||
+        throw new Error.TYPE("Unsupported JS type: %s", value.to_string());
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Converts a GLib variant to a JS value.
 | 
			
		||||
+     *
 | 
			
		||||
+     * Simple value objects (string, number, and Boolean values),
 | 
			
		||||
+     * arrays and tuples of these, and dictionaries with string keys
 | 
			
		||||
+     * are supported. Tuples and arrays are converted to JS arrays,
 | 
			
		||||
+     * and dictionaries or tuples containing dictionary entries are
 | 
			
		||||
+     * converted to JS objects.
 | 
			
		||||
+     *
 | 
			
		||||
+     * Throws a type error if the given variant's type is not supported.
 | 
			
		||||
+     */
 | 
			
		||||
+    public inline JSC.Value variant_to_value(JSC.Context context,
 | 
			
		||||
+                                             GLib.Variant variant)
 | 
			
		||||
+        throws Error.TYPE {
 | 
			
		||||
+        JSC.Value? value = null;
 | 
			
		||||
+        GLib.Variant.Class type = variant.classify();
 | 
			
		||||
+        if (type == MAYBE) {
 | 
			
		||||
+            GLib.Variant? maybe = variant.get_maybe();
 | 
			
		||||
+            if (maybe != null) {
 | 
			
		||||
+                value = variant_to_value(context, maybe);
 | 
			
		||||
+            } else {
 | 
			
		||||
+                value = new JSC.Value.null(context);
 | 
			
		||||
+            }
 | 
			
		||||
+        } else if (type == VARIANT) {
 | 
			
		||||
+            value = variant_to_value(context, variant.get_variant());
 | 
			
		||||
+        } else if (type == STRING) {
 | 
			
		||||
+            value = new JSC.Value.string(context, variant.get_string());
 | 
			
		||||
+        } else if (type == BOOLEAN) {
 | 
			
		||||
+            value = new JSC.Value.boolean(context, variant.get_boolean());
 | 
			
		||||
+        } else if (type == DOUBLE) {
 | 
			
		||||
+            value = new JSC.Value.number(context, variant.get_double());
 | 
			
		||||
+        } else if (type == INT64) {
 | 
			
		||||
+            value = new JSC.Value.number(context, (double) variant.get_int64());
 | 
			
		||||
+        } else if (type == INT32) {
 | 
			
		||||
+            value = new JSC.Value.number(context, (double) variant.get_int32());
 | 
			
		||||
+        } else if (type == INT16) {
 | 
			
		||||
+            value = new JSC.Value.number(context, (double) variant.get_int16());
 | 
			
		||||
+        } else if (type == UINT64) {
 | 
			
		||||
+            value = new JSC.Value.number(context, (double) variant.get_uint64());
 | 
			
		||||
+        } else if (type == UINT32) {
 | 
			
		||||
+            value = new JSC.Value.number(context, (double) variant.get_uint32());
 | 
			
		||||
+        } else if (type == UINT16) {
 | 
			
		||||
+            value = new JSC.Value.number(context, (double) variant.get_uint16());
 | 
			
		||||
+        } else if (type == BYTE) {
 | 
			
		||||
+            value = new JSC.Value.number(context, (double) variant.get_byte());
 | 
			
		||||
+        } else if (type == ARRAY ||
 | 
			
		||||
+                   type == TUPLE) {
 | 
			
		||||
+            size_t len = variant.n_children();
 | 
			
		||||
+            if (len == 0) {
 | 
			
		||||
+                if (type == ARRAY ||
 | 
			
		||||
+                    type == TUPLE) {
 | 
			
		||||
+                    value = new JSC.Value.array_from_garray(context, null);
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    value = new JSC.Value.object(context, null, null);
 | 
			
		||||
+                }
 | 
			
		||||
+            } else {
 | 
			
		||||
+                var first = variant.get_child_value(0);
 | 
			
		||||
+                if (first.classify() == DICT_ENTRY) {
 | 
			
		||||
+                    value = new JSC.Value.object(context, null, null);
 | 
			
		||||
+                    for (size_t i = 0; i < len; i++) {
 | 
			
		||||
+                        var entry = variant.get_child_value(i);
 | 
			
		||||
+                        if (entry.classify() != DICT_ENTRY) {
 | 
			
		||||
+                            throw new Error.TYPE(
 | 
			
		||||
+                                "Variant mixes dict entries with others: %s",
 | 
			
		||||
+                                variant.print(true)
 | 
			
		||||
+                            );
 | 
			
		||||
+                        }
 | 
			
		||||
+                        var key = entry.get_child_value(0);
 | 
			
		||||
+                        if (key.classify() != STRING) {
 | 
			
		||||
+                            throw new Error.TYPE(
 | 
			
		||||
+                                "Dict entry key is not a string: %s",
 | 
			
		||||
+                                entry.print(true)
 | 
			
		||||
+                            );
 | 
			
		||||
+                        }
 | 
			
		||||
+                        value.object_set_property(
 | 
			
		||||
+                            key.get_string(),
 | 
			
		||||
+                            variant_to_value(context, entry.get_child_value(1))
 | 
			
		||||
+                        );
 | 
			
		||||
+                    }
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    var values = new GLib.GenericArray<JSC.Value>((uint) len);
 | 
			
		||||
+                    for (size_t i = 0; i < len; i++) {
 | 
			
		||||
+                        values.add(
 | 
			
		||||
+                            variant_to_value(context, variant.get_child_value(i))
 | 
			
		||||
+                        );
 | 
			
		||||
+                    }
 | 
			
		||||
+                    value = new JSC.Value.array_from_garray(context, values);
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+        }
 | 
			
		||||
+        if (value == null) {
 | 
			
		||||
+            throw new Error.TYPE(
 | 
			
		||||
+                "Unsupported variant type %s", variant.print(true)
 | 
			
		||||
+            );
 | 
			
		||||
+        }
 | 
			
		||||
+        return value;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     /**
 | 
			
		||||
      * Escapes a string so as to be safe to use as a JS string literal.
 | 
			
		||||
      *
 | 
			
		||||
diff --git a/test/client/util/util-js-test.vala b/test/client/util/util-js-test.vala
 | 
			
		||||
index 1fbe5276..16a01d83 100644
 | 
			
		||||
--- a/test/client/util/util-js-test.vala
 | 
			
		||||
+++ b/test/client/util/util-js-test.vala
 | 
			
		||||
@@ -7,9 +7,23 @@
 | 
			
		||||
 
 | 
			
		||||
 public class Util.JS.Test : TestCase {
 | 
			
		||||
 
 | 
			
		||||
+
 | 
			
		||||
+    private JSC.Context? context = null;
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
     public Test() {
 | 
			
		||||
         base("Util.JS.Test");
 | 
			
		||||
         add_test("escape_string", escape_string);
 | 
			
		||||
+        add_test("to_variant", to_variant);
 | 
			
		||||
+        add_test("to_value", to_value);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    public override void set_up() throws GLib.Error {
 | 
			
		||||
+        this.context = new JSC.Context();
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    public override void tear_down() throws GLib.Error {
 | 
			
		||||
+        this.context = null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void escape_string() throws GLib.Error {
 | 
			
		||||
@@ -21,4 +35,115 @@ public class Util.JS.Test : TestCase {
 | 
			
		||||
 
 | 
			
		||||
         assert(Util.JS.escape_string("something…\n") == """something…\n""");
 | 
			
		||||
     }
 | 
			
		||||
+
 | 
			
		||||
+    public void to_variant() throws GLib.Error {
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(new JSC.Value.null(this.context)).print(true),
 | 
			
		||||
+            "@mv nothing"
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(new JSC.Value.string(this.context, "test")).print(true),
 | 
			
		||||
+            "'test'"
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(new JSC.Value.number(this.context, 1.0)).print(true),
 | 
			
		||||
+            "1.0"
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(new JSC.Value.boolean(this.context, true)).print(true),
 | 
			
		||||
+            "true"
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(new JSC.Value.boolean(this.context, false)).print(true),
 | 
			
		||||
+            "false"
 | 
			
		||||
+        );
 | 
			
		||||
+
 | 
			
		||||
+        var value = new JSC.Value.array_from_garray(this.context, null);
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(value).print(true),
 | 
			
		||||
+            "@av []"
 | 
			
		||||
+        );
 | 
			
		||||
+        var array = new GLib.GenericArray<JSC.Value>();
 | 
			
		||||
+        array.add(new JSC.Value.string(this.context, "test"));
 | 
			
		||||
+        value = new JSC.Value.array_from_garray(this.context, array);
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(value).print(true),
 | 
			
		||||
+            "[<'test'>]"
 | 
			
		||||
+        );
 | 
			
		||||
+        value = new JSC.Value.object(this.context, null, null);
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(value).print(true),
 | 
			
		||||
+            "@a{sv} {}"
 | 
			
		||||
+        );
 | 
			
		||||
+        value.object_set_property(
 | 
			
		||||
+            "test", new JSC.Value.boolean(this.context, true)
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(value).print(true),
 | 
			
		||||
+            "{'test': <<true>>}"
 | 
			
		||||
+        );
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    public void to_value() throws GLib.Error {
 | 
			
		||||
+        var variant = new GLib.Variant.maybe(GLib.VariantType.STRING, null);
 | 
			
		||||
+        var value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_null(), variant.print(true));
 | 
			
		||||
+
 | 
			
		||||
+        variant = new GLib.Variant.string("test");
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_string(), variant.print(true));
 | 
			
		||||
+        assert_equal(value.to_string(), "test", variant.print(true));
 | 
			
		||||
+
 | 
			
		||||
+        variant = new GLib.Variant.int32(42);
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_number(), variant.print(true));
 | 
			
		||||
+        assert_equal<int32?>(value.to_int32(), 42, variant.print(true));
 | 
			
		||||
+
 | 
			
		||||
+        variant = new GLib.Variant.double(42.0);
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_number(), variant.print(true));
 | 
			
		||||
+        assert_within(value.to_double(), 42.0, 0.0000001, variant.print(true));
 | 
			
		||||
+
 | 
			
		||||
+        variant = new GLib.Variant.boolean(true);
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_boolean(), variant.print(true));
 | 
			
		||||
+        assert_true(value.to_boolean(), variant.print(true));
 | 
			
		||||
+
 | 
			
		||||
+        variant = new GLib.Variant.boolean(false);
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_boolean(), variant.print(true));
 | 
			
		||||
+        assert_false(value.to_boolean(), variant.print(true));
 | 
			
		||||
+
 | 
			
		||||
+        variant = new GLib.Variant.strv({"test"});
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_array(), variant.print(true));
 | 
			
		||||
+        assert_true(
 | 
			
		||||
+            value.object_get_property_at_index(0).is_string(),
 | 
			
		||||
+            variant.print(true)
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value.object_get_property_at_index(0).to_string(),
 | 
			
		||||
+            "test",
 | 
			
		||||
+            variant.print(true)
 | 
			
		||||
+        );
 | 
			
		||||
+
 | 
			
		||||
+        var dict = new GLib.VariantDict();
 | 
			
		||||
+        variant = dict.end();
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_object(), variant.print(true));
 | 
			
		||||
+
 | 
			
		||||
+        dict = new GLib.VariantDict();
 | 
			
		||||
+        dict.insert_value("test", new GLib.Variant.boolean(true));
 | 
			
		||||
+        variant = dict.end();
 | 
			
		||||
+        value = variant_to_value(this.context, variant);
 | 
			
		||||
+        assert_true(value.is_object(), variant.print(true));
 | 
			
		||||
+        assert_true(
 | 
			
		||||
+            value.object_get_property("test").is_boolean(),
 | 
			
		||||
+            value.to_string()
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_true(
 | 
			
		||||
+            value.object_get_property("test").to_boolean(),
 | 
			
		||||
+            value.to_string()
 | 
			
		||||
+        );
 | 
			
		||||
+    }
 | 
			
		||||
 }
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,644 @@
 | 
			
		||||
From ff565bc6efc83badbecfb48d2fbb457f4d2f681c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Thu, 27 Aug 2020 12:12:22 +1000
 | 
			
		||||
Subject: [PATCH 070/124] Components.WebView: Convert to using messages for JS
 | 
			
		||||
 method invocation
 | 
			
		||||
 | 
			
		||||
Use WebKitGTK UserMessage objects for invoking JS methods rather than
 | 
			
		||||
serialising to JS strings and running those. This is possibly slightly
 | 
			
		||||
less efficient, but removes the onus on serialising to and parsing from
 | 
			
		||||
JS and once switched over from message handlers to UserMessage objects
 | 
			
		||||
will be using a single uniform IPC interface for both.
 | 
			
		||||
---
 | 
			
		||||
 .../components/components-web-view.vala       | 97 +++++++++++++++++--
 | 
			
		||||
 src/client/composer/composer-web-view.vala    | 67 ++++++-------
 | 
			
		||||
 src/client/composer/composer-widget.vala      | 19 ++--
 | 
			
		||||
 .../conversation-web-view.vala                | 15 ++-
 | 
			
		||||
 src/client/util/util-js.vala                  | 36 ++++---
 | 
			
		||||
 .../web-process/web-process-extension.vala    | 53 ++++++++++
 | 
			
		||||
 test/js/components-page-state-test.vala       | 45 +++++++++
 | 
			
		||||
 ui/components-web-view.js                     | 10 ++
 | 
			
		||||
 8 files changed, 268 insertions(+), 74 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/components-web-view.vala b/src/client/components/components-web-view.vala
 | 
			
		||||
index 4bda1c11..368b6a8d 100644
 | 
			
		||||
--- a/src/client/components/components-web-view.vala
 | 
			
		||||
+++ b/src/client/components/components-web-view.vala
 | 
			
		||||
@@ -370,9 +370,7 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
      * Returns the view's content as an HTML string.
 | 
			
		||||
      */
 | 
			
		||||
     public async string? get_html() throws Error {
 | 
			
		||||
-        return Util.JS.to_string(
 | 
			
		||||
-            yield call(Util.JS.callable("geary.getHtml"), null)
 | 
			
		||||
-        );
 | 
			
		||||
+        return yield call_returning<string?>(Util.JS.callable("getHtml"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -410,7 +408,7 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
      * Load any remote images previously that were blocked.
 | 
			
		||||
      */
 | 
			
		||||
     public void load_remote_images() {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.loadRemoteImages"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("loadRemoteImages"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -455,21 +453,100 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     public new async void set_editable(bool enabled,
 | 
			
		||||
                                        Cancellable? cancellable)
 | 
			
		||||
         throws Error {
 | 
			
		||||
-        yield call(
 | 
			
		||||
-            Util.JS.callable("geary.setEditable").bool(enabled), cancellable
 | 
			
		||||
+        yield call_void(
 | 
			
		||||
+            Util.JS.callable("setEditable").bool(enabled), cancellable
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Invokes a {@link Util.JS.Callable} on this web view.
 | 
			
		||||
+     *
 | 
			
		||||
+     * This calls the given callable on the `geary` object for the
 | 
			
		||||
+     * current view, any returned value are ignored.
 | 
			
		||||
      */
 | 
			
		||||
-    protected async JSC.Value call(Util.JS.Callable target,
 | 
			
		||||
+    protected async void call_void(Util.JS.Callable target,
 | 
			
		||||
                                    GLib.Cancellable? cancellable)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        WebKit.JavascriptResult result = yield run_javascript(
 | 
			
		||||
-            target.to_string(), cancellable
 | 
			
		||||
+        yield send_message_to_page(
 | 
			
		||||
+            target.to_message(), cancellable
 | 
			
		||||
         );
 | 
			
		||||
-        return result.get_js_value();
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Invokes a {@link Util.JS.Callable} on this web view.
 | 
			
		||||
+     *
 | 
			
		||||
+     * This calls the given callable on the `geary` object for the
 | 
			
		||||
+     * current view. The value returned by the call is returned by
 | 
			
		||||
+     * this method.
 | 
			
		||||
+     *
 | 
			
		||||
+     * The type parameter `T` must match the type returned by the
 | 
			
		||||
+     * call, else an error is thrown. Only simple nullable value types
 | 
			
		||||
+     * are supported for T, for more complex return types (arrays,
 | 
			
		||||
+     * dictionaries, etc) specify {@link GLib.Variant} for `T` and
 | 
			
		||||
+     * manually parse that.
 | 
			
		||||
+     */
 | 
			
		||||
+    protected async T call_returning<T>(Util.JS.Callable target,
 | 
			
		||||
+                                        GLib.Cancellable? cancellable)
 | 
			
		||||
+        throws GLib.Error {
 | 
			
		||||
+        WebKit.UserMessage? response = yield send_message_to_page(
 | 
			
		||||
+            target.to_message(), cancellable
 | 
			
		||||
+        );
 | 
			
		||||
+        if (response == null) {
 | 
			
		||||
+            throw new Util.JS.Error.TYPE(
 | 
			
		||||
+                "Method call did not return a value: %s", target.to_string()
 | 
			
		||||
+            );
 | 
			
		||||
+        }
 | 
			
		||||
+        GLib.Variant? param = response.parameters;
 | 
			
		||||
+        T ret_value = null;
 | 
			
		||||
+        var ret_type = typeof(T);
 | 
			
		||||
+        if (ret_type == typeof(GLib.Variant)) {
 | 
			
		||||
+            ret_value = param;
 | 
			
		||||
+        } else {
 | 
			
		||||
+            if (param != null && param.get_type().is_maybe()) {
 | 
			
		||||
+                param = param.get_maybe();
 | 
			
		||||
+            }
 | 
			
		||||
+            if (param != null) {
 | 
			
		||||
+                // Since these replies are coming from JS via
 | 
			
		||||
+                // Util.JS.value_to_variant, they will only be one of
 | 
			
		||||
+                // string, double, bool, array or dict
 | 
			
		||||
+                var param_type = param.classify();
 | 
			
		||||
+                if (ret_type == typeof(string) && param_type == STRING) {
 | 
			
		||||
+                    ret_value = param.get_string();
 | 
			
		||||
+                } else if (ret_type == typeof(bool) && param_type == BOOLEAN) {
 | 
			
		||||
+                    ret_value = (bool?) param.get_boolean();
 | 
			
		||||
+                } else if (ret_type == typeof(int) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (int?) ((int) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(short) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (short?) ((short) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(char) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (char?) ((char) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(long) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (long?) ((long) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(int64) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (int64?) ((int64) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(uint) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (uint?) ((uint) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(uchar) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (uchar?) ((uchar) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(ushort) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (ushort?) ((ushort) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(ulong) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (ulong?) ((ulong) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(uint64) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (uint64?) ((uint64) param.get_double());
 | 
			
		||||
+                } else if (ret_type == typeof(double) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (double?) param.get_double();
 | 
			
		||||
+                } else if (ret_type == typeof(float) && param_type == DOUBLE) {
 | 
			
		||||
+                    ret_value = (float?) ((float) param.get_double());
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    throw new Util.JS.Error.TYPE(
 | 
			
		||||
+                        "%s is not a supported type for %s",
 | 
			
		||||
+                        ret_type.name(), param_type.to_string()
 | 
			
		||||
+                    );
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+        }
 | 
			
		||||
+        return ret_value;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
diff --git a/src/client/composer/composer-web-view.vala b/src/client/composer/composer-web-view.vala
 | 
			
		||||
index f8ecccf6..24a2740c 100644
 | 
			
		||||
--- a/src/client/composer/composer-web-view.vala
 | 
			
		||||
+++ b/src/client/composer/composer-web-view.vala
 | 
			
		||||
@@ -202,8 +202,8 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * Returns the view's content as HTML without being cleaned.
 | 
			
		||||
      */
 | 
			
		||||
     public async string? get_html_for_draft() throws Error {
 | 
			
		||||
-        return Util.JS.to_string(
 | 
			
		||||
-            yield call(Util.JS.callable("geary.getHtml").bool(false), null)
 | 
			
		||||
+        return yield call_returning<string?>(
 | 
			
		||||
+            Util.JS.callable("getHtml").bool(false), null
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
@@ -213,8 +213,8 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
     public void set_rich_text(bool enabled) {
 | 
			
		||||
         this.is_rich_text = enabled;
 | 
			
		||||
         if (this.is_content_loaded) {
 | 
			
		||||
-            this.call.begin(
 | 
			
		||||
-                Util.JS.callable("geary.setRichText").bool(enabled), null
 | 
			
		||||
+            this.call_void.begin(
 | 
			
		||||
+                Util.JS.callable("setRichText").bool(enabled), null
 | 
			
		||||
             );
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
@@ -223,14 +223,14 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * Undoes the last edit operation.
 | 
			
		||||
      */
 | 
			
		||||
     public void undo() {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.undo"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("undo"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Redoes the last undone edit operation.
 | 
			
		||||
      */
 | 
			
		||||
     public void redo() {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.redo"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("redo"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -239,9 +239,9 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * Returns an id to be used to refer to the selection in
 | 
			
		||||
      * subsequent calls.
 | 
			
		||||
      */
 | 
			
		||||
-    public async string save_selection() throws Error {
 | 
			
		||||
-        return Util.JS.to_string(
 | 
			
		||||
-            yield call(Util.JS.callable("geary.saveSelection"), null)
 | 
			
		||||
+    public async string? save_selection() throws Error {
 | 
			
		||||
+        return yield call_returning<string?>(
 | 
			
		||||
+            Util.JS.callable("saveSelection"), null
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
@@ -249,9 +249,7 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * Removes a saved selection.
 | 
			
		||||
      */
 | 
			
		||||
     public void free_selection(string id) {
 | 
			
		||||
-        this.call.begin(
 | 
			
		||||
-            Util.JS.callable("geary.freeSelection").string(id), null
 | 
			
		||||
-        );
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("freeSelection").string(id), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -357,9 +355,9 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * will be inserted wrapping the selection.
 | 
			
		||||
      */
 | 
			
		||||
     public void insert_link(string href, string selection_id) {
 | 
			
		||||
-        this.call.begin(
 | 
			
		||||
+        this.call_void.begin(
 | 
			
		||||
             Util.JS.callable(
 | 
			
		||||
-                "geary.insertLink"
 | 
			
		||||
+                "insertLink"
 | 
			
		||||
             ).string(href).string(selection_id),
 | 
			
		||||
             null
 | 
			
		||||
         );
 | 
			
		||||
@@ -373,8 +371,8 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * unlinked section.
 | 
			
		||||
      */
 | 
			
		||||
     public void delete_link(string selection_id) {
 | 
			
		||||
-        this.call.begin(
 | 
			
		||||
-            Util.JS.callable("geary.deleteLink").string(selection_id),
 | 
			
		||||
+        this.call_void.begin(
 | 
			
		||||
+            Util.JS.callable("deleteLink").string(selection_id),
 | 
			
		||||
             null
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
@@ -396,23 +394,23 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * Indents the line at the current text cursor location.
 | 
			
		||||
      */
 | 
			
		||||
     public void indent_line() {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.indentLine"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("indentLine"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void insert_olist() {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.insertOrderedList"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("insertOrderedList"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void insert_ulist() {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.insertUnorderedList"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("insertUnorderedList"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Updates the signature block if it has not been deleted.
 | 
			
		||||
      */
 | 
			
		||||
     public new void update_signature(string signature) {
 | 
			
		||||
-        this.call.begin(
 | 
			
		||||
-            Util.JS.callable("geary.updateSignature").string(signature), null
 | 
			
		||||
+        this.call_void.begin(
 | 
			
		||||
+            Util.JS.callable("updateSignature").string(signature), null
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
@@ -420,22 +418,21 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * Removes the quoted message (if any) from the composer.
 | 
			
		||||
      */
 | 
			
		||||
     public void delete_quoted_message() {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.deleteQuotedMessage"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("deleteQuotedMessage"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Determines if the editor content contains an attachment keyword.
 | 
			
		||||
      */
 | 
			
		||||
-    public async bool contains_attachment_keywords(string keyword_spec,
 | 
			
		||||
-                                                   string subject) {
 | 
			
		||||
+    public async bool? contains_attachment_keywords(string keyword_spec,
 | 
			
		||||
+                                                    string subject) {
 | 
			
		||||
         try {
 | 
			
		||||
-            return Util.JS.to_bool(
 | 
			
		||||
-                yield call(
 | 
			
		||||
-                    Util.JS.callable("geary.containsAttachmentKeyword")
 | 
			
		||||
-                    .string(keyword_spec)
 | 
			
		||||
-                    .string(subject),
 | 
			
		||||
-                    null)
 | 
			
		||||
-                );
 | 
			
		||||
+            return yield call_returning<bool?>(
 | 
			
		||||
+                Util.JS.callable("containsAttachmentKeyword")
 | 
			
		||||
+                .string(keyword_spec)
 | 
			
		||||
+                .string(subject),
 | 
			
		||||
+                null
 | 
			
		||||
+            );
 | 
			
		||||
         } catch (Error err) {
 | 
			
		||||
             debug("Error checking or attachment keywords: %s", err.message);
 | 
			
		||||
             return false;
 | 
			
		||||
@@ -449,7 +446,7 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
      * this.
 | 
			
		||||
      */
 | 
			
		||||
     public async void clean_content() throws Error {
 | 
			
		||||
-        this.call.begin(Util.JS.callable("geary.cleanContent"), null);
 | 
			
		||||
+        this.call_void.begin(Util.JS.callable("cleanContent"), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -459,10 +456,10 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
         const int MAX_BREAKABLE_LEN = 72; // F=F recommended line limit
 | 
			
		||||
         const int MAX_UNBREAKABLE_LEN = 998; // SMTP line limit
 | 
			
		||||
 
 | 
			
		||||
-        string body_text = Util.JS.to_string(
 | 
			
		||||
-            yield call(Util.JS.callable("geary.getText"), null)
 | 
			
		||||
+        string? body_text = yield call_returning<string?>(
 | 
			
		||||
+            Util.JS.callable("getText"), null
 | 
			
		||||
         );
 | 
			
		||||
-        string[] lines = body_text.split("\n");
 | 
			
		||||
+        string[] lines = (body_text ?? "").split("\n");
 | 
			
		||||
         GLib.StringBuilder flowed = new GLib.StringBuilder.sized(body_text.length);
 | 
			
		||||
         foreach (string line in lines) {
 | 
			
		||||
             // Strip trailing whitespace, so it doesn't look like a
 | 
			
		||||
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
 | 
			
		||||
index 4c4d0caf..9148a88e 100644
 | 
			
		||||
--- a/src/client/composer/composer-widget.vala
 | 
			
		||||
+++ b/src/client/composer/composer-widget.vala
 | 
			
		||||
@@ -1450,15 +1450,16 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
 | 
			
		||||
             confirmation = _("Send message with an empty subject?");
 | 
			
		||||
         } else if (!has_body && !has_attachment) {
 | 
			
		||||
             confirmation = _("Send message with an empty body?");
 | 
			
		||||
-        } else if (!has_attachment &&
 | 
			
		||||
-                   yield this.editor.body.contains_attachment_keywords(
 | 
			
		||||
-                       string.join(
 | 
			
		||||
-                           "|",
 | 
			
		||||
-                           ATTACHMENT_KEYWORDS,
 | 
			
		||||
-                           ATTACHMENT_KEYWORDS_LOCALISED
 | 
			
		||||
-                       ),
 | 
			
		||||
-                       this.subject)) {
 | 
			
		||||
-            confirmation = _("Send message without an attachment?");
 | 
			
		||||
+        } else if (!has_attachment) {
 | 
			
		||||
+            var keywords = string.join(
 | 
			
		||||
+                "|", ATTACHMENT_KEYWORDS, ATTACHMENT_KEYWORDS_LOCALISED
 | 
			
		||||
+            );
 | 
			
		||||
+            var contains = yield this.editor.body.contains_attachment_keywords(
 | 
			
		||||
+                keywords, this.subject
 | 
			
		||||
+            );
 | 
			
		||||
+            if (contains != null && contains) {
 | 
			
		||||
+                confirmation = _("Send message without an attachment?");
 | 
			
		||||
+            }
 | 
			
		||||
         }
 | 
			
		||||
         if (confirmation != null) {
 | 
			
		||||
             ConfirmationDialog dialog = new ConfirmationDialog(container.top_window,
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-web-view.vala b/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
index ffa36394..d77af642 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
@@ -89,20 +89,18 @@ public class ConversationWebView : Components.WebView {
 | 
			
		||||
      * Returns the current selection, for prefill as find text.
 | 
			
		||||
      */
 | 
			
		||||
     public async string? get_selection_for_find() throws Error{
 | 
			
		||||
-        JSC.Value result = yield call(
 | 
			
		||||
-            Util.JS.callable("geary.getSelectionForFind"), null
 | 
			
		||||
+        return yield call_returning<string?>(
 | 
			
		||||
+            Util.JS.callable("getSelectionForFind"), null
 | 
			
		||||
         );
 | 
			
		||||
-        return Util.JS.to_string(result);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Returns the current selection, for quoting in a message.
 | 
			
		||||
      */
 | 
			
		||||
     public async string? get_selection_for_quoting() throws Error {
 | 
			
		||||
-        JSC.Value result = yield call(
 | 
			
		||||
-            Util.JS.callable("geary.getSelectionForQuoting"), null
 | 
			
		||||
+        return yield call_returning<string?>(
 | 
			
		||||
+            Util.JS.callable("getSelectionForQuoting"), null
 | 
			
		||||
         );
 | 
			
		||||
-        return Util.JS.to_string(result);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -110,10 +108,9 @@ public class ConversationWebView : Components.WebView {
 | 
			
		||||
      */
 | 
			
		||||
     public async int? get_anchor_target_y(string anchor_body)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        JSC.Value result = yield call(
 | 
			
		||||
-            Util.JS.callable("geary.getAnchorTargetY").string(anchor_body), null
 | 
			
		||||
+        return yield call_returning<int?>(
 | 
			
		||||
+            Util.JS.callable("getAnchorTargetY").string(anchor_body), null
 | 
			
		||||
         );
 | 
			
		||||
-        return (int) Util.JS.to_int32(result);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
diff --git a/src/client/util/util-js.vala b/src/client/util/util-js.vala
 | 
			
		||||
index 2f05a3e2..d2ce9f2e 100644
 | 
			
		||||
--- a/src/client/util/util-js.vala
 | 
			
		||||
+++ b/src/client/util/util-js.vala
 | 
			
		||||
@@ -348,40 +348,54 @@ namespace Util.JS {
 | 
			
		||||
      */
 | 
			
		||||
     public class Callable {
 | 
			
		||||
 
 | 
			
		||||
-        private string base_name;
 | 
			
		||||
-        private string[] safe_args = new string[0];
 | 
			
		||||
+        private string name;
 | 
			
		||||
+        private GLib.Variant[] args = {};
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-        public Callable(string base_name) {
 | 
			
		||||
-            this.base_name = base_name;
 | 
			
		||||
+        public Callable(string name) {
 | 
			
		||||
+            this.name = name;
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+        public WebKit.UserMessage to_message() {
 | 
			
		||||
+            GLib.Variant? args = null;
 | 
			
		||||
+            if (this.args.length == 1) {
 | 
			
		||||
+                args = this.args[0];
 | 
			
		||||
+            } else if (this.args.length > 1) {
 | 
			
		||||
+                args = new GLib.Variant.tuple(this.args);
 | 
			
		||||
+            }
 | 
			
		||||
+            return new WebKit.UserMessage(this.name, args);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         public string to_string() {
 | 
			
		||||
-            return base_name + "(" + global::string.joinv(",", safe_args) + ");";
 | 
			
		||||
+            string[] args = new string[this.args.length];
 | 
			
		||||
+            for (int i = 0; i < args.length; i++) {
 | 
			
		||||
+                args[i] = this.args[i].print(true);
 | 
			
		||||
+            }
 | 
			
		||||
+            return this.name + "(" + global::string.joinv(",", args) + ")";
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         public Callable string(string value) {
 | 
			
		||||
-            add_param("\"" + escape_string(value) + "\"");
 | 
			
		||||
+            add_param(new GLib.Variant.string(value));
 | 
			
		||||
             return this;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         public Callable double(double value) {
 | 
			
		||||
-            add_param(value.to_string());
 | 
			
		||||
+            add_param(new GLib.Variant.double(value));
 | 
			
		||||
             return this;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         public Callable int(int value) {
 | 
			
		||||
-            add_param(value.to_string());
 | 
			
		||||
+            add_param(new GLib.Variant.int32(value));
 | 
			
		||||
             return this;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         public Callable bool(bool value) {
 | 
			
		||||
-            add_param(value ? "true" : "false");
 | 
			
		||||
+            add_param(new GLib.Variant.boolean(value));
 | 
			
		||||
             return this;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        private inline void add_param(string value) {
 | 
			
		||||
-            this.safe_args += value;
 | 
			
		||||
+        private inline void add_param(GLib.Variant value) {
 | 
			
		||||
+            this.args += value;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
     }
 | 
			
		||||
diff --git a/src/client/web-process/web-process-extension.vala b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
index 4bba5154..86f7f44c 100644
 | 
			
		||||
--- a/src/client/web-process/web-process-extension.vala
 | 
			
		||||
+++ b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
@@ -30,6 +30,10 @@ public void webkit_web_extension_initialize_with_user_data(WebKit.WebExtension e
 | 
			
		||||
  */
 | 
			
		||||
 public class GearyWebExtension : Object {
 | 
			
		||||
 
 | 
			
		||||
+    private const string PAGE_STATE_OBJECT_NAME = "geary";
 | 
			
		||||
+    private const string MESSAGE_RETURN_VALUE_NAME = "__return__";
 | 
			
		||||
+    private const string MESSAGE_EXCEPTION_NAME = "__exception__";
 | 
			
		||||
+
 | 
			
		||||
     private const string[] ALLOWED_SCHEMES = { "cid", "geary", "data", "blob" };
 | 
			
		||||
 
 | 
			
		||||
     private const string REMOTE_LOAD_VAR = "_gearyAllowRemoteResourceLoads";
 | 
			
		||||
@@ -157,6 +161,55 @@ public class GearyWebExtension : Object {
 | 
			
		||||
         page.get_editor().selection_changed.connect(() => {
 | 
			
		||||
                 selection_changed(page);
 | 
			
		||||
             });
 | 
			
		||||
+        page.user_message_received.connect(on_page_message_received);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    private bool on_page_message_received(WebKit.WebPage page,
 | 
			
		||||
+                                          WebKit.UserMessage message) {
 | 
			
		||||
+        WebKit.Frame frame = page.get_main_frame();
 | 
			
		||||
+        JSC.Context context = frame.get_js_context();
 | 
			
		||||
+        JSC.Value page_state = context.get_value(PAGE_STATE_OBJECT_NAME);
 | 
			
		||||
+
 | 
			
		||||
+        try {
 | 
			
		||||
+            JSC.Value[]? call_param = null;
 | 
			
		||||
+            GLib.Variant? message_param = message.parameters;
 | 
			
		||||
+            if (message_param != null) {
 | 
			
		||||
+                if (message_param.is_container()) {
 | 
			
		||||
+                    size_t len = message_param.n_children();
 | 
			
		||||
+                    call_param = new JSC.Value[len];
 | 
			
		||||
+                    for (size_t i = 0; i < len; i++) {
 | 
			
		||||
+                        call_param[i] = Util.JS.variant_to_value(
 | 
			
		||||
+                            context,
 | 
			
		||||
+                            message_param.get_child_value(i)
 | 
			
		||||
+                        );
 | 
			
		||||
+                    }
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    call_param = {
 | 
			
		||||
+                        Util.JS.variant_to_value(context, message_param)
 | 
			
		||||
+                    };
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+
 | 
			
		||||
+            JSC.Value ret = page_state.object_invoke_methodv(
 | 
			
		||||
+                message.name, call_param
 | 
			
		||||
+            );
 | 
			
		||||
+
 | 
			
		||||
+            // Must send a reply, even for void calls, otherwise
 | 
			
		||||
+            // WebKitGTK will complain. So return a message return
 | 
			
		||||
+            // rain hail or shine.
 | 
			
		||||
+            // https://bugs.webkit.org/show_bug.cgi?id=215880
 | 
			
		||||
+
 | 
			
		||||
+            message.send_reply(
 | 
			
		||||
+                new WebKit.UserMessage(
 | 
			
		||||
+                    MESSAGE_RETURN_VALUE_NAME,
 | 
			
		||||
+                    Util.JS.value_to_variant(ret)
 | 
			
		||||
+                )
 | 
			
		||||
+            );
 | 
			
		||||
+        } catch (GLib.Error err) {
 | 
			
		||||
+            debug("Failed to handle message: %s", err.message);
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+        return true;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/test/js/components-page-state-test.vala b/test/js/components-page-state-test.vala
 | 
			
		||||
index 5ec75746..562c6cda 100644
 | 
			
		||||
--- a/test/js/components-page-state-test.vala
 | 
			
		||||
+++ b/test/js/components-page-state-test.vala
 | 
			
		||||
@@ -14,12 +14,24 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
 | 
			
		||||
             base(config);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
+        public new async void call_void(Util.JS.Callable callable)
 | 
			
		||||
+            throws GLib.Error {
 | 
			
		||||
+            yield base.call_void(callable, null);
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+        public new async string call_returning(Util.JS.Callable callable)
 | 
			
		||||
+            throws GLib.Error {
 | 
			
		||||
+            return yield base.call_returning<string>(callable, null);
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public PageStateTest() {
 | 
			
		||||
         base("Components.PageStateTest");
 | 
			
		||||
         add_test("content_loaded", content_loaded);
 | 
			
		||||
+        add_test("call_void", call_void);
 | 
			
		||||
+        add_test("call_returning", call_returning);
 | 
			
		||||
 
 | 
			
		||||
         try {
 | 
			
		||||
             WebView.load_resources(GLib.File.new_for_path("/tmp"));
 | 
			
		||||
@@ -45,6 +57,30 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
 | 
			
		||||
         assert(content_loaded_triggered);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public void call_void() throws GLib.Error {
 | 
			
		||||
+        load_body_fixture("OHHAI");
 | 
			
		||||
+        var test_article = this.test_view as TestWebView;
 | 
			
		||||
+
 | 
			
		||||
+        test_article.call_void.begin(
 | 
			
		||||
+            new Util.JS.Callable("testVoid"), this.async_completion
 | 
			
		||||
+        );
 | 
			
		||||
+        test_article.call_void.end(this.async_result());
 | 
			
		||||
+        assert_test_result("void");
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    public void call_returning() throws GLib.Error {
 | 
			
		||||
+        load_body_fixture("OHHAI");
 | 
			
		||||
+        var test_article = this.test_view as TestWebView;
 | 
			
		||||
+
 | 
			
		||||
+        test_article.call_returning.begin(
 | 
			
		||||
+            new Util.JS.Callable("testReturn").string("check 1-2"),
 | 
			
		||||
+            this.async_completion
 | 
			
		||||
+        );
 | 
			
		||||
+        string ret = test_article.call_returning.end(this.async_result());
 | 
			
		||||
+        assert_equal(ret, "check 1-2");
 | 
			
		||||
+        assert_test_result("check 1-2");
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     protected override WebView set_up_test_view() {
 | 
			
		||||
         WebKit.UserScript test_script;
 | 
			
		||||
         test_script = new WebKit.UserScript(
 | 
			
		||||
@@ -60,4 +96,13 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
 | 
			
		||||
         return view;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private void assert_test_result(string expected)
 | 
			
		||||
+        throws GLib.Error {
 | 
			
		||||
+        string? result = Util.JS.to_string(
 | 
			
		||||
+            run_javascript("geary.testResult")
 | 
			
		||||
+            .get_js_value()
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(result, expected);
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/ui/components-web-view.js b/ui/components-web-view.js
 | 
			
		||||
index 80e86d7c..289abca0 100644
 | 
			
		||||
--- a/ui/components-web-view.js
 | 
			
		||||
+++ b/ui/components-web-view.js
 | 
			
		||||
@@ -87,6 +87,8 @@ PageState.prototype = {
 | 
			
		||||
         window.addEventListener("transitionend", function(e) {
 | 
			
		||||
             queuePreferredHeightUpdate();
 | 
			
		||||
         }, false); // load does not bubble
 | 
			
		||||
+
 | 
			
		||||
+        this.testResult = null;
 | 
			
		||||
     },
 | 
			
		||||
     getPreferredHeight: function() {
 | 
			
		||||
         // Return the scroll height of the HTML element since the BODY
 | 
			
		||||
@@ -184,5 +186,13 @@ PageState.prototype = {
 | 
			
		||||
             this.hasSelection = hasSelection;
 | 
			
		||||
             window.webkit.messageHandlers.selectionChanged.postMessage(hasSelection);
 | 
			
		||||
         }
 | 
			
		||||
+    },
 | 
			
		||||
+    // Methods below are for unit tests.
 | 
			
		||||
+    testVoid: function() {
 | 
			
		||||
+        this.testResult = "void";
 | 
			
		||||
+    },
 | 
			
		||||
+    testReturn: function(value) {
 | 
			
		||||
+        this.testResult = value;
 | 
			
		||||
+        return value;
 | 
			
		||||
     }
 | 
			
		||||
 };
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,266 @@
 | 
			
		||||
From c813aa5707acc5226a57dca82449dc709969d05a Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Thu, 27 Aug 2020 16:18:45 +1000
 | 
			
		||||
Subject: [PATCH 071/124] Components.WebView: Check for pass up exceptions when
 | 
			
		||||
 calling JS code
 | 
			
		||||
 | 
			
		||||
Update web extension to check for errors when invoking page state
 | 
			
		||||
methods and pass a message back if found. Check for this, decode and
 | 
			
		||||
throw a vala error in the WebView if found.
 | 
			
		||||
---
 | 
			
		||||
 .../components/components-web-view.vala       | 56 ++++++++++++++---
 | 
			
		||||
 .../web-process/web-process-extension.vala    | 39 ++++++++++--
 | 
			
		||||
 test/js/components-page-state-test.vala       | 60 +++++++++++++++++++
 | 
			
		||||
 ui/components-web-view.js                     |  4 ++
 | 
			
		||||
 4 files changed, 146 insertions(+), 13 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/components-web-view.vala b/src/client/components/components-web-view.vala
 | 
			
		||||
index 368b6a8d..2b373170 100644
 | 
			
		||||
--- a/src/client/components/components-web-view.vala
 | 
			
		||||
+++ b/src/client/components/components-web-view.vala
 | 
			
		||||
@@ -26,6 +26,10 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     /** URI Scheme and delimiter for images loaded by Content-ID. */
 | 
			
		||||
     public const string CID_URL_PREFIX = "cid:";
 | 
			
		||||
 
 | 
			
		||||
+    // Keep these in sync with GearyWebExtension
 | 
			
		||||
+    private const string MESSAGE_RETURN_VALUE_NAME = "__return__";
 | 
			
		||||
+    private const string MESSAGE_EXCEPTION_NAME = "__exception__";
 | 
			
		||||
+
 | 
			
		||||
     // WebKit message handler names
 | 
			
		||||
     private const string COMMAND_STACK_CHANGED = "commandStackChanged";
 | 
			
		||||
     private const string CONTENT_LOADED = "contentLoaded";
 | 
			
		||||
@@ -467,9 +471,7 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     protected async void call_void(Util.JS.Callable target,
 | 
			
		||||
                                    GLib.Cancellable? cancellable)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        yield send_message_to_page(
 | 
			
		||||
-            target.to_message(), cancellable
 | 
			
		||||
-        );
 | 
			
		||||
+        yield call_impl(target, cancellable);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
@@ -488,12 +490,10 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     protected async T call_returning<T>(Util.JS.Callable target,
 | 
			
		||||
                                         GLib.Cancellable? cancellable)
 | 
			
		||||
         throws GLib.Error {
 | 
			
		||||
-        WebKit.UserMessage? response = yield send_message_to_page(
 | 
			
		||||
-            target.to_message(), cancellable
 | 
			
		||||
-        );
 | 
			
		||||
+        WebKit.UserMessage? response = yield call_impl(target, cancellable);
 | 
			
		||||
         if (response == null) {
 | 
			
		||||
             throw new Util.JS.Error.TYPE(
 | 
			
		||||
-                "Method call did not return a value: %s", target.to_string()
 | 
			
		||||
+                "Method call %s did not return a value", target.to_string()
 | 
			
		||||
             );
 | 
			
		||||
         }
 | 
			
		||||
         GLib.Variant? param = response.parameters;
 | 
			
		||||
@@ -612,6 +612,48 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
                              "monospace-font", SettingsBindFlags.DEFAULT);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private async WebKit.UserMessage? call_impl(Util.JS.Callable target,
 | 
			
		||||
+                                                GLib.Cancellable? cancellable)
 | 
			
		||||
+        throws GLib.Error {
 | 
			
		||||
+        WebKit.UserMessage? response = yield send_message_to_page(
 | 
			
		||||
+            target.to_message(), cancellable
 | 
			
		||||
+        );
 | 
			
		||||
+        if (response != null) {
 | 
			
		||||
+            var response_name = response.name;
 | 
			
		||||
+            if (response_name == MESSAGE_EXCEPTION_NAME) {
 | 
			
		||||
+                var exception = new GLib.VariantDict(response.parameters);
 | 
			
		||||
+                var name = exception.lookup_value("name", GLib.VariantType.STRING) as string;
 | 
			
		||||
+                var message = exception.lookup_value("message", GLib.VariantType.STRING) as string;
 | 
			
		||||
+                var backtrace = exception.lookup_value("backtrace_string", GLib.VariantType.STRING) as string;
 | 
			
		||||
+                var source = exception.lookup_value("source_uri", GLib.VariantType.STRING) as string;
 | 
			
		||||
+                var line = exception.lookup_value("line_number", GLib.VariantType.UINT32);
 | 
			
		||||
+                var column = exception.lookup_value("column_number", GLib.VariantType.UINT32);
 | 
			
		||||
+
 | 
			
		||||
+                var log_message = "Method call %s raised %s exception at %s:%d:%d: %s".printf(
 | 
			
		||||
+                    target.to_string(),
 | 
			
		||||
+                    name ?? "unknown",
 | 
			
		||||
+                    source ?? "unknown",
 | 
			
		||||
+                    (line != null ? (int) line.get_uint32() : -1),
 | 
			
		||||
+                    (column != null ? (int) column.get_uint32() : -1),
 | 
			
		||||
+                    message ?? "unknown"
 | 
			
		||||
+                );
 | 
			
		||||
+                debug(log_message);
 | 
			
		||||
+                if (backtrace != null) {
 | 
			
		||||
+                    debug(backtrace);
 | 
			
		||||
+                }
 | 
			
		||||
+
 | 
			
		||||
+                throw new Util.JS.Error.EXCEPTION(log_message);
 | 
			
		||||
+            } else if (response_name != MESSAGE_RETURN_VALUE_NAME) {
 | 
			
		||||
+                throw new Util.JS.Error.TYPE(
 | 
			
		||||
+                    "Method call %s returned unknown name: %s",
 | 
			
		||||
+                    target.to_string(),
 | 
			
		||||
+                    response_name
 | 
			
		||||
+                );
 | 
			
		||||
+            }
 | 
			
		||||
+        }
 | 
			
		||||
+        return response;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     private void handle_cid_request(WebKit.URISchemeRequest request) {
 | 
			
		||||
         if (!handle_internal_response(request)) {
 | 
			
		||||
             request.finish_error(new FileError.NOENT("Unknown CID"));
 | 
			
		||||
diff --git a/src/client/web-process/web-process-extension.vala b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
index 86f7f44c..7aa6dd3c 100644
 | 
			
		||||
--- a/src/client/web-process/web-process-extension.vala
 | 
			
		||||
+++ b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
@@ -31,6 +31,8 @@ public void webkit_web_extension_initialize_with_user_data(WebKit.WebExtension e
 | 
			
		||||
 public class GearyWebExtension : Object {
 | 
			
		||||
 
 | 
			
		||||
     private const string PAGE_STATE_OBJECT_NAME = "geary";
 | 
			
		||||
+
 | 
			
		||||
+    // Keep these in sync with Components.WebView
 | 
			
		||||
     private const string MESSAGE_RETURN_VALUE_NAME = "__return__";
 | 
			
		||||
     private const string MESSAGE_EXCEPTION_NAME = "__exception__";
 | 
			
		||||
 
 | 
			
		||||
@@ -199,12 +201,37 @@ public class GearyWebExtension : Object {
 | 
			
		||||
             // rain hail or shine.
 | 
			
		||||
             // https://bugs.webkit.org/show_bug.cgi?id=215880
 | 
			
		||||
 
 | 
			
		||||
-            message.send_reply(
 | 
			
		||||
-                new WebKit.UserMessage(
 | 
			
		||||
-                    MESSAGE_RETURN_VALUE_NAME,
 | 
			
		||||
-                    Util.JS.value_to_variant(ret)
 | 
			
		||||
-                )
 | 
			
		||||
-            );
 | 
			
		||||
+            JSC.Exception? thrown = context.get_exception();
 | 
			
		||||
+            if (thrown != null) {
 | 
			
		||||
+                var detail = new GLib.VariantDict();
 | 
			
		||||
+                if (thrown.get_message() != null) {
 | 
			
		||||
+                    detail.insert_value("name", new GLib.Variant.string(thrown.get_name()));
 | 
			
		||||
+                }
 | 
			
		||||
+                if (thrown.get_message() != null) {
 | 
			
		||||
+                    detail.insert_value("message", new GLib.Variant.string(thrown.get_message()));
 | 
			
		||||
+                }
 | 
			
		||||
+                if (thrown.get_backtrace_string() != null) {
 | 
			
		||||
+                    detail.insert_value("backtrace_string", new GLib.Variant.string(thrown.get_backtrace_string()));
 | 
			
		||||
+                }
 | 
			
		||||
+                if (thrown.get_source_uri() != null) {
 | 
			
		||||
+                    detail.insert_value("source_uri", new GLib.Variant.string(thrown.get_source_uri()));
 | 
			
		||||
+                }
 | 
			
		||||
+                detail.insert_value("line_number", new GLib.Variant.uint32(thrown.get_line_number()));
 | 
			
		||||
+                detail.insert_value("column_number", new GLib.Variant.uint32(thrown.get_column_number()));
 | 
			
		||||
+                message.send_reply(
 | 
			
		||||
+                    new WebKit.UserMessage(
 | 
			
		||||
+                        MESSAGE_EXCEPTION_NAME,
 | 
			
		||||
+                        detail.end()
 | 
			
		||||
+                    )
 | 
			
		||||
+                );
 | 
			
		||||
+            } else {
 | 
			
		||||
+                message.send_reply(
 | 
			
		||||
+                    new WebKit.UserMessage(
 | 
			
		||||
+                        MESSAGE_RETURN_VALUE_NAME,
 | 
			
		||||
+                        Util.JS.value_to_variant(ret)
 | 
			
		||||
+                    )
 | 
			
		||||
+                );
 | 
			
		||||
+            }
 | 
			
		||||
         } catch (GLib.Error err) {
 | 
			
		||||
             debug("Failed to handle message: %s", err.message);
 | 
			
		||||
         }
 | 
			
		||||
diff --git a/test/js/components-page-state-test.vala b/test/js/components-page-state-test.vala
 | 
			
		||||
index 562c6cda..bf952416 100644
 | 
			
		||||
--- a/test/js/components-page-state-test.vala
 | 
			
		||||
+++ b/test/js/components-page-state-test.vala
 | 
			
		||||
@@ -31,7 +31,9 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
 | 
			
		||||
         base("Components.PageStateTest");
 | 
			
		||||
         add_test("content_loaded", content_loaded);
 | 
			
		||||
         add_test("call_void", call_void);
 | 
			
		||||
+        add_test("call_void_throws", call_void_throws);
 | 
			
		||||
         add_test("call_returning", call_returning);
 | 
			
		||||
+        add_test("call_returning_throws", call_returning_throws);
 | 
			
		||||
 
 | 
			
		||||
         try {
 | 
			
		||||
             WebView.load_resources(GLib.File.new_for_path("/tmp"));
 | 
			
		||||
@@ -68,6 +70,35 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
 | 
			
		||||
         assert_test_result("void");
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public void call_void_throws() throws GLib.Error {
 | 
			
		||||
+        load_body_fixture("OHHAI");
 | 
			
		||||
+        var test_article = this.test_view as TestWebView;
 | 
			
		||||
+
 | 
			
		||||
+        try {
 | 
			
		||||
+            test_article.call_void.begin(
 | 
			
		||||
+                new Util.JS.Callable("testThrow").string("void message"),
 | 
			
		||||
+                this.async_completion
 | 
			
		||||
+            );
 | 
			
		||||
+            test_article.call_void.end(this.async_result());
 | 
			
		||||
+            assert_not_reached();
 | 
			
		||||
+        } catch (Util.JS.Error.EXCEPTION err) {
 | 
			
		||||
+            assert_string(
 | 
			
		||||
+                err.message
 | 
			
		||||
+            ).contains(
 | 
			
		||||
+                "testThrow"
 | 
			
		||||
+            // WebKitGTK doesn't actually pass any details through:
 | 
			
		||||
+            // https://bugs.webkit.org/show_bug.cgi?id=215877
 | 
			
		||||
+            // ).contains(
 | 
			
		||||
+            //     "Error"
 | 
			
		||||
+            // ).contains(
 | 
			
		||||
+            //     "void message"
 | 
			
		||||
+            // ).contains(
 | 
			
		||||
+            //     "components-web-view.js"
 | 
			
		||||
+            );
 | 
			
		||||
+            assert_test_result("void message");
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     public void call_returning() throws GLib.Error {
 | 
			
		||||
         load_body_fixture("OHHAI");
 | 
			
		||||
         var test_article = this.test_view as TestWebView;
 | 
			
		||||
@@ -81,6 +112,35 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
 | 
			
		||||
         assert_test_result("check 1-2");
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    public void call_returning_throws() throws GLib.Error {
 | 
			
		||||
+        load_body_fixture("OHHAI");
 | 
			
		||||
+        var test_article = this.test_view as TestWebView;
 | 
			
		||||
+
 | 
			
		||||
+        try {
 | 
			
		||||
+            test_article.call_returning.begin(
 | 
			
		||||
+                new Util.JS.Callable("testThrow").string("return message"),
 | 
			
		||||
+                this.async_completion
 | 
			
		||||
+            );
 | 
			
		||||
+            test_article.call_returning.end(this.async_result());
 | 
			
		||||
+            assert_not_reached();
 | 
			
		||||
+        } catch (Util.JS.Error.EXCEPTION err) {
 | 
			
		||||
+            assert_string(
 | 
			
		||||
+                err.message
 | 
			
		||||
+            ).contains(
 | 
			
		||||
+                "testThrow"
 | 
			
		||||
+            // WebKitGTK doesn't actually pass any details through:
 | 
			
		||||
+            // https://bugs.webkit.org/show_bug.cgi?id=215877
 | 
			
		||||
+            // ).contains(
 | 
			
		||||
+            //     "Error"
 | 
			
		||||
+            // ).contains(
 | 
			
		||||
+            //     "return message"
 | 
			
		||||
+            // ).contains(
 | 
			
		||||
+            //     "components-web-view.js"
 | 
			
		||||
+            );
 | 
			
		||||
+            assert_test_result("return message");
 | 
			
		||||
+        }
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     protected override WebView set_up_test_view() {
 | 
			
		||||
         WebKit.UserScript test_script;
 | 
			
		||||
         test_script = new WebKit.UserScript(
 | 
			
		||||
diff --git a/ui/components-web-view.js b/ui/components-web-view.js
 | 
			
		||||
index 289abca0..0f932a19 100644
 | 
			
		||||
--- a/ui/components-web-view.js
 | 
			
		||||
+++ b/ui/components-web-view.js
 | 
			
		||||
@@ -194,5 +194,9 @@ PageState.prototype = {
 | 
			
		||||
     testReturn: function(value) {
 | 
			
		||||
         this.testResult = value;
 | 
			
		||||
         return value;
 | 
			
		||||
+    },
 | 
			
		||||
+    testThrow: function(value) {
 | 
			
		||||
+        this.testResult = value;
 | 
			
		||||
+        throw this.testResult;
 | 
			
		||||
     }
 | 
			
		||||
 };
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
From db69807836cb2485af0941a83f57451c034b21a0 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 09:44:46 +1000
 | 
			
		||||
Subject: [PATCH 072/124] GearyWebExtension: Add factory method for error user
 | 
			
		||||
 messages
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../web-process/web-process-extension.vala    | 56 +++++++++++++------
 | 
			
		||||
 1 file changed, 38 insertions(+), 18 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/web-process/web-process-extension.vala b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
index 7aa6dd3c..89d9a1e3 100644
 | 
			
		||||
--- a/src/client/web-process/web-process-extension.vala
 | 
			
		||||
+++ b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
@@ -145,6 +145,37 @@ public class GearyWebExtension : Object {
 | 
			
		||||
         return ret;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private WebKit.UserMessage to_exception_message(string? name,
 | 
			
		||||
+                                                    string? message,
 | 
			
		||||
+                                                    string? backtrace = null,
 | 
			
		||||
+                                                    string? source = null,
 | 
			
		||||
+                                                    int line_number = -1,
 | 
			
		||||
+                                                    int column_number = -1) {
 | 
			
		||||
+        var detail = new GLib.VariantDict();
 | 
			
		||||
+        if (name != null) {
 | 
			
		||||
+            detail.insert_value("name", new GLib.Variant.string(name));
 | 
			
		||||
+        }
 | 
			
		||||
+        if (message != null) {
 | 
			
		||||
+            detail.insert_value("message", new GLib.Variant.string(message));
 | 
			
		||||
+        }
 | 
			
		||||
+        if (backtrace != null) {
 | 
			
		||||
+            detail.insert_value("backtrace", new GLib.Variant.string(backtrace));
 | 
			
		||||
+        }
 | 
			
		||||
+        if (source != null) {
 | 
			
		||||
+            detail.insert_value("source", new GLib.Variant.string(source));
 | 
			
		||||
+        }
 | 
			
		||||
+        if (line_number > 0) {
 | 
			
		||||
+            detail.insert_value("line_number", new GLib.Variant.uint32(line_number));
 | 
			
		||||
+        }
 | 
			
		||||
+        if (column_number > 0) {
 | 
			
		||||
+            detail.insert_value("column_number", new GLib.Variant.uint32(column_number));
 | 
			
		||||
+        }
 | 
			
		||||
+        return new WebKit.UserMessage(
 | 
			
		||||
+            MESSAGE_EXCEPTION_NAME,
 | 
			
		||||
+            detail.end()
 | 
			
		||||
+        );
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     private void on_page_created(WebKit.WebExtension extension,
 | 
			
		||||
                                  WebKit.WebPage page) {
 | 
			
		||||
         WebKit.Frame frame = page.get_main_frame();
 | 
			
		||||
@@ -203,25 +234,14 @@ public class GearyWebExtension : Object {
 | 
			
		||||
 
 | 
			
		||||
             JSC.Exception? thrown = context.get_exception();
 | 
			
		||||
             if (thrown != null) {
 | 
			
		||||
-                var detail = new GLib.VariantDict();
 | 
			
		||||
-                if (thrown.get_message() != null) {
 | 
			
		||||
-                    detail.insert_value("name", new GLib.Variant.string(thrown.get_name()));
 | 
			
		||||
-                }
 | 
			
		||||
-                if (thrown.get_message() != null) {
 | 
			
		||||
-                    detail.insert_value("message", new GLib.Variant.string(thrown.get_message()));
 | 
			
		||||
-                }
 | 
			
		||||
-                if (thrown.get_backtrace_string() != null) {
 | 
			
		||||
-                    detail.insert_value("backtrace_string", new GLib.Variant.string(thrown.get_backtrace_string()));
 | 
			
		||||
-                }
 | 
			
		||||
-                if (thrown.get_source_uri() != null) {
 | 
			
		||||
-                    detail.insert_value("source_uri", new GLib.Variant.string(thrown.get_source_uri()));
 | 
			
		||||
-                }
 | 
			
		||||
-                detail.insert_value("line_number", new GLib.Variant.uint32(thrown.get_line_number()));
 | 
			
		||||
-                detail.insert_value("column_number", new GLib.Variant.uint32(thrown.get_column_number()));
 | 
			
		||||
                 message.send_reply(
 | 
			
		||||
-                    new WebKit.UserMessage(
 | 
			
		||||
-                        MESSAGE_EXCEPTION_NAME,
 | 
			
		||||
-                        detail.end()
 | 
			
		||||
+                    to_exception_message(
 | 
			
		||||
+                        thrown.get_name(),
 | 
			
		||||
+                        thrown.get_message(),
 | 
			
		||||
+                        thrown.get_backtrace_string(),
 | 
			
		||||
+                        thrown.get_source_uri(),
 | 
			
		||||
+                        (int) thrown.get_line_number(),
 | 
			
		||||
+                        (int) thrown.get_column_number()
 | 
			
		||||
                     )
 | 
			
		||||
                 );
 | 
			
		||||
             } else {
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,223 @@
 | 
			
		||||
From 6162785d997fcfa4efaf6ec83670b2fab8cca6bd Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 09:49:46 +1000
 | 
			
		||||
Subject: [PATCH 073/124] GearyWebExtension: Add support for sending messages
 | 
			
		||||
 from JS to client
 | 
			
		||||
 | 
			
		||||
Define a vala-backed JS class in the extension and make that available
 | 
			
		||||
to pages when they are registered. Add some helper JS to PageState for
 | 
			
		||||
defining message sending functions. Listen for these in
 | 
			
		||||
Components.WebView and dispatch to the registered callback for it.
 | 
			
		||||
---
 | 
			
		||||
 .../components/components-web-view.vala       | 55 ++++++++++++++++
 | 
			
		||||
 .../web-process/web-process-extension.vala    | 63 +++++++++++++++++++
 | 
			
		||||
 ui/components-web-view.js                     |  9 +++
 | 
			
		||||
 3 files changed, 127 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/components-web-view.vala b/src/client/components/components-web-view.vala
 | 
			
		||||
index 2b373170..c746c441 100644
 | 
			
		||||
--- a/src/client/components/components-web-view.vala
 | 
			
		||||
+++ b/src/client/components/components-web-view.vala
 | 
			
		||||
@@ -198,6 +198,24 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     /** Delegate for UserContentManager message callbacks. */
 | 
			
		||||
     public delegate void JavaScriptMessageHandler(WebKit.JavascriptResult js_result);
 | 
			
		||||
 
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Delegate for message handler callbacks.
 | 
			
		||||
+     *
 | 
			
		||||
+     * @see register_message_callback
 | 
			
		||||
+     */
 | 
			
		||||
+    protected delegate void MessageCallback(GLib.Variant? parameters);
 | 
			
		||||
+
 | 
			
		||||
+    // Work around for not being able to put delegates in a Gee collection.
 | 
			
		||||
+    private class MessageCallable {
 | 
			
		||||
+
 | 
			
		||||
+        public unowned MessageCallback handler;
 | 
			
		||||
+
 | 
			
		||||
+        public MessageCallable(MessageCallback handler) {
 | 
			
		||||
+            this.handler = handler;
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     /**
 | 
			
		||||
      * Determines if the view's content has been fully loaded.
 | 
			
		||||
      *
 | 
			
		||||
@@ -263,6 +281,8 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
 
 | 
			
		||||
     private Gee.List<ulong> registered_message_handlers =
 | 
			
		||||
         new Gee.LinkedList<ulong>();
 | 
			
		||||
+    private Gee.Map<string,MessageCallable> message_handlers =
 | 
			
		||||
+        new Gee.HashMap<string,MessageCallable>();
 | 
			
		||||
 
 | 
			
		||||
     private double webkit_reported_height = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -359,6 +379,7 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
             this.user_content_manager.disconnect(id);
 | 
			
		||||
         }
 | 
			
		||||
         this.registered_message_handlers.clear();
 | 
			
		||||
+        this.message_handlers.clear();
 | 
			
		||||
         base.destroy();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
@@ -568,6 +589,14 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    /**
 | 
			
		||||
+     * Registers a callback for a specific WebKit user message.
 | 
			
		||||
+     */
 | 
			
		||||
+    protected void register_message_callback(string name,
 | 
			
		||||
+                                             MessageCallback handler) {
 | 
			
		||||
+        this.message_handlers.set(name, new MessageCallable(handler));
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     private void init(Application.Configuration config) {
 | 
			
		||||
         // XXX get the allow prefix from the extension somehow
 | 
			
		||||
 
 | 
			
		||||
@@ -595,6 +624,8 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
             SELECTION_CHANGED, on_selection_changed
 | 
			
		||||
         );
 | 
			
		||||
 
 | 
			
		||||
+        this.user_message_received.connect(this.on_message_received);
 | 
			
		||||
+
 | 
			
		||||
         // Manage zoom level, ensure it's sane
 | 
			
		||||
         config.bind(Application.Configuration.CONVERSATION_VIEWER_ZOOM_KEY, this, "zoom_level");
 | 
			
		||||
         if (this.zoom_level < ZOOM_MIN) {
 | 
			
		||||
@@ -803,6 +834,30 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private bool on_message_received(WebKit.UserMessage message) {
 | 
			
		||||
+        if (message.name == MESSAGE_EXCEPTION_NAME) {
 | 
			
		||||
+            var detail = new GLib.VariantDict(message.parameters);
 | 
			
		||||
+            var name = detail.lookup_value("name", GLib.VariantType.STRING) as string;
 | 
			
		||||
+            var log_message = detail.lookup_value("message", GLib.VariantType.STRING) as string;
 | 
			
		||||
+            warning(
 | 
			
		||||
+                "Error sending message from JS: %s: %s",
 | 
			
		||||
+                name ?? "unknown",
 | 
			
		||||
+                log_message ?? "unknown"
 | 
			
		||||
+            );
 | 
			
		||||
+        } else if (this.message_handlers.has_key(message.name)) {
 | 
			
		||||
+            debug(
 | 
			
		||||
+                "Message received: %s(%s)",
 | 
			
		||||
+                message.name,
 | 
			
		||||
+                message.parameters != null ? message.parameters.print(true) : ""
 | 
			
		||||
+            );
 | 
			
		||||
+            MessageCallable callback = this.message_handlers.get(message.name);
 | 
			
		||||
+            callback.handler(message.parameters);
 | 
			
		||||
+        } else {
 | 
			
		||||
+            warning("Message with unknown handler received: %s", message.name);
 | 
			
		||||
+        }
 | 
			
		||||
+        return true;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 // XXX this needs to be moved into the libsoup bindings
 | 
			
		||||
diff --git a/src/client/web-process/web-process-extension.vala b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
index 89d9a1e3..31f2b0f0 100644
 | 
			
		||||
--- a/src/client/web-process/web-process-extension.vala
 | 
			
		||||
+++ b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
@@ -38,6 +38,8 @@ public class GearyWebExtension : Object {
 | 
			
		||||
 
 | 
			
		||||
     private const string[] ALLOWED_SCHEMES = { "cid", "geary", "data", "blob" };
 | 
			
		||||
 
 | 
			
		||||
+    private const string EXTENSION_CLASS_VAR = "_GearyWebExtension";
 | 
			
		||||
+    private const string EXTENSION_CLASS_SEND = "send";
 | 
			
		||||
     private const string REMOTE_LOAD_VAR = "_gearyAllowRemoteResourceLoads";
 | 
			
		||||
 
 | 
			
		||||
     private WebKit.WebExtension extension;
 | 
			
		||||
@@ -180,6 +182,25 @@ public class GearyWebExtension : Object {
 | 
			
		||||
                                  WebKit.WebPage page) {
 | 
			
		||||
         WebKit.Frame frame = page.get_main_frame();
 | 
			
		||||
         JSC.Context context = frame.get_js_context();
 | 
			
		||||
+
 | 
			
		||||
+        var extension_class = context.register_class(
 | 
			
		||||
+            this.get_type().name(),
 | 
			
		||||
+            null,
 | 
			
		||||
+            null,
 | 
			
		||||
+            null
 | 
			
		||||
+        );
 | 
			
		||||
+        extension_class.add_method(
 | 
			
		||||
+            EXTENSION_CLASS_SEND,
 | 
			
		||||
+            (instance, values) => {
 | 
			
		||||
+                return this.on_page_send_message(page, values);
 | 
			
		||||
+            },
 | 
			
		||||
+            GLib.Type.NONE
 | 
			
		||||
+        );
 | 
			
		||||
+        context.set_value(
 | 
			
		||||
+            EXTENSION_CLASS_VAR,
 | 
			
		||||
+            new JSC.Value.object(context, extension_class, extension_class)
 | 
			
		||||
+        );
 | 
			
		||||
+
 | 
			
		||||
         context.set_value(
 | 
			
		||||
             REMOTE_LOAD_VAR,
 | 
			
		||||
             new JSC.Value.boolean(context, false)
 | 
			
		||||
@@ -259,4 +280,46 @@ public class GearyWebExtension : Object {
 | 
			
		||||
         return true;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    private bool on_page_send_message(WebKit.WebPage page,
 | 
			
		||||
+                                      GLib.GenericArray<JSC.Value> args) {
 | 
			
		||||
+        WebKit.UserMessage? message = null;
 | 
			
		||||
+        if (args.length > 0) {
 | 
			
		||||
+            var name = args.get(0).to_string();
 | 
			
		||||
+            GLib.Variant? parameters = null;
 | 
			
		||||
+            if (args.length > 1) {
 | 
			
		||||
+                JSC.Value param_value = args.get(1);
 | 
			
		||||
+                try {
 | 
			
		||||
+                    int len = Util.JS.to_int32(
 | 
			
		||||
+                        param_value.object_get_property("length")
 | 
			
		||||
+                    );
 | 
			
		||||
+                    if (len == 1) {
 | 
			
		||||
+                        parameters = Util.JS.value_to_variant(
 | 
			
		||||
+                            param_value.object_get_property_at_index(0)
 | 
			
		||||
+                        );
 | 
			
		||||
+                    } else if (len > 1) {
 | 
			
		||||
+                        parameters = Util.JS.value_to_variant(param_value);
 | 
			
		||||
+                    }
 | 
			
		||||
+                } catch (Util.JS.Error err) {
 | 
			
		||||
+                    message = to_exception_message(
 | 
			
		||||
+                        this.get_type().name(), err.message
 | 
			
		||||
+                    );
 | 
			
		||||
+                }
 | 
			
		||||
+            }
 | 
			
		||||
+            if (message == null) {
 | 
			
		||||
+                message = new WebKit.UserMessage(name, parameters);
 | 
			
		||||
+            }
 | 
			
		||||
+        }
 | 
			
		||||
+        if (message == null) {
 | 
			
		||||
+            var log_message = "Not enough parameters for JS call to %s.%s()".printf(
 | 
			
		||||
+                EXTENSION_CLASS_VAR,
 | 
			
		||||
+                EXTENSION_CLASS_SEND
 | 
			
		||||
+            );
 | 
			
		||||
+            debug(log_message);
 | 
			
		||||
+            message = to_exception_message(this.get_type().name(), log_message);
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+        page.send_message_to_view.begin(message, null);
 | 
			
		||||
+        return true;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/ui/components-web-view.js b/ui/components-web-view.js
 | 
			
		||||
index 0f932a19..35e82dfc 100644
 | 
			
		||||
--- a/ui/components-web-view.js
 | 
			
		||||
+++ b/ui/components-web-view.js
 | 
			
		||||
@@ -200,3 +200,12 @@ PageState.prototype = {
 | 
			
		||||
         throw this.testResult;
 | 
			
		||||
     }
 | 
			
		||||
 };
 | 
			
		||||
+
 | 
			
		||||
+let MessageSender = function(name) {
 | 
			
		||||
+    return function() {
 | 
			
		||||
+        // Since typeof(arguments) == 'object', convert to an array so
 | 
			
		||||
+        // that Components.WebView.MessageCallback callbacks get
 | 
			
		||||
+        // arrays or tuples rather than dicts as arguments
 | 
			
		||||
+        _GearyWebExtension.send(name, Array.from(arguments));
 | 
			
		||||
+    };
 | 
			
		||||
+};
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,275 @@
 | 
			
		||||
From 89453931bf6743049644274fc730a10e7bd2a53d Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 11:20:27 +1000
 | 
			
		||||
Subject: [PATCH 074/124] Util.Js: Improve JSC Value to GLib.Variant conversion
 | 
			
		||||
 | 
			
		||||
Stop needlessly wrapping object members and array elements in
 | 
			
		||||
variant variants.
 | 
			
		||||
 | 
			
		||||
Don't wrap object values in variants since the code is already using
 | 
			
		||||
vardicts for these. Return a variant array if a JS array contains values
 | 
			
		||||
of all the same type and don't wrap these in variants, else return
 | 
			
		||||
a tuple, which don't need to be wrapped either.
 | 
			
		||||
---
 | 
			
		||||
 src/client/util/util-js.vala       | 160 +++++++++++++++++++++--------
 | 
			
		||||
 test/client/util/util-js-test.vala |  28 ++++-
 | 
			
		||||
 2 files changed, 143 insertions(+), 45 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/util/util-js.vala b/src/client/util/util-js.vala
 | 
			
		||||
index d2ce9f2e..095f9da4 100644
 | 
			
		||||
--- a/src/client/util/util-js.vala
 | 
			
		||||
+++ b/src/client/util/util-js.vala
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
 /*
 | 
			
		||||
- * Copyright 2017,2019 Michael James Gratton <mike@vee.net>
 | 
			
		||||
+ * Copyright © 2017-2020 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.
 | 
			
		||||
@@ -25,6 +25,64 @@ namespace Util.JS {
 | 
			
		||||
         TYPE
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    /** Supported types of JSC values. */
 | 
			
		||||
+    public enum JscType {
 | 
			
		||||
+
 | 
			
		||||
+        /** Specifies an unsupported value type. */
 | 
			
		||||
+        UNKNOWN,
 | 
			
		||||
+
 | 
			
		||||
+        /** Specifies a JavaScript `undefined` value. */
 | 
			
		||||
+        UNDEFINED,
 | 
			
		||||
+
 | 
			
		||||
+        /** Specifies a JavaScript `null` value. */
 | 
			
		||||
+        NULL,
 | 
			
		||||
+        FUNCTION,
 | 
			
		||||
+        STRING,
 | 
			
		||||
+        NUMBER,
 | 
			
		||||
+        BOOLEAN,
 | 
			
		||||
+        ARRAY,
 | 
			
		||||
+        CONSTRUCTOR,
 | 
			
		||||
+        OBJECT;
 | 
			
		||||
+
 | 
			
		||||
+        /**
 | 
			
		||||
+         * Determines the type of a JSC value.
 | 
			
		||||
+         *
 | 
			
		||||
+         * Returns the type of the given value, or {@link UNKNOWN} if
 | 
			
		||||
+         * it could not be determined.
 | 
			
		||||
+         */
 | 
			
		||||
+        public static JscType to_type(JSC.Value value) {
 | 
			
		||||
+            if (value.is_undefined()) {
 | 
			
		||||
+                return UNDEFINED;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_null()) {
 | 
			
		||||
+                return NULL;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_string()) {
 | 
			
		||||
+                return STRING;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_number()) {
 | 
			
		||||
+                return NUMBER;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_boolean()) {
 | 
			
		||||
+                return BOOLEAN;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_array()) {
 | 
			
		||||
+                return ARRAY;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_object()) {
 | 
			
		||||
+                return OBJECT;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_function()) {
 | 
			
		||||
+                return FUNCTION;
 | 
			
		||||
+            }
 | 
			
		||||
+            if (value.is_constructor()) {
 | 
			
		||||
+                return CONSTRUCTOR;
 | 
			
		||||
+            }
 | 
			
		||||
+            return UNKNOWN;
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
     /**
 | 
			
		||||
      * Returns a JSC Value as a bool.
 | 
			
		||||
      *
 | 
			
		||||
@@ -132,60 +190,80 @@ namespace Util.JS {
 | 
			
		||||
      *
 | 
			
		||||
      * Simple value objects (string, number, and Boolean values),
 | 
			
		||||
      * arrays of these, and objects with these types as properties are
 | 
			
		||||
-     * supported. Arrays are converted to arrays of variants, and
 | 
			
		||||
-     * objects to dictionaries containing string keys and variant
 | 
			
		||||
-     * values. Null or undefined values are returned as an empty maybe
 | 
			
		||||
-     * variant type, since it is not possible to determine the actual
 | 
			
		||||
-     * type.
 | 
			
		||||
+     * supported. Arrays containing objects of the same type are
 | 
			
		||||
+     * converted to arrays, otherwise they are converted to tuples,
 | 
			
		||||
+     * empty arrays are converted to the unit tuple, and objects are
 | 
			
		||||
+     * converted to vardict containing property names as keys and
 | 
			
		||||
+     * values. Null and undefined values are returned as an empty
 | 
			
		||||
+     * maybe variant type, since it is not possible to determine the
 | 
			
		||||
+     * actual type.
 | 
			
		||||
      *
 | 
			
		||||
      * Throws a type error if the given value's type is not supported.
 | 
			
		||||
      */
 | 
			
		||||
     public inline GLib.Variant value_to_variant(JSC.Value value)
 | 
			
		||||
         throws Error {
 | 
			
		||||
-        if (value.is_null() || value.is_undefined()) {
 | 
			
		||||
-            return new GLib.Variant.maybe(GLib.VariantType.VARIANT, null);
 | 
			
		||||
-        }
 | 
			
		||||
-        if (value.is_boolean()) {
 | 
			
		||||
-            return new GLib.Variant.boolean(value.to_boolean());
 | 
			
		||||
-        }
 | 
			
		||||
-        if (value.is_number()) {
 | 
			
		||||
-            return new GLib.Variant.double(value.to_double());
 | 
			
		||||
-        }
 | 
			
		||||
-        if (value.is_string()) {
 | 
			
		||||
-            return new GLib.Variant.string(value.to_string());
 | 
			
		||||
-        }
 | 
			
		||||
-        if (value.is_array()) {
 | 
			
		||||
+        GLib.Variant? variant = null;
 | 
			
		||||
+        switch (JscType.to_type(value)) {
 | 
			
		||||
+        case UNDEFINED:
 | 
			
		||||
+        case NULL:
 | 
			
		||||
+            variant = new GLib.Variant.maybe(GLib.VariantType.VARIANT, null);
 | 
			
		||||
+            break;
 | 
			
		||||
+
 | 
			
		||||
+        case STRING:
 | 
			
		||||
+            variant = new GLib.Variant.string(value.to_string());
 | 
			
		||||
+            break;
 | 
			
		||||
+
 | 
			
		||||
+        case NUMBER:
 | 
			
		||||
+            variant = new GLib.Variant.double(value.to_double());
 | 
			
		||||
+            break;
 | 
			
		||||
+
 | 
			
		||||
+        case BOOLEAN:
 | 
			
		||||
+            variant = new GLib.Variant.boolean(value.to_boolean());
 | 
			
		||||
+            break;
 | 
			
		||||
+
 | 
			
		||||
+        case ARRAY:
 | 
			
		||||
             int len = to_int32(value.object_get_property("length"));
 | 
			
		||||
-            GLib.Variant[] values = new GLib.Variant[len];
 | 
			
		||||
-            for (int i = 0; i < len; i++) {
 | 
			
		||||
-                values[i] = new GLib.Variant.variant(
 | 
			
		||||
-                    value_to_variant(value.object_get_property_at_index(i))
 | 
			
		||||
-                );
 | 
			
		||||
+            if (len == 0) {
 | 
			
		||||
+                variant = new GLib.Variant.tuple({});
 | 
			
		||||
+            } else {
 | 
			
		||||
+                JSC.Value element = value.object_get_property_at_index(0);
 | 
			
		||||
+                var first_type = JscType.to_type(element);
 | 
			
		||||
+                var all_same_type = true;
 | 
			
		||||
+                var values = new GLib.Variant[len];
 | 
			
		||||
+                values[0] = value_to_variant(element);
 | 
			
		||||
+                for (int i = 1; i < len; i++) {
 | 
			
		||||
+                    element = value.object_get_property_at_index(i);
 | 
			
		||||
+                    values[i] = value_to_variant(element);
 | 
			
		||||
+                    all_same_type &= (first_type == JscType.to_type(element));
 | 
			
		||||
+                }
 | 
			
		||||
+                if (!all_same_type) {
 | 
			
		||||
+                    variant = new GLib.Variant.tuple(values);
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    variant = new GLib.Variant.array(
 | 
			
		||||
+                        values[0].get_type(), values
 | 
			
		||||
+                    );
 | 
			
		||||
+                }
 | 
			
		||||
             }
 | 
			
		||||
-            return new GLib.Variant.array(GLib.VariantType.VARIANT, values);
 | 
			
		||||
-        }
 | 
			
		||||
-        if (value.is_object()) {
 | 
			
		||||
+            break;
 | 
			
		||||
+
 | 
			
		||||
+        case OBJECT:
 | 
			
		||||
             GLib.VariantDict dict = new GLib.VariantDict();
 | 
			
		||||
             string[] names = value.object_enumerate_properties();
 | 
			
		||||
             if (names != null) {
 | 
			
		||||
                 foreach (var name in names) {
 | 
			
		||||
-                    try {
 | 
			
		||||
-                        dict.insert_value(
 | 
			
		||||
-                            name,
 | 
			
		||||
-                            new GLib.Variant.variant(
 | 
			
		||||
-                                value_to_variant(
 | 
			
		||||
-                                    value.object_get_property(name)
 | 
			
		||||
-                                )
 | 
			
		||||
-                            )
 | 
			
		||||
-                        );
 | 
			
		||||
-                    } catch (Error.TYPE err) {
 | 
			
		||||
-                        // ignored
 | 
			
		||||
-                    }
 | 
			
		||||
+                    dict.insert_value(
 | 
			
		||||
+                        name,
 | 
			
		||||
+                        value_to_variant(value.object_get_property(name))
 | 
			
		||||
+                    );
 | 
			
		||||
                 }
 | 
			
		||||
             }
 | 
			
		||||
-            return dict.end();
 | 
			
		||||
+            variant = dict.end();
 | 
			
		||||
+            break;
 | 
			
		||||
+
 | 
			
		||||
+        default:
 | 
			
		||||
+            throw new Error.TYPE("Unsupported JS type: %s", value.to_string());
 | 
			
		||||
         }
 | 
			
		||||
-        throw new Error.TYPE("Unsupported JS type: %s", value.to_string());
 | 
			
		||||
+        return variant;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
diff --git a/test/client/util/util-js-test.vala b/test/client/util/util-js-test.vala
 | 
			
		||||
index 16a01d83..f1da043d 100644
 | 
			
		||||
--- a/test/client/util/util-js-test.vala
 | 
			
		||||
+++ b/test/client/util/util-js-test.vala
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
 /*
 | 
			
		||||
- * Copyright 2017 Michael Gratton <mike@vee.net>
 | 
			
		||||
+ * Copyright © 2017-2020 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.
 | 
			
		||||
@@ -61,15 +61,35 @@ public class Util.JS.Test : TestCase {
 | 
			
		||||
         var value = new JSC.Value.array_from_garray(this.context, null);
 | 
			
		||||
         assert_equal(
 | 
			
		||||
             value_to_variant(value).print(true),
 | 
			
		||||
-            "@av []"
 | 
			
		||||
+            "()"
 | 
			
		||||
         );
 | 
			
		||||
+
 | 
			
		||||
         var array = new GLib.GenericArray<JSC.Value>();
 | 
			
		||||
         array.add(new JSC.Value.string(this.context, "test"));
 | 
			
		||||
         value = new JSC.Value.array_from_garray(this.context, array);
 | 
			
		||||
         assert_equal(
 | 
			
		||||
             value_to_variant(value).print(true),
 | 
			
		||||
-            "[<'test'>]"
 | 
			
		||||
+            "['test']"
 | 
			
		||||
         );
 | 
			
		||||
+
 | 
			
		||||
+        array = new GLib.GenericArray<JSC.Value>();
 | 
			
		||||
+        array.add(new JSC.Value.string(this.context, "test1"));
 | 
			
		||||
+        array.add(new JSC.Value.string(this.context, "test2"));
 | 
			
		||||
+        value = new JSC.Value.array_from_garray(this.context, array);
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(value).print(true),
 | 
			
		||||
+            "['test1', 'test2']"
 | 
			
		||||
+        );
 | 
			
		||||
+
 | 
			
		||||
+        array = new GLib.GenericArray<JSC.Value>();
 | 
			
		||||
+        array.add(new JSC.Value.string(this.context, "test"));
 | 
			
		||||
+        array.add(new JSC.Value.boolean(this.context, true));
 | 
			
		||||
+        value = new JSC.Value.array_from_garray(this.context, array);
 | 
			
		||||
+        assert_equal(
 | 
			
		||||
+            value_to_variant(value).print(true),
 | 
			
		||||
+            "('test', true)"
 | 
			
		||||
+        );
 | 
			
		||||
+
 | 
			
		||||
         value = new JSC.Value.object(this.context, null, null);
 | 
			
		||||
         assert_equal(
 | 
			
		||||
             value_to_variant(value).print(true),
 | 
			
		||||
@@ -80,7 +100,7 @@ public class Util.JS.Test : TestCase {
 | 
			
		||||
         );
 | 
			
		||||
         assert_equal(
 | 
			
		||||
             value_to_variant(value).print(true),
 | 
			
		||||
-            "{'test': <<true>>}"
 | 
			
		||||
+            "{'test': <true>}"
 | 
			
		||||
         );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,234 @@
 | 
			
		||||
From fb96676fbd4ab7f413071f18cbf444cd7a953b77 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 11:25:28 +1000
 | 
			
		||||
Subject: [PATCH 075/124] =?UTF-8?q?Components.WebView:=20Convert=20to=20us?=
 | 
			
		||||
 =?UTF-8?q?ing=20messages=20for=20JS=20=E2=86=92=20client=20comms?=
 | 
			
		||||
MIME-Version: 1.0
 | 
			
		||||
Content-Type: text/plain; charset=UTF-8
 | 
			
		||||
Content-Transfer-Encoding: 8bit
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../components/components-web-view.vala       | 79 +++++++++----------
 | 
			
		||||
 ui/components-web-view.js                     | 25 +++---
 | 
			
		||||
 2 files changed, 53 insertions(+), 51 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/components-web-view.vala b/src/client/components/components-web-view.vala
 | 
			
		||||
index c746c441..a5cdfe33 100644
 | 
			
		||||
--- a/src/client/components/components-web-view.vala
 | 
			
		||||
+++ b/src/client/components/components-web-view.vala
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
 /*
 | 
			
		||||
- * Copyright 2016 Software Freedom Conservancy Inc.
 | 
			
		||||
- * Copyright 2016-2019 Michael Gratton <mike@vee.net>
 | 
			
		||||
+ * Copyright © 2016 Software Freedom Conservancy Inc.
 | 
			
		||||
+ * Copyright © 2016-2020 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.
 | 
			
		||||
@@ -31,12 +31,12 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     private const string MESSAGE_EXCEPTION_NAME = "__exception__";
 | 
			
		||||
 
 | 
			
		||||
     // WebKit message handler names
 | 
			
		||||
-    private const string COMMAND_STACK_CHANGED = "commandStackChanged";
 | 
			
		||||
-    private const string CONTENT_LOADED = "contentLoaded";
 | 
			
		||||
-    private const string DOCUMENT_MODIFIED = "documentModified";
 | 
			
		||||
-    private const string PREFERRED_HEIGHT_CHANGED = "preferredHeightChanged";
 | 
			
		||||
-    private const string REMOTE_IMAGE_LOAD_BLOCKED = "remoteImageLoadBlocked";
 | 
			
		||||
-    private const string SELECTION_CHANGED = "selectionChanged";
 | 
			
		||||
+    private const string COMMAND_STACK_CHANGED = "command_stack_changed";
 | 
			
		||||
+    private const string CONTENT_LOADED = "content_loaded";
 | 
			
		||||
+    private const string DOCUMENT_MODIFIED = "document_modified";
 | 
			
		||||
+    private const string PREFERRED_HEIGHT_CHANGED = "preferred_height_changed";
 | 
			
		||||
+    private const string REMOTE_IMAGE_LOAD_BLOCKED = "remote_image_load_blocked";
 | 
			
		||||
+    private const string SELECTION_CHANGED = "selection_changed";
 | 
			
		||||
 
 | 
			
		||||
     private const double ZOOM_DEFAULT = 1.0;
 | 
			
		||||
     private const double ZOOM_FACTOR = 0.1;
 | 
			
		||||
@@ -605,22 +605,22 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
                 warning("Web process crashed: %s", reason.to_string());
 | 
			
		||||
             });
 | 
			
		||||
 
 | 
			
		||||
-        register_message_handler(
 | 
			
		||||
+        register_message_callback(
 | 
			
		||||
             COMMAND_STACK_CHANGED, on_command_stack_changed
 | 
			
		||||
         );
 | 
			
		||||
-        register_message_handler(
 | 
			
		||||
+        register_message_callback(
 | 
			
		||||
             CONTENT_LOADED, on_content_loaded
 | 
			
		||||
         );
 | 
			
		||||
-        register_message_handler(
 | 
			
		||||
+        register_message_callback(
 | 
			
		||||
             DOCUMENT_MODIFIED, on_document_modified
 | 
			
		||||
         );
 | 
			
		||||
-        register_message_handler(
 | 
			
		||||
+        register_message_callback(
 | 
			
		||||
             PREFERRED_HEIGHT_CHANGED, on_preferred_height_changed
 | 
			
		||||
         );
 | 
			
		||||
-        register_message_handler(
 | 
			
		||||
+        register_message_callback(
 | 
			
		||||
             REMOTE_IMAGE_LOAD_BLOCKED, on_remote_image_load_blocked
 | 
			
		||||
         );
 | 
			
		||||
-        register_message_handler(
 | 
			
		||||
+        register_message_callback(
 | 
			
		||||
             SELECTION_CHANGED, on_selection_changed
 | 
			
		||||
         );
 | 
			
		||||
 
 | 
			
		||||
@@ -783,12 +783,12 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
         return false;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_preferred_height_changed(WebKit.JavascriptResult result) {
 | 
			
		||||
+    private void on_preferred_height_changed(GLib.Variant? parameters) {
 | 
			
		||||
         double height = this.webkit_reported_height;
 | 
			
		||||
-        try {
 | 
			
		||||
-            height = Util.JS.to_double(result.get_js_value());
 | 
			
		||||
-        } catch (Util.JS.Error err) {
 | 
			
		||||
-            debug("Could not get preferred height: %s", err.message);
 | 
			
		||||
+        if (parameters != null && parameters.classify() == DOUBLE) {
 | 
			
		||||
+            height = parameters.get_double();
 | 
			
		||||
+        } else {
 | 
			
		||||
+            warning("Could not get JS preferred height");
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         if (this.webkit_reported_height != height) {
 | 
			
		||||
@@ -797,40 +797,39 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_command_stack_changed(WebKit.JavascriptResult result) {
 | 
			
		||||
-        try {
 | 
			
		||||
-            string[] values =
 | 
			
		||||
-                Util.JS.to_string(result.get_js_value()).split(",");
 | 
			
		||||
-            command_stack_changed(values[0] == "true", values[1] == "true");
 | 
			
		||||
-        } catch (Util.JS.Error err) {
 | 
			
		||||
-            debug("Could not get command stack state: %s", err.message);
 | 
			
		||||
+    private void on_command_stack_changed(GLib.Variant? parameters) {
 | 
			
		||||
+        if (parameters != null &&
 | 
			
		||||
+            parameters.is_container() &&
 | 
			
		||||
+            parameters.n_children() == 2) {
 | 
			
		||||
+            GLib.Variant can_undo = parameters.get_child_value(0);
 | 
			
		||||
+            GLib.Variant can_redo = parameters.get_child_value(1);
 | 
			
		||||
+            command_stack_changed(
 | 
			
		||||
+                can_undo.classify() == BOOLEAN && can_undo.get_boolean(),
 | 
			
		||||
+                can_redo.classify() == BOOLEAN && can_redo.get_boolean()
 | 
			
		||||
+            );
 | 
			
		||||
+        } else {
 | 
			
		||||
+            warning("Could not get JS command stack state");
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_document_modified(WebKit.JavascriptResult result) {
 | 
			
		||||
+    private void on_document_modified(GLib.Variant? parameters) {
 | 
			
		||||
         document_modified();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_remote_image_load_blocked(WebKit.JavascriptResult result) {
 | 
			
		||||
+    private void on_remote_image_load_blocked(GLib.Variant? parameters) {
 | 
			
		||||
         remote_image_load_blocked();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_content_loaded(WebKit.JavascriptResult result) {
 | 
			
		||||
+    private void on_content_loaded(GLib.Variant? parameters) {
 | 
			
		||||
         this.is_content_loaded = true;
 | 
			
		||||
         content_loaded();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_selection_changed(WebKit.JavascriptResult result) {
 | 
			
		||||
-        try {
 | 
			
		||||
-            bool has_selection = Util.JS.to_bool(result.get_js_value());
 | 
			
		||||
-            // Avoid firing multiple notifies if the value hasn't
 | 
			
		||||
-            // changed
 | 
			
		||||
-            if (this.has_selection != has_selection) {
 | 
			
		||||
-                this.has_selection = has_selection;
 | 
			
		||||
-            }
 | 
			
		||||
-            selection_changed(has_selection);
 | 
			
		||||
-        } catch (Util.JS.Error err) {
 | 
			
		||||
-            debug("Could not get selection content: %s", err.message);
 | 
			
		||||
+    private void on_selection_changed(GLib.Variant? parameters) {
 | 
			
		||||
+        if (parameters != null && parameters.classify() == BOOLEAN) {
 | 
			
		||||
+            selection_changed(parameters.get_boolean());
 | 
			
		||||
+        } else {
 | 
			
		||||
+            warning("Could not get JS selection value");
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/ui/components-web-view.js b/ui/components-web-view.js
 | 
			
		||||
index 35e82dfc..29b6acd5 100644
 | 
			
		||||
--- a/ui/components-web-view.js
 | 
			
		||||
+++ b/ui/components-web-view.js
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
 /*
 | 
			
		||||
- * Copyright 2016 Michael Gratton <mike@vee.net>
 | 
			
		||||
+ * Copyright © 2016-2020 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.
 | 
			
		||||
@@ -20,6 +20,13 @@ PageState.prototype = {
 | 
			
		||||
         this.hasSelection = false;
 | 
			
		||||
         this.lastPreferredHeight = 0;
 | 
			
		||||
 
 | 
			
		||||
+        this._selectionChanged = MessageSender("selection_changed");
 | 
			
		||||
+        this._contentLoaded = MessageSender("content_loaded");
 | 
			
		||||
+        this._remoteImageLoadBlocked = MessageSender("remote_image_load_blocked");
 | 
			
		||||
+        this._preferredHeightChanged = MessageSender("preferred_height_changed");
 | 
			
		||||
+        this._commandStackChanged = MessageSender("command_stack_changed");
 | 
			
		||||
+        this._documentModified = MessageSender("document_modified");
 | 
			
		||||
+
 | 
			
		||||
         let state = this;
 | 
			
		||||
 
 | 
			
		||||
         // Set up an observer to keep track of modifications made to
 | 
			
		||||
@@ -106,7 +113,7 @@ PageState.prototype = {
 | 
			
		||||
         // be vaguegly correct when notifying of the HTML load
 | 
			
		||||
         // completing.
 | 
			
		||||
         this.updatePreferredHeight();
 | 
			
		||||
-        window.webkit.messageHandlers.contentLoaded.postMessage(null);
 | 
			
		||||
+        this._contentLoaded();
 | 
			
		||||
     },
 | 
			
		||||
     loadRemoteImages: function() {
 | 
			
		||||
         window._gearyAllowRemoteResourceLoads = true;
 | 
			
		||||
@@ -142,7 +149,7 @@ PageState.prototype = {
 | 
			
		||||
         this.bodyObserver.disconnect();
 | 
			
		||||
     },
 | 
			
		||||
     remoteImageLoadBlocked: function() {
 | 
			
		||||
-        window.webkit.messageHandlers.remoteImageLoadBlocked.postMessage(null);
 | 
			
		||||
+        this._remoteImageLoadBlocked();
 | 
			
		||||
     },
 | 
			
		||||
     /**
 | 
			
		||||
      * Sends "preferredHeightChanged" message if it has changed.
 | 
			
		||||
@@ -160,9 +167,7 @@ PageState.prototype = {
 | 
			
		||||
         // shrink again, leading to visual flicker.
 | 
			
		||||
         if (this.isLoaded && height > 0 && height != this.lastPreferredHeight) {
 | 
			
		||||
             this.lastPreferredHeight = height;
 | 
			
		||||
-            window.webkit.messageHandlers.preferredHeightChanged.postMessage(
 | 
			
		||||
-                height
 | 
			
		||||
-            );
 | 
			
		||||
+            this._preferredHeightChanged(height);
 | 
			
		||||
         }
 | 
			
		||||
     },
 | 
			
		||||
     checkCommandStack: function() {
 | 
			
		||||
@@ -172,19 +177,17 @@ PageState.prototype = {
 | 
			
		||||
         if (canUndo != this.undoEnabled || canRedo != this.redoEnabled) {
 | 
			
		||||
             this.undoEnabled = canUndo;
 | 
			
		||||
             this.redoEnabled = canRedo;
 | 
			
		||||
-            window.webkit.messageHandlers.commandStackChanged.postMessage(
 | 
			
		||||
-                this.undoEnabled + "," + this.redoEnabled
 | 
			
		||||
-            );
 | 
			
		||||
+            this._commandStackChanged(this.undoEnabled, this.redoEnabled);
 | 
			
		||||
         }
 | 
			
		||||
     },
 | 
			
		||||
     documentModified: function(element) {
 | 
			
		||||
-        window.webkit.messageHandlers.documentModified.postMessage(null);
 | 
			
		||||
+        this._documentModified();
 | 
			
		||||
     },
 | 
			
		||||
     selectionChanged: function() {
 | 
			
		||||
         let hasSelection = !window.getSelection().isCollapsed;
 | 
			
		||||
         if (this.hasSelection != hasSelection) {
 | 
			
		||||
             this.hasSelection = hasSelection;
 | 
			
		||||
-            window.webkit.messageHandlers.selectionChanged.postMessage(hasSelection);
 | 
			
		||||
+            this._selectionChanged(hasSelection);
 | 
			
		||||
         }
 | 
			
		||||
     },
 | 
			
		||||
     // Methods below are for unit tests.
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,185 @@
 | 
			
		||||
From 3655f4896f2b33f47a94c8e7dc4f9623ba42fc2e Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 11:38:06 +1000
 | 
			
		||||
Subject: [PATCH 076/124] =?UTF-8?q?Composer.WebView:=20Convert=20to=20usin?=
 | 
			
		||||
 =?UTF-8?q?g=20messages=20for=20JS=20=E2=86=92=20client=20comms?=
 | 
			
		||||
MIME-Version: 1.0
 | 
			
		||||
Content-Type: text/plain; charset=UTF-8
 | 
			
		||||
Content-Transfer-Encoding: 8bit
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/composer/composer-web-view.vala | 75 ++++++++++------------
 | 
			
		||||
 ui/composer-web-view.js                    | 18 ++++--
 | 
			
		||||
 2 files changed, 45 insertions(+), 48 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/composer/composer-web-view.vala b/src/client/composer/composer-web-view.vala
 | 
			
		||||
index 24a2740c..57b7e1e4 100644
 | 
			
		||||
--- a/src/client/composer/composer-web-view.vala
 | 
			
		||||
+++ b/src/client/composer/composer-web-view.vala
 | 
			
		||||
@@ -33,8 +33,8 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
     private const string SPACER = "<div><br /></div>";
 | 
			
		||||
 
 | 
			
		||||
     // WebKit message handler names
 | 
			
		||||
-    private const string CURSOR_CONTEXT_CHANGED = "cursorContextChanged";
 | 
			
		||||
-    private const string DRAG_DROP_RECEIVED = "dragDropReceived";
 | 
			
		||||
+    private const string CURSOR_CONTEXT_CHANGED = "cursor_context_changed";
 | 
			
		||||
+    private const string DRAG_DROP_RECEIVED = "drag_drop_received";
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      * Encapsulates editing-related state for a specific DOM node.
 | 
			
		||||
@@ -152,8 +152,8 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
         this.user_content_manager.add_style_sheet(WebView.app_style);
 | 
			
		||||
         this.user_content_manager.add_script(WebView.app_script);
 | 
			
		||||
 
 | 
			
		||||
-        register_message_handler(CURSOR_CONTEXT_CHANGED, on_cursor_context_changed);
 | 
			
		||||
-        register_message_handler(DRAG_DROP_RECEIVED, on_drag_drop_received);
 | 
			
		||||
+        register_message_callback(CURSOR_CONTEXT_CHANGED, on_cursor_context_changed);
 | 
			
		||||
+        register_message_callback(DRAG_DROP_RECEIVED, on_drag_drop_received);
 | 
			
		||||
 
 | 
			
		||||
         // XXX this is a bit of a hack given the docs for is_empty,
 | 
			
		||||
         // above
 | 
			
		||||
@@ -530,50 +530,43 @@ public class Composer.WebView : Components.WebView {
 | 
			
		||||
         return ret;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_cursor_context_changed(WebKit.JavascriptResult result) {
 | 
			
		||||
-        try {
 | 
			
		||||
-            cursor_context_changed(
 | 
			
		||||
-                new EditContext(Util.JS.to_string(result.get_js_value()))
 | 
			
		||||
-            );
 | 
			
		||||
-        } catch (Util.JS.Error err) {
 | 
			
		||||
-            debug("Could not get text cursor style: %s", err.message);
 | 
			
		||||
+    private void on_cursor_context_changed(GLib.Variant? parameters) {
 | 
			
		||||
+        if (parameters != null && parameters.classify() == STRING) {
 | 
			
		||||
+            cursor_context_changed(new EditContext(parameters as string));
 | 
			
		||||
+        } else {
 | 
			
		||||
+            warning("Could not get text cursor style");
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      *  Handle a dropped image
 | 
			
		||||
      */
 | 
			
		||||
-    private void on_drag_drop_received(WebKit.JavascriptResult result) {
 | 
			
		||||
-
 | 
			
		||||
-        try {
 | 
			
		||||
-            JSC.Value object = result.get_js_value();
 | 
			
		||||
-            string filename = Util.JS.to_string(
 | 
			
		||||
-                Util.JS.get_property(object, "fileName")
 | 
			
		||||
-            );
 | 
			
		||||
-            string filename_unescaped = GLib.Uri.unescape_string(filename);
 | 
			
		||||
-
 | 
			
		||||
-            string file_type = Util.JS.to_string(
 | 
			
		||||
-                Util.JS.get_property(object, "fileType")
 | 
			
		||||
-            );
 | 
			
		||||
-
 | 
			
		||||
-            string content_base64 = Util.JS.to_string(
 | 
			
		||||
-                Util.JS.get_property(object, "content")
 | 
			
		||||
-            );
 | 
			
		||||
-            uint8[] image = GLib.Base64.decode(content_base64);
 | 
			
		||||
-
 | 
			
		||||
-            if (image.length == 0) {
 | 
			
		||||
-                warning("%s is empty", filename);
 | 
			
		||||
-                return;
 | 
			
		||||
-            }
 | 
			
		||||
+    private void on_drag_drop_received(GLib.Variant? parameters) {
 | 
			
		||||
+        var dict = new GLib.VariantDict(parameters);
 | 
			
		||||
+        string file_name = dict.lookup_value(
 | 
			
		||||
+            "fileName", GLib.VariantType.STRING
 | 
			
		||||
+        ).get_string();
 | 
			
		||||
+        string file_name_unescaped = GLib.Uri.unescape_string(file_name);
 | 
			
		||||
+
 | 
			
		||||
+        string file_type = dict.lookup_value(
 | 
			
		||||
+            "fileType", GLib.VariantType.STRING
 | 
			
		||||
+        ).get_string();
 | 
			
		||||
+
 | 
			
		||||
+        string content_base64 = dict.lookup_value(
 | 
			
		||||
+            "content", GLib.VariantType.STRING
 | 
			
		||||
+        ).get_string();
 | 
			
		||||
+        uint8[] image = GLib.Base64.decode(content_base64);
 | 
			
		||||
+
 | 
			
		||||
+        if (image.length == 0) {
 | 
			
		||||
+            warning("%s is empty", file_name);
 | 
			
		||||
+            return;
 | 
			
		||||
+        }
 | 
			
		||||
 
 | 
			
		||||
-            // A simple check to see if the file looks like an image. A problem here
 | 
			
		||||
-            // will be this accepting types which won't be supported by WebKit
 | 
			
		||||
-            // or recipients.
 | 
			
		||||
-            if (file_type.index_of("image/") == 0) {
 | 
			
		||||
-                image_file_dropped(filename_unescaped, file_type, image);
 | 
			
		||||
-            }
 | 
			
		||||
-        } catch (Util.JS.Error err) {
 | 
			
		||||
-            debug("Could not get deceptive link param: %s", err.message);
 | 
			
		||||
+        // A simple check to see if the file looks like an image. A problem here
 | 
			
		||||
+        // will be this accepting types which won't be supported by WebKit
 | 
			
		||||
+        // or recipients.
 | 
			
		||||
+        if (file_type.index_of("image/") == 0) {
 | 
			
		||||
+            image_file_dropped(file_name_unescaped, file_type, image);
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/ui/composer-web-view.js b/ui/composer-web-view.js
 | 
			
		||||
index ca918990..4fe34ad0 100644
 | 
			
		||||
--- a/ui/composer-web-view.js
 | 
			
		||||
+++ b/ui/composer-web-view.js
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
 /*
 | 
			
		||||
- * Copyright 2016 Software Freedom Conservancy Inc.
 | 
			
		||||
- * Copyright 2016 Michael Gratton <mike@vee.net>
 | 
			
		||||
+ * Copyright © 2016 Software Freedom Conservancy Inc.
 | 
			
		||||
+ * Copyright © 2016-2020 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.
 | 
			
		||||
@@ -35,6 +35,9 @@ ComposerPageState.prototype = {
 | 
			
		||||
         this.nextSelectionId = 0;
 | 
			
		||||
         this.cursorContext = null;
 | 
			
		||||
 
 | 
			
		||||
+        this._cursorContextChanged = MessageSender("cursor_context_changed");
 | 
			
		||||
+        this._dragDropReceived = MessageSender("drag_drop_received");
 | 
			
		||||
+
 | 
			
		||||
         document.addEventListener("click", function(e) {
 | 
			
		||||
             if (e.target.tagName == "A") {
 | 
			
		||||
                 e.preventDefault();
 | 
			
		||||
@@ -99,7 +102,9 @@ ComposerPageState.prototype = {
 | 
			
		||||
         }, true);
 | 
			
		||||
 
 | 
			
		||||
         // Handle file drag & drop
 | 
			
		||||
-        document.body.addEventListener("drop", state.handleFileDrop, true);
 | 
			
		||||
+        document.body.addEventListener("drop", function(e) {
 | 
			
		||||
+            state.handleFileDrop(e);
 | 
			
		||||
+        }, true);
 | 
			
		||||
         document.body.addEventListener("allowDrop", function(e) {
 | 
			
		||||
             ev.preventDefault();
 | 
			
		||||
         }, true);
 | 
			
		||||
@@ -346,9 +351,7 @@ ComposerPageState.prototype = {
 | 
			
		||||
             let newContext = new EditContext(cursor);
 | 
			
		||||
             if (!newContext.equals(this.cursorContext)) {
 | 
			
		||||
                 this.cursorContext = newContext;
 | 
			
		||||
-                window.webkit.messageHandlers.cursorContextChanged.postMessage(
 | 
			
		||||
-                    newContext.encode()
 | 
			
		||||
-                );
 | 
			
		||||
+                this._cursorContextChanged(newContext.encode());
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
@@ -396,13 +399,14 @@ ComposerPageState.prototype = {
 | 
			
		||||
                 continue;
 | 
			
		||||
 
 | 
			
		||||
             const reader = new FileReader();
 | 
			
		||||
+            const state = this;
 | 
			
		||||
             reader.onload = (function(filename, imageType) { return function(loadEvent) {
 | 
			
		||||
                 // Remove prefixed file type and encoding type
 | 
			
		||||
                 var parts = loadEvent.target.result.split(",");
 | 
			
		||||
                 if (parts.length < 2)
 | 
			
		||||
                     return;
 | 
			
		||||
 
 | 
			
		||||
-                window.webkit.messageHandlers.dragDropReceived.postMessage({
 | 
			
		||||
+                state._dragDropReceived({
 | 
			
		||||
                     fileName: encodeURIComponent(filename),
 | 
			
		||||
                     fileType: imageType,
 | 
			
		||||
                     content: parts[1]
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,142 @@
 | 
			
		||||
From 7b0146274ccaad18115a66ded6753cb68bd22357 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 11:45:35 +1000
 | 
			
		||||
Subject: [PATCH 077/124] =?UTF-8?q?Conversation.WebView:=20Convert=20to=20?=
 | 
			
		||||
 =?UTF-8?q?using=20messages=20for=20JS=20=E2=86=92=20client=20comms?=
 | 
			
		||||
MIME-Version: 1.0
 | 
			
		||||
Content-Type: text/plain; charset=UTF-8
 | 
			
		||||
Content-Transfer-Encoding: 8bit
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../conversation-web-view.vala                | 71 +++++++++----------
 | 
			
		||||
 ui/conversation-web-view.js                   |  4 +-
 | 
			
		||||
 2 files changed, 38 insertions(+), 37 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-web-view.vala b/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
index d77af642..a1ba21a6 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-web-view.vala
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
 /*
 | 
			
		||||
- * Copyright 2016 Software Freedom Conservancy Inc.
 | 
			
		||||
- * Copyright 2017 Michael Gratton <mike@vee.net>
 | 
			
		||||
+ * Copyright © 2016 Software Freedom Conservancy Inc.
 | 
			
		||||
+ * Copyright © 2017-2020 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.
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
 public class ConversationWebView : Components.WebView {
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-    private const string DECEPTIVE_LINK_CLICKED = "deceptiveLinkClicked";
 | 
			
		||||
+    private const string DECEPTIVE_LINK_CLICKED = "deceptive_link_clicked";
 | 
			
		||||
 
 | 
			
		||||
     // Key codes we don't forward on to the super class on key press
 | 
			
		||||
     // since we want to override them elsewhere, especially
 | 
			
		||||
@@ -221,48 +221,47 @@ public class ConversationWebView : Components.WebView {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void init() {
 | 
			
		||||
-        register_message_handler(
 | 
			
		||||
+        register_message_callback(
 | 
			
		||||
             DECEPTIVE_LINK_CLICKED, on_deceptive_link_clicked
 | 
			
		||||
         );
 | 
			
		||||
 
 | 
			
		||||
         this.notify["preferred-height"].connect(() => queue_resize());
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void on_deceptive_link_clicked(WebKit.JavascriptResult result) {
 | 
			
		||||
-        try {
 | 
			
		||||
-            JSC.Value object = result.get_js_value();
 | 
			
		||||
-            uint reason = (uint) Util.JS.to_int32(
 | 
			
		||||
-                Util.JS.get_property(object, "reason")
 | 
			
		||||
-            );
 | 
			
		||||
-
 | 
			
		||||
-            string href = Util.JS.to_string(
 | 
			
		||||
-                Util.JS.get_property(object, "href")
 | 
			
		||||
-            );
 | 
			
		||||
+    private void on_deceptive_link_clicked(GLib.Variant? parameters) {
 | 
			
		||||
+        var dict = new GLib.VariantDict(parameters);
 | 
			
		||||
+        uint reason = (uint) dict.lookup_value(
 | 
			
		||||
+            "reason", GLib.VariantType.DOUBLE
 | 
			
		||||
+        ).get_double();
 | 
			
		||||
 
 | 
			
		||||
-            string text = Util.JS.to_string(
 | 
			
		||||
-                Util.JS.get_property(object, "text")
 | 
			
		||||
-            );
 | 
			
		||||
-
 | 
			
		||||
-            JSC.Value js_location = Util.JS.get_property(object, "location");
 | 
			
		||||
+        string href = dict.lookup_value(
 | 
			
		||||
+            "href", GLib.VariantType.STRING
 | 
			
		||||
+        ).get_string();
 | 
			
		||||
 
 | 
			
		||||
-            Gdk.Rectangle location = Gdk.Rectangle();
 | 
			
		||||
-            location.x = Util.JS.to_int32(
 | 
			
		||||
-                Util.JS.get_property(js_location, "x")
 | 
			
		||||
-            );
 | 
			
		||||
-            location.y = Util.JS.to_int32(
 | 
			
		||||
-                Util.JS.get_property(js_location, "y")
 | 
			
		||||
-            );
 | 
			
		||||
-            location.width = Util.JS.to_int32(
 | 
			
		||||
-                Util.JS.get_property(js_location, "width")
 | 
			
		||||
-            );
 | 
			
		||||
-            location.height = Util.JS.to_int32(
 | 
			
		||||
-                Util.JS.get_property(js_location, "height")
 | 
			
		||||
-            );
 | 
			
		||||
+        string text = dict.lookup_value(
 | 
			
		||||
+            "text", GLib.VariantType.STRING
 | 
			
		||||
+        ).get_string();
 | 
			
		||||
 
 | 
			
		||||
-            deceptive_link_clicked((DeceptiveText) reason, text, href, location);
 | 
			
		||||
-        } catch (Util.JS.Error err) {
 | 
			
		||||
-            debug("Could not get deceptive link param: %s", err.message);
 | 
			
		||||
-        }
 | 
			
		||||
+        Gdk.Rectangle location = Gdk.Rectangle();
 | 
			
		||||
+        var location_dict = new GLib.VariantDict(
 | 
			
		||||
+            dict.lookup_value("location", GLib.VariantType.VARDICT)
 | 
			
		||||
+        );
 | 
			
		||||
+        location.x = (int) location_dict.lookup_value(
 | 
			
		||||
+            "x", GLib.VariantType.DOUBLE
 | 
			
		||||
+        ).get_double();
 | 
			
		||||
+        location.y = (int) location_dict.lookup_value(
 | 
			
		||||
+            "y", GLib.VariantType.DOUBLE
 | 
			
		||||
+        ).get_double();
 | 
			
		||||
+        location.width = (int) location_dict.lookup_value(
 | 
			
		||||
+            "width", GLib.VariantType.DOUBLE
 | 
			
		||||
+        ).get_double();
 | 
			
		||||
+        location.height = (int) location_dict.lookup_value(
 | 
			
		||||
+            "height", GLib.VariantType.DOUBLE
 | 
			
		||||
+        ).get_double();
 | 
			
		||||
+
 | 
			
		||||
+        deceptive_link_clicked(
 | 
			
		||||
+            (DeceptiveText) reason, text, href, location
 | 
			
		||||
+        );
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/ui/conversation-web-view.js b/ui/conversation-web-view.js
 | 
			
		||||
index 451db288..1d730d47 100644
 | 
			
		||||
--- a/ui/conversation-web-view.js
 | 
			
		||||
+++ b/ui/conversation-web-view.js
 | 
			
		||||
@@ -26,6 +26,8 @@ ConversationPageState.prototype = {
 | 
			
		||||
     init: function() {
 | 
			
		||||
         PageState.prototype.init.apply(this, []);
 | 
			
		||||
 
 | 
			
		||||
+        this._deceptiveLinkClicked = MessageSender("deceptive_link_clicked");
 | 
			
		||||
+
 | 
			
		||||
         let state = this;
 | 
			
		||||
         document.addEventListener("click", function(e) {
 | 
			
		||||
             if (e.target.tagName == "A" &&
 | 
			
		||||
@@ -267,7 +269,7 @@ ConversationPageState.prototype = {
 | 
			
		||||
             let reason = ConversationPageState.isDeceptiveText(text, href);
 | 
			
		||||
             if (reason != ConversationPageState.NOT_DECEPTIVE) {
 | 
			
		||||
                 cancelClick = true;
 | 
			
		||||
-                window.webkit.messageHandlers.deceptiveLinkClicked.postMessage({
 | 
			
		||||
+                this._deceptiveLinkClicked({
 | 
			
		||||
                     reason: reason,
 | 
			
		||||
                     text: text,
 | 
			
		||||
                     href: href,
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,138 @@
 | 
			
		||||
From 7950ce50c6bdb6ca77561a00d1afb9bc689278cf Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 11:59:11 +1000
 | 
			
		||||
Subject: [PATCH 078/124] GearyWebExtension: Untangle extension and JS
 | 
			
		||||
 interaction a bit
 | 
			
		||||
 | 
			
		||||
Move selection changed event listener into JS so it doesn't have to
 | 
			
		||||
cross the JS/native boundary twice.
 | 
			
		||||
 | 
			
		||||
Move sending remote load blocked from JS to the extension since we can
 | 
			
		||||
do that directly now and again so the JS/native boundary doesn't need
 | 
			
		||||
to be double-crossed again.
 | 
			
		||||
---
 | 
			
		||||
 .../web-process/web-process-extension.vala    | 60 ++-----------------
 | 
			
		||||
 ui/components-web-view.js                     |  8 +--
 | 
			
		||||
 2 files changed, 8 insertions(+), 60 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/web-process/web-process-extension.vala b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
index 31f2b0f0..6eed7746 100644
 | 
			
		||||
--- a/src/client/web-process/web-process-extension.vala
 | 
			
		||||
+++ b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
@@ -77,7 +77,10 @@ public class GearyWebExtension : Object {
 | 
			
		||||
             if (should_load_remote_images(page)) {
 | 
			
		||||
                 should_load = true;
 | 
			
		||||
             } else {
 | 
			
		||||
-                remote_image_load_blocked(page);
 | 
			
		||||
+                page.send_message_to_view.begin(
 | 
			
		||||
+                    new WebKit.UserMessage("remote_image_load_blocked", null),
 | 
			
		||||
+                    null
 | 
			
		||||
+                );
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
@@ -99,54 +102,6 @@ public class GearyWebExtension : Object {
 | 
			
		||||
         return should_load;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void remote_image_load_blocked(WebKit.WebPage page) {
 | 
			
		||||
-        WebKit.Frame frame = page.get_main_frame();
 | 
			
		||||
-        JSC.Context context = frame.get_js_context();
 | 
			
		||||
-        try {
 | 
			
		||||
-            execute_script(
 | 
			
		||||
-                context,
 | 
			
		||||
-                "geary.remoteImageLoadBlocked();",
 | 
			
		||||
-                GLib.Log.FILE,
 | 
			
		||||
-                GLib.Log.METHOD,
 | 
			
		||||
-                GLib.Log.LINE
 | 
			
		||||
-            );
 | 
			
		||||
-        } catch (Error err) {
 | 
			
		||||
-            debug(
 | 
			
		||||
-                "Error calling PageState::remoteImageLoadBlocked: %s",
 | 
			
		||||
-                err.message
 | 
			
		||||
-            );
 | 
			
		||||
-        }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    private void selection_changed(WebKit.WebPage page) {
 | 
			
		||||
-        WebKit.Frame frame = page.get_main_frame();
 | 
			
		||||
-        JSC.Context context = frame.get_js_context();
 | 
			
		||||
-        try {
 | 
			
		||||
-            execute_script(
 | 
			
		||||
-                context,
 | 
			
		||||
-                "geary.selectionChanged();",
 | 
			
		||||
-                GLib.Log.FILE,
 | 
			
		||||
-                GLib.Log.METHOD,
 | 
			
		||||
-                GLib.Log.LINE
 | 
			
		||||
-            );
 | 
			
		||||
-        } catch (Error err) {
 | 
			
		||||
-            debug("Error calling PageStates::selectionChanged: %s", err.message);
 | 
			
		||||
-        }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
-    private JSC.Value execute_script(JSC.Context context,
 | 
			
		||||
-                                     string script,
 | 
			
		||||
-                                     string file_name,
 | 
			
		||||
-                                     string method_name,
 | 
			
		||||
-                                     int line_number)
 | 
			
		||||
-        throws Util.JS.Error {
 | 
			
		||||
-        JSC.Value ret = context.evaluate_with_source_uri(
 | 
			
		||||
-            script, -1, "geary:%s/%s".printf(file_name, method_name), line_number
 | 
			
		||||
-        );
 | 
			
		||||
-        Util.JS.check_exception(context);
 | 
			
		||||
-        return ret;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     private WebKit.UserMessage to_exception_message(string? name,
 | 
			
		||||
                                                     string? message,
 | 
			
		||||
                                                     string? backtrace = null,
 | 
			
		||||
@@ -208,13 +163,6 @@ public class GearyWebExtension : Object {
 | 
			
		||||
 
 | 
			
		||||
         page.console_message_sent.connect(on_console_message);
 | 
			
		||||
         page.send_request.connect(on_send_request);
 | 
			
		||||
-        // XXX investigate whether the earliest supported
 | 
			
		||||
-        // version of WK supports the DOM "selectionchanged"
 | 
			
		||||
-        // event, and if so use that rather that doing it in
 | 
			
		||||
-        // here in the extension
 | 
			
		||||
-        page.get_editor().selection_changed.connect(() => {
 | 
			
		||||
-                selection_changed(page);
 | 
			
		||||
-            });
 | 
			
		||||
         page.user_message_received.connect(on_page_message_received);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/ui/components-web-view.js b/ui/components-web-view.js
 | 
			
		||||
index 29b6acd5..d0998a67 100644
 | 
			
		||||
--- a/ui/components-web-view.js
 | 
			
		||||
+++ b/ui/components-web-view.js
 | 
			
		||||
@@ -22,7 +22,6 @@ PageState.prototype = {
 | 
			
		||||
 
 | 
			
		||||
         this._selectionChanged = MessageSender("selection_changed");
 | 
			
		||||
         this._contentLoaded = MessageSender("content_loaded");
 | 
			
		||||
-        this._remoteImageLoadBlocked = MessageSender("remote_image_load_blocked");
 | 
			
		||||
         this._preferredHeightChanged = MessageSender("preferred_height_changed");
 | 
			
		||||
         this._commandStackChanged = MessageSender("command_stack_changed");
 | 
			
		||||
         this._documentModified = MessageSender("document_modified");
 | 
			
		||||
@@ -46,6 +45,10 @@ PageState.prototype = {
 | 
			
		||||
             state.loaded();
 | 
			
		||||
         });
 | 
			
		||||
 
 | 
			
		||||
+        document.addEventListener("selectionchange", function(e) {
 | 
			
		||||
+            state.selectionChanged();
 | 
			
		||||
+        });
 | 
			
		||||
+
 | 
			
		||||
         // Coalesce multiple calls to updatePreferredHeight using a
 | 
			
		||||
         // timeout to avoid the overhead of multiple JS messages sent
 | 
			
		||||
         // to the app and hence view multiple resizes being queued.
 | 
			
		||||
@@ -148,9 +151,6 @@ PageState.prototype = {
 | 
			
		||||
     stopBodyObserver: function() {
 | 
			
		||||
         this.bodyObserver.disconnect();
 | 
			
		||||
     },
 | 
			
		||||
-    remoteImageLoadBlocked: function() {
 | 
			
		||||
-        this._remoteImageLoadBlocked();
 | 
			
		||||
-    },
 | 
			
		||||
     /**
 | 
			
		||||
      * Sends "preferredHeightChanged" message if it has changed.
 | 
			
		||||
      */
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
From eba82a1fbda18c2e567bd143862e7d687982b973 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 12:01:22 +1000
 | 
			
		||||
Subject: [PATCH 079/124] GearyWebExtension: Trivial code clean up
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/web-process/web-process-extension.vala | 7 +++----
 | 
			
		||||
 1 file changed, 3 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/web-process/web-process-extension.vala b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
index 6eed7746..6785903e 100644
 | 
			
		||||
--- a/src/client/web-process/web-process-extension.vala
 | 
			
		||||
+++ b/src/client/web-process/web-process-extension.vala
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
 /*
 | 
			
		||||
- * Copyright 2016 Michael Gratton <mike@vee.net>
 | 
			
		||||
+ * Copyright © 2016-2020 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.
 | 
			
		||||
@@ -13,9 +13,9 @@ public void webkit_web_extension_initialize_with_user_data(WebKit.WebExtension e
 | 
			
		||||
     bool logging_enabled = data.get_boolean();
 | 
			
		||||
 
 | 
			
		||||
     Geary.Logging.init();
 | 
			
		||||
-    GLib.Log.set_writer_func(Geary.Logging.default_log_writer);
 | 
			
		||||
     if (logging_enabled) {
 | 
			
		||||
-        Geary.Logging.log_to(stdout);
 | 
			
		||||
+        GLib.Log.set_writer_func(Geary.Logging.default_log_writer);
 | 
			
		||||
+        Geary.Logging.log_to(GLib.stdout);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     debug("Initialising...");
 | 
			
		||||
@@ -50,7 +50,6 @@ public class GearyWebExtension : Object {
 | 
			
		||||
         extension.page_created.connect(on_page_created);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    // XXX Conditionally enable while we still depend on WK2 <2.12
 | 
			
		||||
     private void on_console_message(WebKit.WebPage page,
 | 
			
		||||
                                     WebKit.ConsoleMessage message) {
 | 
			
		||||
         string source = message.get_source_id();
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
From 47b134a04eeb502fadb80e6ae2340178645396bd Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 12:05:23 +1000
 | 
			
		||||
Subject: [PATCH 080/124] Components.WebView: Remove now-unused message handler
 | 
			
		||||
 infrastructure
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 .../components/components-web-view.vala       | 30 +------------------
 | 
			
		||||
 1 file changed, 1 insertion(+), 29 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/components/components-web-view.vala b/src/client/components/components-web-view.vala
 | 
			
		||||
index a5cdfe33..904c5358 100644
 | 
			
		||||
--- a/src/client/components/components-web-view.vala
 | 
			
		||||
+++ b/src/client/components/components-web-view.vala
 | 
			
		||||
@@ -195,9 +195,6 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-    /** Delegate for UserContentManager message callbacks. */
 | 
			
		||||
-    public delegate void JavaScriptMessageHandler(WebKit.JavascriptResult js_result);
 | 
			
		||||
-
 | 
			
		||||
     /**
 | 
			
		||||
      * Delegate for message handler callbacks.
 | 
			
		||||
      *
 | 
			
		||||
@@ -279,8 +276,6 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     private Gee.Map<string,Geary.Memory.Buffer> internal_resources =
 | 
			
		||||
         new Gee.HashMap<string,Geary.Memory.Buffer>();
 | 
			
		||||
 
 | 
			
		||||
-    private Gee.List<ulong> registered_message_handlers =
 | 
			
		||||
-        new Gee.LinkedList<ulong>();
 | 
			
		||||
     private Gee.Map<string,MessageCallable> message_handlers =
 | 
			
		||||
         new Gee.HashMap<string,MessageCallable>();
 | 
			
		||||
 
 | 
			
		||||
@@ -357,7 +352,7 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
      * The new view will use the same WebProcess, settings and content
 | 
			
		||||
      * manager as the given related view's.
 | 
			
		||||
      *
 | 
			
		||||
-     * @see WebKit.WebView.with_related_view
 | 
			
		||||
+     * @see WebKit.WebView.WebView.with_related_view
 | 
			
		||||
      */
 | 
			
		||||
     protected WebView.with_related_view(Application.Configuration config,
 | 
			
		||||
                                         WebView related) {
 | 
			
		||||
@@ -375,10 +370,6 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public override void destroy() {
 | 
			
		||||
-        foreach (ulong id in this.registered_message_handlers) {
 | 
			
		||||
-            this.user_content_manager.disconnect(id);
 | 
			
		||||
-        }
 | 
			
		||||
-        this.registered_message_handlers.clear();
 | 
			
		||||
         this.message_handlers.clear();
 | 
			
		||||
         base.destroy();
 | 
			
		||||
     }
 | 
			
		||||
@@ -570,25 +561,6 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 | 
			
		||||
         return ret_value;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    /**
 | 
			
		||||
-     * Convenience function for registering and connecting JS messages.
 | 
			
		||||
-     */
 | 
			
		||||
-    protected inline void register_message_handler(string name,
 | 
			
		||||
-                                                   JavaScriptMessageHandler handler) {
 | 
			
		||||
-        // XXX can't use the delegate directly, see b.g.o Bug
 | 
			
		||||
-        // 604781. However the workaround below creates a circular
 | 
			
		||||
-        // reference, causing WebView instances to leak. So to
 | 
			
		||||
-        // work around that we need to record handler ids and
 | 
			
		||||
-        // disconnect them when being destroyed.
 | 
			
		||||
-        ulong id = this.user_content_manager.script_message_received[name].connect(
 | 
			
		||||
-            (result) => { handler(result); }
 | 
			
		||||
-        );
 | 
			
		||||
-        this.registered_message_handlers.add(id);
 | 
			
		||||
-        if (!this.user_content_manager.register_script_message_handler(name)) {
 | 
			
		||||
-            debug("Failed to register script message handler: %s", name);
 | 
			
		||||
-        }
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     /**
 | 
			
		||||
      * Registers a callback for a specific WebKit user message.
 | 
			
		||||
      */
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
From 92e842bf083d3185e6ee94b09eab710fb2374fac Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 12:06:07 +1000
 | 
			
		||||
Subject: [PATCH 081/124] ConversationViewer.ConversationMessage: Fix valadoc
 | 
			
		||||
 warning
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/conversation-viewer/conversation-message.vala | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/conversation-viewer/conversation-message.vala b/src/client/conversation-viewer/conversation-message.vala
 | 
			
		||||
index a11ece01..109c4a1c 100644
 | 
			
		||||
--- a/src/client/conversation-viewer/conversation-message.vala
 | 
			
		||||
+++ b/src/client/conversation-viewer/conversation-message.vala
 | 
			
		||||
@@ -666,7 +666,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
 | 
			
		||||
     /**
 | 
			
		||||
      * Adds a set of internal resources to web_view.
 | 
			
		||||
      *
 | 
			
		||||
-     * @see add_internal_resource
 | 
			
		||||
+     * @see Components.WebView.add_internal_resources
 | 
			
		||||
      */
 | 
			
		||||
     public void add_internal_resources(Gee.Map<string,Geary.Memory.Buffer> res) {
 | 
			
		||||
         if (this.web_view == null)
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,103 @@
 | 
			
		||||
From 0609fbc3d7cec05a4e5fbf4c5ca9377ea802344b Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 12:06:36 +1000
 | 
			
		||||
Subject: [PATCH 082/124] Util.JS: Remove now-unused code
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/client/util/util-js.vala       | 50 ------------------------------
 | 
			
		||||
 test/client/util/util-js-test.vala | 11 -------
 | 
			
		||||
 2 files changed, 61 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/client/util/util-js.vala b/src/client/util/util-js.vala
 | 
			
		||||
index 095f9da4..193b3c7a 100644
 | 
			
		||||
--- a/src/client/util/util-js.vala
 | 
			
		||||
+++ b/src/client/util/util-js.vala
 | 
			
		||||
@@ -364,56 +364,6 @@ namespace Util.JS {
 | 
			
		||||
         return value;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    /**
 | 
			
		||||
-     * Escapes a string so as to be safe to use as a JS string literal.
 | 
			
		||||
-     *
 | 
			
		||||
-     * This does not append opening or closing quotes.
 | 
			
		||||
-     */
 | 
			
		||||
-    public string escape_string(string value) {
 | 
			
		||||
-        StringBuilder builder = new StringBuilder.sized(value.length);
 | 
			
		||||
-        for (int i = 0; i < value.length; i++) {
 | 
			
		||||
-            if (value.valid_char(i)) {
 | 
			
		||||
-                unichar c = value.get_char(i);
 | 
			
		||||
-                switch (c) {
 | 
			
		||||
-                case '\x00':
 | 
			
		||||
-                    builder.append("\x00");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\'':
 | 
			
		||||
-                    builder.append("\\\'");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '"':
 | 
			
		||||
-                    builder.append("\\\"");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\\':
 | 
			
		||||
-                    builder.append("\\\\");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\n':
 | 
			
		||||
-                    builder.append("\\n");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\r':
 | 
			
		||||
-                    builder.append("\\r");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\x0b':
 | 
			
		||||
-                    builder.append("\x0b");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\t':
 | 
			
		||||
-                    builder.append("\\t");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\b':
 | 
			
		||||
-                    builder.append("\\b");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                case '\f':
 | 
			
		||||
-                    builder.append("\\f");
 | 
			
		||||
-                    break;
 | 
			
		||||
-                default:
 | 
			
		||||
-                    builder.append_unichar(c);
 | 
			
		||||
-                    break;
 | 
			
		||||
-                }
 | 
			
		||||
-            }
 | 
			
		||||
-        }
 | 
			
		||||
-        return (string) builder.data;
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     /**
 | 
			
		||||
      * Convenience method for returning a new Callable instance.
 | 
			
		||||
      */
 | 
			
		||||
diff --git a/test/client/util/util-js-test.vala b/test/client/util/util-js-test.vala
 | 
			
		||||
index f1da043d..9fea3cd7 100644
 | 
			
		||||
--- a/test/client/util/util-js-test.vala
 | 
			
		||||
+++ b/test/client/util/util-js-test.vala
 | 
			
		||||
@@ -13,7 +13,6 @@ public class Util.JS.Test : TestCase {
 | 
			
		||||
 
 | 
			
		||||
     public Test() {
 | 
			
		||||
         base("Util.JS.Test");
 | 
			
		||||
-        add_test("escape_string", escape_string);
 | 
			
		||||
         add_test("to_variant", to_variant);
 | 
			
		||||
         add_test("to_value", to_value);
 | 
			
		||||
     }
 | 
			
		||||
@@ -26,16 +25,6 @@ public class Util.JS.Test : TestCase {
 | 
			
		||||
         this.context = null;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public void escape_string() throws GLib.Error {
 | 
			
		||||
-        assert(Util.JS.escape_string("\n") == """\n""");
 | 
			
		||||
-        assert(Util.JS.escape_string("\r") == """\r""");
 | 
			
		||||
-        assert(Util.JS.escape_string("\t") == """\t""");
 | 
			
		||||
-        assert(Util.JS.escape_string("\'") == """\'""");
 | 
			
		||||
-        assert(Util.JS.escape_string("\"") == """\"""");
 | 
			
		||||
-
 | 
			
		||||
-        assert(Util.JS.escape_string("something…\n") == """something…\n""");
 | 
			
		||||
-    }
 | 
			
		||||
-
 | 
			
		||||
     public void to_variant() throws GLib.Error {
 | 
			
		||||
         assert_equal(
 | 
			
		||||
             value_to_variant(new JSC.Value.null(this.context)).print(true),
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,130 @@
 | 
			
		||||
From 1d80ed2034512aca7e355921c0b942d4cf651b94 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Fri, 28 Aug 2020 12:07:59 +1000
 | 
			
		||||
Subject: [PATCH 083/124] ComposerPageState: Use CSS for managing focus with
 | 
			
		||||
 composer body parts
 | 
			
		||||
 | 
			
		||||
Now that the `:focus-within` pseudoclass is supported, use this rather
 | 
			
		||||
than some custom JS to update custom HTML classes. This also prevents
 | 
			
		||||
spurious mutation events from firing.
 | 
			
		||||
---
 | 
			
		||||
 test/js/composer-page-state-test.vala | 24 ++++++++----------------
 | 
			
		||||
 ui/composer-web-view.css              |  6 +++---
 | 
			
		||||
 ui/composer-web-view.js               | 25 -------------------------
 | 
			
		||||
 3 files changed, 11 insertions(+), 44 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/test/js/composer-page-state-test.vala b/test/js/composer-page-state-test.vala
 | 
			
		||||
index 1a2e2df3..5a0a8b3c 100644
 | 
			
		||||
--- a/test/js/composer-page-state-test.vala
 | 
			
		||||
+++ b/test/js/composer-page-state-test.vala
 | 
			
		||||
@@ -11,7 +11,7 @@ class Composer.PageStateTest : Components.WebViewTestCase<Composer.WebView> {
 | 
			
		||||
         """<div id="geary-body" dir="auto">%s<div><br></div><div><br></div></div><div id="geary-signature" dir="auto"></div>""";
 | 
			
		||||
     public const string DIRTY_BODY_TEMPLATE =
 | 
			
		||||
         """
 | 
			
		||||
-<div id="geary-body" dir="auto" class="geary-focus" contenteditable="true">%s<div><br></div><div><br></div></div>
 | 
			
		||||
+<div id="geary-body" dir="auto" contenteditable="true">%s<div><br></div><div><br></div></div>
 | 
			
		||||
 <div id="geary-signature" class="geary-no-display" dir="auto" contenteditable="true"></div>
 | 
			
		||||
 """;
 | 
			
		||||
     public const string CLEAN_BODY_TEMPLATE = """<div id="geary-body" dir="auto">%s<div><br></div><div><br></div></div>""";
 | 
			
		||||
@@ -227,7 +227,7 @@ some text
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public void clean_content() throws Error {
 | 
			
		||||
+    public void clean_content() throws GLib.Error {
 | 
			
		||||
         // XXX split these up into multiple tests
 | 
			
		||||
         load_body_fixture("""
 | 
			
		||||
 http://example1.com
 | 
			
		||||
@@ -257,20 +257,12 @@ unknown://example6.com
 | 
			
		||||
 I can send email through smtp.gmail.com:587 or through <a href="https://www.gmail.com/">https://www.gmail.com/</a>
 | 
			
		||||
 """;
 | 
			
		||||
 
 | 
			
		||||
-        try {
 | 
			
		||||
-            run_javascript("geary.cleanContent();");
 | 
			
		||||
-            string result = Util.JS.to_string(
 | 
			
		||||
-                run_javascript("window.document.body.innerHTML;")
 | 
			
		||||
-                .get_js_value()
 | 
			
		||||
-            );
 | 
			
		||||
-            assert(result == DIRTY_BODY_TEMPLATE.printf(expected));
 | 
			
		||||
-        } catch (Util.JS.Error err) {
 | 
			
		||||
-            print("Util.JS.Error: %s\n", err.message);
 | 
			
		||||
-            assert_not_reached();
 | 
			
		||||
-        } catch (Error err) {
 | 
			
		||||
-            print("WKError: %s\n", err.message);
 | 
			
		||||
-            assert_not_reached();
 | 
			
		||||
-        }
 | 
			
		||||
+        run_javascript("geary.cleanContent();");
 | 
			
		||||
+        string result = Util.JS.to_string(
 | 
			
		||||
+            run_javascript("window.document.body.innerHTML;")
 | 
			
		||||
+            .get_js_value()
 | 
			
		||||
+        );
 | 
			
		||||
+        assert_equal(result, DIRTY_BODY_TEMPLATE.printf(expected));
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void get_html() throws Error {
 | 
			
		||||
diff --git a/ui/composer-web-view.css b/ui/composer-web-view.css
 | 
			
		||||
index 3cecfb3b..07ae6869 100644
 | 
			
		||||
--- a/ui/composer-web-view.css
 | 
			
		||||
+++ b/ui/composer-web-view.css
 | 
			
		||||
@@ -43,12 +43,12 @@ body > div#geary-quote {
 | 
			
		||||
   padding: 6px !important;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-body > div.geary-focus {
 | 
			
		||||
+body > div:focus-within {
 | 
			
		||||
   background-color: white;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-body > div#geary-signature.geary-focus,
 | 
			
		||||
-body > div#geary-quote.geary-focus {
 | 
			
		||||
+body > div#geary-signature:focus-within,
 | 
			
		||||
+body > div#geary-quote:focus-within {
 | 
			
		||||
   outline: 1px dashed #ccc !important;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/ui/composer-web-view.js b/ui/composer-web-view.js
 | 
			
		||||
index 4fe34ad0..5ee4105e 100644
 | 
			
		||||
--- a/ui/composer-web-view.js
 | 
			
		||||
+++ b/ui/composer-web-view.js
 | 
			
		||||
@@ -123,7 +123,6 @@ ComposerPageState.prototype = {
 | 
			
		||||
 
 | 
			
		||||
         // Focus within the HTML document
 | 
			
		||||
         document.body.focus();
 | 
			
		||||
-        this.updateFocusClass(this.bodyPart);
 | 
			
		||||
 
 | 
			
		||||
         // Set text cursor at appropriate position
 | 
			
		||||
         let cursor = document.getElementById("cursormarker");
 | 
			
		||||
@@ -354,30 +353,6 @@ ComposerPageState.prototype = {
 | 
			
		||||
                 this._cursorContextChanged(newContext.encode());
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
-
 | 
			
		||||
-        while (cursor != null) {
 | 
			
		||||
-            let parent = cursor.parentNode;
 | 
			
		||||
-            if (parent == document.body) {
 | 
			
		||||
-                this.updateFocusClass(cursor);
 | 
			
		||||
-                break;
 | 
			
		||||
-            }
 | 
			
		||||
-            cursor = parent;
 | 
			
		||||
-        }
 | 
			
		||||
-    },
 | 
			
		||||
-    /**
 | 
			
		||||
-     * Work around WebKit note yet supporting :focus-inside pseudoclass.
 | 
			
		||||
-     */
 | 
			
		||||
-    updateFocusClass: function(newFocus) {
 | 
			
		||||
-        if (this.focusedPart != null) {
 | 
			
		||||
-            this.focusedPart.classList.remove("geary-focus");
 | 
			
		||||
-            this.focusedPart = null;
 | 
			
		||||
-        }
 | 
			
		||||
-        if (newFocus == this.bodyPart ||
 | 
			
		||||
-            newFocus == this.signaturePart ||
 | 
			
		||||
-            newFocus == this.quotePart) {
 | 
			
		||||
-            this.focusedPart = newFocus;
 | 
			
		||||
-            this.focusedPart.classList.add("geary-focus");
 | 
			
		||||
-        }
 | 
			
		||||
     },
 | 
			
		||||
     containedInPart: function(target) {
 | 
			
		||||
         let inPart = false;
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
From 3f7c054db085a846b550c2cbc9fb71b352add2b9 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Sat, 29 Aug 2020 12:57:08 +1000
 | 
			
		||||
Subject: [PATCH 084/124] build: Bump WebKitGTK min version to include
 | 
			
		||||
 UserMessage support
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 meson.build | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/meson.build b/meson.build
 | 
			
		||||
index 240eacaa..9b55b24d 100644
 | 
			
		||||
--- a/meson.build
 | 
			
		||||
+++ b/meson.build
 | 
			
		||||
@@ -53,7 +53,7 @@ valac = meson.get_compiler('vala')
 | 
			
		||||
 target_vala = '0.48.6'
 | 
			
		||||
 target_glib = '2.64'
 | 
			
		||||
 target_gtk = '3.24.7'
 | 
			
		||||
-target_webkit = '2.26'
 | 
			
		||||
+target_webkit = '2.28'
 | 
			
		||||
 
 | 
			
		||||
 if not valac.version().version_compare('>=' + target_vala)
 | 
			
		||||
   error('Vala does not meet minimum required version: ' + target_vala)
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1546
									
								
								mail-client/geary/files/0085-Update-Ukrainian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1546
									
								
								mail-client/geary/files/0085-Update-Ukrainian-translation.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
From 4db6d01e2356a5c9542ee394ecfaea5aaf6ccab8 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Michael Gratton <mike@vee.net>
 | 
			
		||||
Date: Tue, 13 Oct 2020 18:49:57 +1100
 | 
			
		||||
Subject: [PATCH 086/124] client: Remove perf relnote, it's not really that
 | 
			
		||||
 noteworthy
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 desktop/org.gnome.Geary.appdata.xml.in.in | 8 --------
 | 
			
		||||
 1 file changed, 8 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/desktop/org.gnome.Geary.appdata.xml.in.in b/desktop/org.gnome.Geary.appdata.xml.in.in
 | 
			
		||||
index 471b69c4..7c1ddcab 100644
 | 
			
		||||
--- a/desktop/org.gnome.Geary.appdata.xml.in.in
 | 
			
		||||
+++ b/desktop/org.gnome.Geary.appdata.xml.in.in
 | 
			
		||||
@@ -88,14 +88,6 @@
 | 
			
		||||
   <translation type="gettext">geary</translation>
 | 
			
		||||
 
 | 
			
		||||
   <releases>
 | 
			
		||||
-    <release version="3.40" date="">
 | 
			
		||||
-      <description>
 | 
			
		||||
-        <p>Enhancements included in this release:</p>
 | 
			
		||||
-        <ul>
 | 
			
		||||
-          <li>Conversation loading performance improvements</li>
 | 
			
		||||
-        </ul>
 | 
			
		||||
-      </description>
 | 
			
		||||
-    </release>
 | 
			
		||||
     <release version="3.38" date="2020-09-13">
 | 
			
		||||
       <description>
 | 
			
		||||
         <p>Enhancements included in this release:</p>
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										973
									
								
								mail-client/geary/files/0087-Update-Turkish-translation.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										973
									
								
								mail-client/geary/files/0087-Update-Turkish-translation.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,973 @@
 | 
			
		||||
From 1f623bf100b78667e94a75d02a2a4a43512b827c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Emin=20Tufan=20=C3=87etin?= <etcetin@gmail.com>
 | 
			
		||||
Date: Tue, 13 Oct 2020 13:48:40 +0000
 | 
			
		||||
Subject: [PATCH 087/124] Update Turkish translation
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 po/tr.po | 409 +++++++++++++++++++++++++++----------------------------
 | 
			
		||||
 1 file changed, 201 insertions(+), 208 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/po/tr.po b/po/tr.po
 | 
			
		||||
index f96666c5..51f95638 100644
 | 
			
		||||
--- a/po/tr.po
 | 
			
		||||
+++ b/po/tr.po
 | 
			
		||||
@@ -16,8 +16,8 @@ msgid ""
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Project-Id-Version: geary.mainline\n"
 | 
			
		||||
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/geary/issues\n"
 | 
			
		||||
-"POT-Creation-Date: 2020-08-30 09:31+0000\n"
 | 
			
		||||
-"PO-Revision-Date: 2020-08-30 12:32+0300\n"
 | 
			
		||||
+"POT-Creation-Date: 2020-10-12 10:41+0000\n"
 | 
			
		||||
+"PO-Revision-Date: 2020-10-13 16:47+0300\n"
 | 
			
		||||
 "Last-Translator: Emin Tufan Çetin <etcetin@gmail.com>\n"
 | 
			
		||||
 "Language-Team: Turkish <gnome-turk@gnome.org>\n"
 | 
			
		||||
 "Language: tr\n"
 | 
			
		||||
@@ -25,7 +25,7 @@ msgstr ""
 | 
			
		||||
 "Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
 "Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
 "Plural-Forms: nplurals=1; plural=0;\n"
 | 
			
		||||
-"X-Generator: Poedit 2.4\n"
 | 
			
		||||
+"X-Generator: Poedit 2.4.1\n"
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/geary-attach.contract.desktop.in:3
 | 
			
		||||
 msgid "Send by email"
 | 
			
		||||
@@ -40,7 +40,7 @@ msgstr "Dosyaları Geary kullanarak gönderin"
 | 
			
		||||
 #: desktop/org.gnome.Geary.appdata.xml.in.in:11
 | 
			
		||||
 #: desktop/org.gnome.Geary.desktop.in.in:3
 | 
			
		||||
 #: src/client/accounts/accounts-editor-servers-pane.vala:560
 | 
			
		||||
-#: src/client/application/application-main-window.vala:608
 | 
			
		||||
+#: src/client/application/application-main-window.vala:628
 | 
			
		||||
 msgid "Geary"
 | 
			
		||||
 msgstr "Geary"
 | 
			
		||||
 
 | 
			
		||||
@@ -161,75 +161,34 @@ msgid "The last recorded height of the application window."
 | 
			
		||||
 msgstr "Uygulama penceresinin kaydedilen son yüksekliği."
 | 
			
		||||
 
 | 
			
		||||
 #: desktop/org.gnome.Geary.gschema.xml:26
 | 
			
		||||
-msgid "Position of folder list pane"
 | 
			
		||||
-msgstr "Klasör listesi bölmesinin konumu"
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:27
 | 
			
		||||
-msgid "Position of the folder list Paned grabber."
 | 
			
		||||
-msgstr "Klasör listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:32
 | 
			
		||||
-msgid "Position of folder list pane when horizontal"
 | 
			
		||||
-msgstr "Klasör listesi bölmesinin yataykenki konumu"
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:33
 | 
			
		||||
-msgid ""
 | 
			
		||||
-"Position of the folder list Paned grabber in the horizontal orientation."
 | 
			
		||||
-msgstr "Yatay yönelimde klasör listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:38
 | 
			
		||||
-msgid "Position of folder list pane when vertical"
 | 
			
		||||
-msgstr "Klasör listesi bölmesinin dikeykenki konumu"
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:39
 | 
			
		||||
-msgid "Position of the folder list Paned grabber in the vertical orientation."
 | 
			
		||||
-msgstr "Dikey yönelimde klasör listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:44
 | 
			
		||||
-msgid "Orientation of the folder list pane"
 | 
			
		||||
-msgstr "Klasör listesi bölmesinin konumlandırması"
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:45
 | 
			
		||||
-msgid "True if the folder list Paned is in the horizontal orientation."
 | 
			
		||||
-msgstr "Eğer klasör listesi bölmesi yatay yönelimdeyse doğru."
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:50
 | 
			
		||||
 msgid "Show/hide formatting toolbar"
 | 
			
		||||
 msgstr "Biçimlendirme araç çubuğunu göster/gizle"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:51
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:27
 | 
			
		||||
 msgid "True if the formatting toolbar in the composer is shown."
 | 
			
		||||
 msgstr "Eğer oluşturucudaki biçimlendirme araç çubuğu gösterilecekse doğru."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:56
 | 
			
		||||
-msgid "Position of message list pane"
 | 
			
		||||
-msgstr "İleti listesi bölmesinin konumu"
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:57
 | 
			
		||||
-msgid "Position of the message list Paned grabber."
 | 
			
		||||
-msgstr "İleti listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
-
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:62
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:32
 | 
			
		||||
 msgid "Autoselect next message"
 | 
			
		||||
 msgstr "Sonraki iletiyi kendiliğinden seç"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:63
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:33
 | 
			
		||||
 msgid "True if we should autoselect the next available conversation."
 | 
			
		||||
 msgstr "Eğer sonraki uygun konuşmayı kendiliğinden seçmemiz gerekiyorsa doğru."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:68
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:38
 | 
			
		||||
 msgid "Display message previews"
 | 
			
		||||
 msgstr "İleti ön izlemelerini göster"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:69
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:39
 | 
			
		||||
 msgid "True if we should display a short preview of each message."
 | 
			
		||||
 msgstr "Her iletinin kısa bir ön izlemesini göstermemiz gerekiyorsa doğru."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:74
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:44
 | 
			
		||||
 msgid "Use single key shortcuts"
 | 
			
		||||
 msgstr "Tek tuşlu kısayolları kullan"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:75
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:45
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "Enables shortcuts for email actions that do not require pressing <Ctrl> to "
 | 
			
		||||
 "emulate those used by Gmail."
 | 
			
		||||
@@ -237,11 +196,11 @@ msgstr ""
 | 
			
		||||
 "Gmailʼin kullandığına benzemek için eposta eylemlerinde <Ctrl>ʼye basmayı "
 | 
			
		||||
 "gerektirmeyen kısayolları etkinleştirir."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:82
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:52
 | 
			
		||||
 msgid "Languages that shall be used in the spell checker"
 | 
			
		||||
 msgstr "Yazım denetleyicide kullanılacak diller"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:83
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:53
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "A list of POSIX locales, with the empty list disabling spell checking and "
 | 
			
		||||
 "the null list using desktop languages by default."
 | 
			
		||||
@@ -249,11 +208,11 @@ msgstr ""
 | 
			
		||||
 "POSIX yerellerinin listesi, boş listeyle imla denetimi devre dışı bırakılır "
 | 
			
		||||
 "ve butlan (null) listeyle öntanımlı olarak masaüstü dillerini kullanılır."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:90
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:60
 | 
			
		||||
 msgid "Languages that are displayed in the spell checker popover"
 | 
			
		||||
 msgstr "Yazım denetleyici açılır penceresinde gösterilecek diller"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:91
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:61
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "List of languages that are always displayed in the popover of the spell "
 | 
			
		||||
 "checker."
 | 
			
		||||
@@ -261,62 +220,62 @@ msgstr ""
 | 
			
		||||
 "Yazım denetleyicinin açılır penceresinde her zaman gösterilecek dillerin "
 | 
			
		||||
 "listesi."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:96
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:66
 | 
			
		||||
 msgid "Notify of new mail at startup"
 | 
			
		||||
 msgstr "Başlangıçta yeni postanın bildirilmesi"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:97
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:67
 | 
			
		||||
 msgid "True to notify of new mail at startup."
 | 
			
		||||
 msgstr "Başlangıçta yeni postaların bildirilmesi için doğru."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:102
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:72
 | 
			
		||||
 msgid "Ask when opening an attachment"
 | 
			
		||||
 msgstr "Ek açarken sor"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:103
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:73
 | 
			
		||||
 msgid "True to ask when opening an attachment."
 | 
			
		||||
 msgstr "Eki açarken sormak için doğru."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:108
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:78
 | 
			
		||||
 msgid "Whether to compose emails in HTML"
 | 
			
		||||
 msgstr "E-postaların HTML’de oluşturulup oluşturulmayacağı"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:109
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:79
 | 
			
		||||
 msgid "True to compose emails in HTML; false for plain text."
 | 
			
		||||
 msgstr "E-postaları HTML’de oluşturmak için doğru, düz metin için yanlış."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:114
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:84
 | 
			
		||||
 msgid "Advisory strategy for full-text searching"
 | 
			
		||||
 msgstr "Tam metin arama için tavsiye niteliğinde izlem"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:115
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:85
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "Acceptable values are “exact”, “conservative”, “aggressive”, and “horizon”."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Kabul edilebilir değerler şunlardır: “exact” (birebir), "
 | 
			
		||||
 "“conservative” (ılımlı), “aggressive” (sert) ve “horizon”."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:120
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:90
 | 
			
		||||
 msgid "Zoom of conversation viewer"
 | 
			
		||||
 msgstr "Konuşma göstericisinin yakınlaşması"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:121
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:91
 | 
			
		||||
 msgid "The zoom to apply on the conservation view."
 | 
			
		||||
 msgstr "Konuşma görünümünde uygulanacak yakınlaşma."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:126
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:96
 | 
			
		||||
 msgid "Size of detached composer window"
 | 
			
		||||
 msgstr "Ayrılan oluşturucu penceresinin boyutu"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:127
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:97
 | 
			
		||||
 msgid "The last recorded size of the detached composer window."
 | 
			
		||||
 msgstr "Ayrılmış oluşturucu penceresinin kaydedilen son boyutu."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:132
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:102
 | 
			
		||||
 msgid "Undo sending email delay"
 | 
			
		||||
 msgstr "Eposta göndermeyi geri alma gecikmesi"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:133
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:103
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "The number of seconds to wait before sending an email. Set to zero or less "
 | 
			
		||||
 "to disable."
 | 
			
		||||
@@ -324,29 +283,29 @@ msgstr ""
 | 
			
		||||
 "Eposta gönderilmeden önce beklenecek saniye. Devre dışı bırakmak için sıfır "
 | 
			
		||||
 "veya daha azına belirleyin."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:139
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:109
 | 
			
		||||
 msgid "Brief notification display time"
 | 
			
		||||
 msgstr "Özet bildirim gösterim zamanı"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:140
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:110
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "The length of time in seconds for which brief notifications should be "
 | 
			
		||||
 "displayed."
 | 
			
		||||
 msgstr "Özet bildirimlerin gösterileceği zamanın saniye türünde uzunluğu."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:146
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:116
 | 
			
		||||
 msgid "List of optional plugins"
 | 
			
		||||
 msgstr "İsteğe bağlı eklenti listesi"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:147
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:117
 | 
			
		||||
 msgid "Plugins listed here will be loaded on startup."
 | 
			
		||||
 msgstr "Burada listelenen eklentiler başlangıçta yüklenecek."
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:152
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:122
 | 
			
		||||
 msgid "Whether we migrated the old settings"
 | 
			
		||||
 msgstr "Eski ayarları taşıyıp taşımayacağımız"
 | 
			
		||||
 
 | 
			
		||||
-#: desktop/org.gnome.Geary.gschema.xml:153
 | 
			
		||||
+#: desktop/org.gnome.Geary.gschema.xml:123
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "False to check for the old “org.yorba.geary”-schema and copy its values."
 | 
			
		||||
 msgstr ""
 | 
			
		||||
@@ -622,12 +581,12 @@ msgid_plural "%d days back"
 | 
			
		||||
 msgstr[0] "%d gün öncesinden"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/accounts/accounts-editor-list-pane.vala:255
 | 
			
		||||
-#: src/client/application/application-main-window.vala:2061
 | 
			
		||||
+#: src/client/application/application-main-window.vala:2129
 | 
			
		||||
 msgid "Undo"
 | 
			
		||||
 msgstr "Geri Al"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/accounts/accounts-editor-list-pane.vala:264
 | 
			
		||||
-#: src/client/application/application-main-window.vala:2044
 | 
			
		||||
+#: src/client/application/application-main-window.vala:2112
 | 
			
		||||
 msgid "Redo"
 | 
			
		||||
 msgstr "Yinele"
 | 
			
		||||
 
 | 
			
		||||
@@ -722,7 +681,7 @@ msgstr "TLS"
 | 
			
		||||
 #. account
 | 
			
		||||
 #. Translators: An info bar button label
 | 
			
		||||
 #: src/client/accounts/accounts-editor-row.vala:539
 | 
			
		||||
-#: src/client/application/application-main-window.vala:554
 | 
			
		||||
+#: src/client/application/application-main-window.vala:574
 | 
			
		||||
 msgid "Login"
 | 
			
		||||
 msgstr "Giriş"
 | 
			
		||||
 
 | 
			
		||||
@@ -974,13 +933,13 @@ msgstr ""
 | 
			
		||||
 
 | 
			
		||||
 #. / Warning printed to the console when a deprecated
 | 
			
		||||
 #. / command line option is used.
 | 
			
		||||
-#: src/client/application/application-client.vala:1047
 | 
			
		||||
+#: src/client/application/application-client.vala:1045
 | 
			
		||||
 msgid "The `--hidden` option is deprecated and will be removed in the future."
 | 
			
		||||
 msgstr "`--hidden` seçeneği terk edilmiştir ve gelecekte kaldırılacaktır."
 | 
			
		||||
 
 | 
			
		||||
 #. / Command line warning, string substitution
 | 
			
		||||
 #. / is the given argument
 | 
			
		||||
-#: src/client/application/application-client.vala:1080
 | 
			
		||||
+#: src/client/application/application-client.vala:1078
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Unrecognised program argument: “%s”"
 | 
			
		||||
 msgstr "Tanınmayan program argümanı: “%s”"
 | 
			
		||||
@@ -1165,54 +1124,54 @@ msgid "Email to %s discarded"
 | 
			
		||||
 msgstr "Şun(lar)a gidecek eposta gözden çıkarıldı: %s"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar status label
 | 
			
		||||
-#: src/client/application/application-main-window.vala:540
 | 
			
		||||
+#: src/client/application/application-main-window.vala:560
 | 
			
		||||
 msgid "Working offline"
 | 
			
		||||
 msgstr "Çevrim dışı çalışıyor"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar description label
 | 
			
		||||
-#: src/client/application/application-main-window.vala:542
 | 
			
		||||
+#: src/client/application/application-main-window.vala:562
 | 
			
		||||
 msgid "You will not be able to send or receive email until re-connected."
 | 
			
		||||
 msgstr "Yeniden bağlanana dek e-posta gönderemez veya alamazsınız."
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar status label
 | 
			
		||||
-#: src/client/application/application-main-window.vala:549
 | 
			
		||||
+#: src/client/application/application-main-window.vala:569
 | 
			
		||||
 msgid "Login problem"
 | 
			
		||||
 msgstr "Giriş sorunu"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar description label
 | 
			
		||||
-#: src/client/application/application-main-window.vala:551
 | 
			
		||||
+#: src/client/application/application-main-window.vala:571
 | 
			
		||||
 msgid "An account has reported an incorrect login or password."
 | 
			
		||||
 msgstr "Hesap yanlış bir giriş veya parola bildirdi."
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar button tool-tip
 | 
			
		||||
-#: src/client/application/application-main-window.vala:558
 | 
			
		||||
+#: src/client/application/application-main-window.vala:578
 | 
			
		||||
 msgid "Retry login, you will be prompted for your password"
 | 
			
		||||
 msgstr "Giriş yapmayı yeniden dene, parola girmeniz istenecek"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar status label
 | 
			
		||||
-#: src/client/application/application-main-window.vala:565
 | 
			
		||||
+#: src/client/application/application-main-window.vala:585
 | 
			
		||||
 msgid "Security problem"
 | 
			
		||||
 msgstr "Güvenlik sorunu"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar description label
 | 
			
		||||
-#: src/client/application/application-main-window.vala:567
 | 
			
		||||
+#: src/client/application/application-main-window.vala:587
 | 
			
		||||
 msgid "An account has reported an untrusted server."
 | 
			
		||||
 msgstr "Hesap, güvenilmeyen bir sunucu bildirdi."
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar button label
 | 
			
		||||
-#: src/client/application/application-main-window.vala:570
 | 
			
		||||
+#: src/client/application/application-main-window.vala:590
 | 
			
		||||
 msgid "Check"
 | 
			
		||||
 msgstr "Gözden geçir"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: An info bar button tool-tip
 | 
			
		||||
-#: src/client/application/application-main-window.vala:574
 | 
			
		||||
+#: src/client/application/application-main-window.vala:594
 | 
			
		||||
 msgid "Check the security details for the connection"
 | 
			
		||||
 msgstr "Bağlantı güvenlik ayrıntılarını gözden geçirin"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Main window title, first string
 | 
			
		||||
 #. / substitution being the currently selected folder name,
 | 
			
		||||
 #. / the second being the selected account name.
 | 
			
		||||
-#: src/client/application/application-main-window.vala:617
 | 
			
		||||
+#: src/client/application/application-main-window.vala:637
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "%s — %s"
 | 
			
		||||
 msgstr "%s — %s"
 | 
			
		||||
@@ -1220,47 +1179,47 @@ msgstr "%s — %s"
 | 
			
		||||
 #. Translators: The name of the folder group containing
 | 
			
		||||
 #. folders created by people (as opposed to special-use
 | 
			
		||||
 #. folders)
 | 
			
		||||
-#: src/client/application/application-main-window.vala:996
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1019
 | 
			
		||||
 #: src/client/folder-list/folder-list-account-branch.vala:43
 | 
			
		||||
 msgid "Labels"
 | 
			
		||||
 msgstr "Etiketler"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1293
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1337
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Empty all email from your %s folder?"
 | 
			
		||||
 msgstr "%s klasörünüzdeki tüm e-postaları boşalt?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1294
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1338
 | 
			
		||||
 msgid "This removes the email from Geary and your email server."
 | 
			
		||||
 msgstr "Bu işlem e-postayı Geary’den ve e-posta sunucunuzdan kaldırır."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1295
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1339
 | 
			
		||||
 msgid "This cannot be undone."
 | 
			
		||||
 msgstr "Bu geri alınamaz."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1296
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1340
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "Empty %s"
 | 
			
		||||
 msgstr "%s boşalt"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Primary text for a confirmation dialog
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1353
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1397
 | 
			
		||||
 msgid "Do you want to permanently delete this conversation?"
 | 
			
		||||
 msgid_plural "Do you want to permanently delete these conversations?"
 | 
			
		||||
 msgstr[0] "Bu konuşmaları kalıcı olarak silmek istiyor musunuz?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1358
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1373
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1402
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1417
 | 
			
		||||
 msgid "Delete"
 | 
			
		||||
 msgstr "Sil"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Primary text for a confirmation dialog
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1368
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1412
 | 
			
		||||
 msgid "Do you want to permanently delete this message?"
 | 
			
		||||
 msgid_plural "Do you want to permanently delete these messages?"
 | 
			
		||||
 msgstr[0] "Bu ileti(ler)i kalıcı olarak silmek istiyor musunuz?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/application/application-main-window.vala:1691
 | 
			
		||||
+#: src/client/application/application-main-window.vala:1703
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "%s (%d)"
 | 
			
		||||
 msgstr "%s (%d)"
 | 
			
		||||
@@ -1271,7 +1230,7 @@ msgstr "%s (%d)"
 | 
			
		||||
 #. Document (100.9MB)
 | 
			
		||||
 #. / In the composer, the filename followed by its filesize, i.e. "notes.txt (1.12KB)"
 | 
			
		||||
 #: src/client/components/components-attachment-pane.vala:107
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1784
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1792
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "%s (%s)"
 | 
			
		||||
 msgstr "%s (%s)"
 | 
			
		||||
@@ -1292,6 +1251,36 @@ msgstr ""
 | 
			
		||||
 msgid "Don’t _ask me again"
 | 
			
		||||
 msgstr "Yeniden _sorma"
 | 
			
		||||
 
 | 
			
		||||
+#: src/client/components/components-conversation-actions.vala:90
 | 
			
		||||
+msgid "Mark conversation"
 | 
			
		||||
+msgid_plural "Mark conversations"
 | 
			
		||||
+msgstr[0] "Konuşmayı imle"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-conversation-actions.vala:95
 | 
			
		||||
+msgid "Add label to conversation"
 | 
			
		||||
+msgid_plural "Add label to conversations"
 | 
			
		||||
+msgstr[0] "Konuşmayı etiketle"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-conversation-actions.vala:100
 | 
			
		||||
+msgid "Move conversation"
 | 
			
		||||
+msgid_plural "Move conversations"
 | 
			
		||||
+msgstr[0] "Konuşmayı taşı"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-conversation-actions.vala:105
 | 
			
		||||
+msgid "Archive conversation"
 | 
			
		||||
+msgid_plural "Archive conversations"
 | 
			
		||||
+msgstr[0] "Konuşmayı arşivle"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-conversation-actions.vala:116
 | 
			
		||||
+msgid "Move conversation to Trash"
 | 
			
		||||
+msgid_plural "Move conversations to Trash"
 | 
			
		||||
+msgstr[0] "Konuşmayı Çöpʼe taşı"
 | 
			
		||||
+
 | 
			
		||||
+#: src/client/components/components-conversation-actions.vala:126
 | 
			
		||||
+msgid "Delete conversation"
 | 
			
		||||
+msgid_plural "Delete conversations"
 | 
			
		||||
+msgstr[0] "Konuşmayı sil"
 | 
			
		||||
+
 | 
			
		||||
 #: src/client/components/components-inspector.vala:78
 | 
			
		||||
 msgid "Inspector"
 | 
			
		||||
 msgstr "İnceleyici"
 | 
			
		||||
@@ -1322,7 +1311,7 @@ msgstr "Farklı Kaydet"
 | 
			
		||||
 
 | 
			
		||||
 #: src/client/components/components-inspector.vala:230
 | 
			
		||||
 #: src/client/dialogs/dialogs-problem-details-dialog.vala:224
 | 
			
		||||
-#: ui/accounts_editor_servers_pane.ui:17
 | 
			
		||||
+#: ui/accounts_editor_servers_pane.ui:17 ui/composer-headerbar.ui:61
 | 
			
		||||
 msgid "Cancel"
 | 
			
		||||
 msgstr "İptal Et"
 | 
			
		||||
 
 | 
			
		||||
@@ -1338,15 +1327,10 @@ msgstr "Konuşma ön izlemesini _göster"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Preferences label
 | 
			
		||||
 #: src/client/components/components-preferences-window.vala:144
 | 
			
		||||
-msgid "Use _three pane view"
 | 
			
		||||
-msgstr "_Üç bölmeli görünümü kullan"
 | 
			
		||||
-
 | 
			
		||||
-#. / Translators: Preferences label
 | 
			
		||||
-#: src/client/components/components-preferences-window.vala:154
 | 
			
		||||
 msgid "Use _single key email shortcuts"
 | 
			
		||||
 msgstr "_Tek tuşlu eposta kısayolları kullan"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/components/components-preferences-window.vala:156
 | 
			
		||||
+#: src/client/components/components-preferences-window.vala:146
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "Enable keyboard shortcuts for email actions that do not require pressing "
 | 
			
		||||
 "<Ctrl>"
 | 
			
		||||
@@ -1355,22 +1339,22 @@ msgstr ""
 | 
			
		||||
 "etkinleştir"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Preferences label
 | 
			
		||||
-#: src/client/components/components-preferences-window.vala:167
 | 
			
		||||
+#: src/client/components/components-preferences-window.vala:157
 | 
			
		||||
 msgid "_Watch for new mail when closed"
 | 
			
		||||
 msgstr "Kapatıldığında yeni postayı _gözetle"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Preferences tooltip
 | 
			
		||||
-#: src/client/components/components-preferences-window.vala:171
 | 
			
		||||
+#: src/client/components/components-preferences-window.vala:161
 | 
			
		||||
 msgid "Geary will keep running after all windows are closed"
 | 
			
		||||
 msgstr "Geary, tüm pencereler kapatıldıktan sonra çalışmayı sürdürecek"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Preferences page title
 | 
			
		||||
-#: src/client/components/components-preferences-window.vala:189
 | 
			
		||||
+#: src/client/components/components-preferences-window.vala:178
 | 
			
		||||
 msgid "Preferences"
 | 
			
		||||
 msgstr "Tercihler"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Preferences page title
 | 
			
		||||
-#: src/client/components/components-preferences-window.vala:250
 | 
			
		||||
+#: src/client/components/components-preferences-window.vala:234
 | 
			
		||||
 msgid "Plugins"
 | 
			
		||||
 msgstr "Eklentiler"
 | 
			
		||||
 
 | 
			
		||||
@@ -1489,36 +1473,6 @@ msgstr "Sunucu adı gerekli"
 | 
			
		||||
 msgid "Could not look up server name"
 | 
			
		||||
 msgstr "Sunucu adı yoklanamıyor"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/components/main-toolbar.vala:116
 | 
			
		||||
-msgid "Mark conversation"
 | 
			
		||||
-msgid_plural "Mark conversations"
 | 
			
		||||
-msgstr[0] "Konuşmayı imle"
 | 
			
		||||
-
 | 
			
		||||
-#: src/client/components/main-toolbar.vala:121
 | 
			
		||||
-msgid "Add label to conversation"
 | 
			
		||||
-msgid_plural "Add label to conversations"
 | 
			
		||||
-msgstr[0] "Konuşmayı etiketle"
 | 
			
		||||
-
 | 
			
		||||
-#: src/client/components/main-toolbar.vala:126
 | 
			
		||||
-msgid "Move conversation"
 | 
			
		||||
-msgid_plural "Move conversations"
 | 
			
		||||
-msgstr[0] "Konuşmayı taşı"
 | 
			
		||||
-
 | 
			
		||||
-#: src/client/components/main-toolbar.vala:131
 | 
			
		||||
-msgid "Archive conversation"
 | 
			
		||||
-msgid_plural "Archive conversations"
 | 
			
		||||
-msgstr[0] "Konuşmayı arşivle"
 | 
			
		||||
-
 | 
			
		||||
-#: src/client/components/main-toolbar.vala:142
 | 
			
		||||
-msgid "Move conversation to Trash"
 | 
			
		||||
-msgid_plural "Move conversations to Trash"
 | 
			
		||||
-msgstr[0] "Konuşmayı Çöpʼe taşı"
 | 
			
		||||
-
 | 
			
		||||
-#: src/client/components/main-toolbar.vala:152
 | 
			
		||||
-msgid "Delete conversation"
 | 
			
		||||
-msgid_plural "Delete conversations"
 | 
			
		||||
-msgstr[0] "Konuşmayı sil"
 | 
			
		||||
-
 | 
			
		||||
 #. / Displayed in the space-limited status bar while a message is in the process of being sent.
 | 
			
		||||
 #: src/client/components/status-bar.vala:26
 | 
			
		||||
 msgid "Sending…"
 | 
			
		||||
@@ -1650,92 +1604,92 @@ msgstr ""
 | 
			
		||||
 #. Translators: This dialog text is displayed to the
 | 
			
		||||
 #. user when closing a composer where the options are
 | 
			
		||||
 #. Keep, Discard or Cancel.
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:862
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:865
 | 
			
		||||
 msgid "Do you want to keep or discard this draft message?"
 | 
			
		||||
 msgstr "Bu iletiyi saklamak mı yoksa gözden çıkarmak mı istersiniz?"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: This dialog text is displayed to the
 | 
			
		||||
 #. user when closing a composer where the options are
 | 
			
		||||
 #. only Discard or Cancel.
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:888
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:891
 | 
			
		||||
 msgid "Do you want to discard this draft message?"
 | 
			
		||||
 msgstr "Bu taslak iletiyi gözden çıkarmak istiyor musunuz?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1440
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1448
 | 
			
		||||
 msgid "Send message with an empty subject and body?"
 | 
			
		||||
 msgstr "İleti konusu ve gövdesi olmadan gönderilsin mi?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1442
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1450
 | 
			
		||||
 msgid "Send message with an empty subject?"
 | 
			
		||||
 msgstr "İleti konusu olmadan gönderilsin mi?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1444
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1452
 | 
			
		||||
 msgid "Send message with an empty body?"
 | 
			
		||||
 msgstr "İleti, ileti gövdesi olmadan gönderilsin mi?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1453
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1461
 | 
			
		||||
 msgid "Send message without an attachment?"
 | 
			
		||||
 msgstr "İleti eki olmadan gönderilsin mi?"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1772
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1780
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "“%s” already attached for delivery."
 | 
			
		||||
 msgstr "“%s” gönderim için zaten eklendi."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1804
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1854
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1812
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1862
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "“%s” is an empty file."
 | 
			
		||||
 msgstr "“%s” boş bir dosya."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1842
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1850
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "“%s” could not be found."
 | 
			
		||||
 msgstr "“%s” bulunamadı."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1848
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1856
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "“%s” is a folder."
 | 
			
		||||
 msgstr "“%s” bir klasör."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1867
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1875
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "“%s” could not be opened for reading."
 | 
			
		||||
 msgstr "“%s” okuma için açılamadı."
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1875
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1883
 | 
			
		||||
 msgid "Cannot add attachment"
 | 
			
		||||
 msgstr "Eklenti eklenemiyor"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: This is the name of the file chooser filter
 | 
			
		||||
 #. when inserting an image in the composer.
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:1946
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:1954
 | 
			
		||||
 msgid "Images"
 | 
			
		||||
 msgstr "Resimler"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Human-readable version of the RFC 822 To header
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:2010
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:2018
 | 
			
		||||
 #: src/client/conversation-viewer/conversation-email.vala:542
 | 
			
		||||
 #: src/client/util/util-email.vala:249 ui/conversation-message.ui:312
 | 
			
		||||
 msgid "To:"
 | 
			
		||||
 msgstr "Kime:"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Human-readable version of the RFC 822 CC header
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:2016
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:2024
 | 
			
		||||
 #: src/client/conversation-viewer/conversation-email.vala:547
 | 
			
		||||
 #: src/client/util/util-email.vala:254 ui/conversation-message.ui:357
 | 
			
		||||
 msgid "Cc:"
 | 
			
		||||
 msgstr "Cc:"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Human-readable version of the RFC 822 BCC header
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:2022
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:2030
 | 
			
		||||
 #: src/client/conversation-viewer/conversation-email.vala:552
 | 
			
		||||
 #: ui/conversation-message.ui:402
 | 
			
		||||
 msgid "Bcc:"
 | 
			
		||||
 msgstr "Bcc:"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Human-readable version of the RFC 822 Reply-To header
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:2028
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:2036
 | 
			
		||||
 msgid "Reply-To: "
 | 
			
		||||
 msgstr "Şuna Yanıtla: "
 | 
			
		||||
 
 | 
			
		||||
@@ -1744,7 +1698,7 @@ msgstr "Şuna Yanıtla: "
 | 
			
		||||
 #. printf argument will be the alternate email address,
 | 
			
		||||
 #. and the second will be the account's primary email
 | 
			
		||||
 #. address.
 | 
			
		||||
-#: src/client/composer/composer-widget.vala:2146
 | 
			
		||||
+#: src/client/composer/composer-widget.vala:2154
 | 
			
		||||
 #, c-format
 | 
			
		||||
 msgid "%1$s via %2$s"
 | 
			
		||||
 msgstr "%2$s aracılığıyla %1$s"
 | 
			
		||||
@@ -1762,49 +1716,49 @@ msgid "Search for more languages"
 | 
			
		||||
 msgstr "Daha çok dil için ara"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Context menu item
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:339
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:389
 | 
			
		||||
 msgid "Move conversation to _Trash"
 | 
			
		||||
 msgid_plural "Move conversations to _Trash"
 | 
			
		||||
 msgstr[0] "Konuşmayı _Çöpʼe taşı"
 | 
			
		||||
 
 | 
			
		||||
 #. / Translators: Context menu item
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:351
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:401
 | 
			
		||||
 msgid "_Delete conversation"
 | 
			
		||||
 msgid_plural "_Delete conversations"
 | 
			
		||||
 msgstr[0] "Konuşmayı _sil"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:364
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:414
 | 
			
		||||
 #: ui/main-toolbar-menus.ui:5
 | 
			
		||||
 msgid "Mark as _Read"
 | 
			
		||||
 msgstr "_Okundu olarak imle"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:372
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:422
 | 
			
		||||
 #: ui/main-toolbar-menus.ui:9
 | 
			
		||||
 msgid "Mark as _Unread"
 | 
			
		||||
 msgstr "Ok_unmamış olarak imle"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:380
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:430
 | 
			
		||||
 #: ui/main-toolbar-menus.ui:17
 | 
			
		||||
 msgid "U_nstar"
 | 
			
		||||
 msgstr "Y_ıldızı kaldır"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:387
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:437
 | 
			
		||||
 #: ui/main-toolbar-menus.ui:13
 | 
			
		||||
 msgid "_Star"
 | 
			
		||||
 msgstr "_Yıldızla"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Menu item to reply to a specific message.
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:396
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:446
 | 
			
		||||
 #: ui/conversation-email-menus.ui:9
 | 
			
		||||
 msgid "_Reply"
 | 
			
		||||
 msgstr "_Yanıtla"
 | 
			
		||||
 
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:402
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:452
 | 
			
		||||
 msgid "R_eply All"
 | 
			
		||||
 msgstr "Tümüne _Yanıtla"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Menu item to forward a specific message.
 | 
			
		||||
-#: src/client/conversation-list/conversation-list-view.vala:408
 | 
			
		||||
+#: src/client/conversation-list/conversation-list-view.vala:458
 | 
			
		||||
 #: ui/conversation-email-menus.ui:21
 | 
			
		||||
 msgid "_Forward"
 | 
			
		||||
 msgstr "_Yönlendir"
 | 
			
		||||
@@ -1894,25 +1848,25 @@ msgstr "Gönderenden her zaman göster"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Title label for placeholder when no
 | 
			
		||||
 #. conversations have been selected.
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:83
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:87
 | 
			
		||||
 msgid "No conversations selected"
 | 
			
		||||
 msgstr "Konuşma seçilmedi"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Sub-title label for placeholder when no
 | 
			
		||||
 #. conversations have been selected.
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:87
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:91
 | 
			
		||||
 msgid "Selecting a conversation from the list will display it here"
 | 
			
		||||
 msgstr "Listeden bir ileti seçtiğinizde burada gösterilecek"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Title label for placeholder when multiple
 | 
			
		||||
 #. conversations have been selected.
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:96
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:100
 | 
			
		||||
 msgid "Multiple conversations selected"
 | 
			
		||||
 msgstr "Birden çok konuşma seçildi"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Sub-title label for placeholder when multiple
 | 
			
		||||
 #. conversations have been selected.
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:100
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:104
 | 
			
		||||
 msgid "Choosing an action will apply to all selected conversations"
 | 
			
		||||
 msgstr "Bir eylem seçtiğinizde tüm seçili konuşmalara uygulanacaktır"
 | 
			
		||||
 
 | 
			
		||||
@@ -1920,20 +1874,20 @@ msgstr "Bir eylem seçtiğinizde tüm seçili konuşmalara uygulanacaktır"
 | 
			
		||||
 #. conversations have exist in a folder.
 | 
			
		||||
 #. Translators: Title label for placeholder when no
 | 
			
		||||
 #. conversations have been found in a search.
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:109
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:122
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:113
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:126
 | 
			
		||||
 msgid "No conversations found"
 | 
			
		||||
 msgstr "Konuşma bulunamadı"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Sub-title label for placeholder when no
 | 
			
		||||
 #. conversations have exist in a folder.
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:113
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:117
 | 
			
		||||
 msgid "This folder does not contain any conversations"
 | 
			
		||||
 msgstr "Bu klasör herhangi bir konuşma içermiyor"
 | 
			
		||||
 
 | 
			
		||||
 #. Translators: Sub-title label for placeholder when no
 | 
			
		||||
 #. conversations have been found in a search.
 | 
			
		||||
-#: src/client/conversation-viewer/conversation-viewer.vala:126
 | 
			
		||||
+#: src/client/conversation-viewer/conversation-viewer.vala:130
 | 
			
		||||
 msgid "Your search returned no results, try refining your search terms"
 | 
			
		||||
 msgstr "Aramanız sonuçsuz kaldı, arama terimlerinizi arıtmayı deneyin"
 | 
			
		||||
 
 | 
			
		||||
@@ -2652,7 +2606,7 @@ msgstr "okunmadı"
 | 
			
		||||
 #. Draft mailbox. Separate names using a vertical bar and
 | 
			
		||||
 #. put the most common localized name to the front for the
 | 
			
		||||
 #. default. English names do not need to be included.
 | 
			
		||||
-#: src/engine/imap-engine/imap-engine-generic-account.vala:996
 | 
			
		||||
+#: src/engine/imap-engine/imap-engine-generic-account.vala:998
 | 
			
		||||
 msgid "Drafts | Draft"
 | 
			
		||||
 msgstr "Taslaklar | Taslak"
 | 
			
		||||
 
 | 
			
		||||
@@ -2660,14 +2614,14 @@ msgstr "Taslaklar | Taslak"
 | 
			
		||||
 #. Sent mailbox. Separate names using a vertical bar and
 | 
			
		||||
 #. put the most common localized name to the front for the
 | 
			
		||||
 #. default. English names do not need to be included.
 | 
			
		||||
-#: src/engine/imap-engine/imap-engine-generic-account.vala:1005
 | 
			
		||||
+#: src/engine/imap-engine/imap-engine-generic-account.vala:1007
 | 
			
		||||
 msgid "Sent | Sent Mail | Sent Email | Sent E-Mail"
 | 
			
		||||
 msgstr ""
 | 
			
		||||
 "Gönderilmiş | Gönderilmiş Posta | Gönderilmiş Eposta | Gönderilmiş E-Posta"
 | 
			
		||||
 
 | 
			
		||||
 #. The localised name(s) of the Sent folder name as used
 | 
			
		||||
 #. by MS Outlook/Exchange.
 | 
			
		||||
-#: src/engine/imap-engine/imap-engine-generic-account.vala:1010
 | 
			
		||||
+#: src/engine/imap-engine/imap-engine-generic-account.vala:1012
 | 
			
		||||
 msgctxt "Outlook localised name"
 | 
			
		||||
 msgid "Sent Items"
 | 
			
		||||
 msgstr "Gönderilmiş Ögeler"
 | 
			
		||||
@@ -2676,7 +2630,7 @@ msgstr "Gönderilmiş Ögeler"
 | 
			
		||||
 #. Junk/Spam mailbox. Separate names using a vertical bar
 | 
			
		||||
 #. and put the most common localized name to the front for
 | 
			
		||||
 #. the default. English names do not need to be included.
 | 
			
		||||
-#: src/engine/imap-engine/imap-engine-generic-account.vala:1020
 | 
			
		||||
+#: src/engine/imap-engine/imap-engine-generic-account.vala:1022
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "Junk | Spam | Junk Mail | Junk Email | Junk E-Mail | Bulk Mail | Bulk Email "
 | 
			
		||||
 "| Bulk E-Mail"
 | 
			
		||||
@@ -2688,13 +2642,13 @@ msgstr ""
 | 
			
		||||
 #. Trash mailbox. Separate names using a vertical bar and
 | 
			
		||||
 #. put the most common localized name to the front for the
 | 
			
		||||
 #. default. English names do not need to be included.
 | 
			
		||||
-#: src/engine/imap-engine/imap-engine-generic-account.vala:1030
 | 
			
		||||
+#: src/engine/imap-engine/imap-engine-generic-account.vala:1032
 | 
			
		||||
 msgid "Trash | Rubbish | Rubbish Bin"
 | 
			
		||||
 msgstr "Çöp | Çöp | Çöp Kutusu"
 | 
			
		||||
 
 | 
			
		||||
 #. The localised name(s) of the Trash folder name as used
 | 
			
		||||
 #. by MS Outlook/Exchange.
 | 
			
		||||
-#: src/engine/imap-engine/imap-engine-generic-account.vala:1035
 | 
			
		||||
+#: src/engine/imap-engine/imap-engine-generic-account.vala:1037
 | 
			
		||||
 msgctxt "Outlook localised name"
 | 
			
		||||
 msgid "Deleted Items"
 | 
			
		||||
 msgstr "Silinen Ögeler"
 | 
			
		||||
@@ -2703,7 +2657,7 @@ msgstr "Silinen Ögeler"
 | 
			
		||||
 #. Archive mailbox. Separate names using a vertical bar
 | 
			
		||||
 #. and put the most common localized name to the front for
 | 
			
		||||
 #. the default. English names do not need to be included.
 | 
			
		||||
-#: src/engine/imap-engine/imap-engine-generic-account.vala:1045
 | 
			
		||||
+#: src/engine/imap-engine/imap-engine-generic-account.vala:1047
 | 
			
		||||
 msgid "Archive | Archives"
 | 
			
		||||
 msgstr "Arşiv | Arşivler"
 | 
			
		||||
 
 | 
			
		||||
@@ -3079,6 +3033,26 @@ msgstr "Seçilen ekleri aç"
 | 
			
		||||
 msgid "Save _All"
 | 
			
		||||
 msgstr "_Tümünü Kaydet"
 | 
			
		||||
 
 | 
			
		||||
+#: ui/components-conversation-actions.ui:85
 | 
			
		||||
+msgid "Reply"
 | 
			
		||||
+msgstr "Yanıtla"
 | 
			
		||||
+
 | 
			
		||||
+#: ui/components-conversation-actions.ui:108
 | 
			
		||||
+msgid "Reply All"
 | 
			
		||||
+msgstr "Tümüne Yanıtla"
 | 
			
		||||
+
 | 
			
		||||
+#: ui/components-conversation-actions.ui:131
 | 
			
		||||
+msgid "Forward"
 | 
			
		||||
+msgstr "Yönlendir"
 | 
			
		||||
+
 | 
			
		||||
+#: ui/components-conversation-actions.ui:163
 | 
			
		||||
+msgid "_Archive"
 | 
			
		||||
+msgstr "_Arşivle"
 | 
			
		||||
+
 | 
			
		||||
+#: ui/components-conversation-actions.ui:211
 | 
			
		||||
+msgid "Toggle find bar"
 | 
			
		||||
+msgstr "Bulma çubuğunu aç"
 | 
			
		||||
+
 | 
			
		||||
 #: ui/components-inspector-error-view.ui:31
 | 
			
		||||
 msgid ""
 | 
			
		||||
 "If the problem is serious or persists, please save and send these details to "
 | 
			
		||||
@@ -3616,35 +3590,19 @@ msgctxt "shortcut window"
 | 
			
		||||
 msgid "Insert a link"
 | 
			
		||||
 msgstr "Bağlantı yerleştir"
 | 
			
		||||
 
 | 
			
		||||
-#: ui/main-toolbar.ui:24
 | 
			
		||||
+#: ui/main-toolbar.ui:85 ui/main-toolbar.ui:179
 | 
			
		||||
+msgid "Back"
 | 
			
		||||
+msgstr "Geri"
 | 
			
		||||
+
 | 
			
		||||
+#: ui/main-toolbar.ui:104
 | 
			
		||||
 msgctxt "tooltip"
 | 
			
		||||
 msgid "Compose Message"
 | 
			
		||||
 msgstr "İleti Oluştur"
 | 
			
		||||
 
 | 
			
		||||
-#: ui/main-toolbar.ui:62
 | 
			
		||||
+#: ui/main-toolbar.ui:122
 | 
			
		||||
 msgid "Toggle search bar"
 | 
			
		||||
 msgstr "Arama çubuğunu aç"
 | 
			
		||||
 
 | 
			
		||||
-#: ui/main-toolbar.ui:114
 | 
			
		||||
-msgid "Reply"
 | 
			
		||||
-msgstr "Yanıtla"
 | 
			
		||||
-
 | 
			
		||||
-#: ui/main-toolbar.ui:137
 | 
			
		||||
-msgid "Reply All"
 | 
			
		||||
-msgstr "Tümüne Yanıtla"
 | 
			
		||||
-
 | 
			
		||||
-#: ui/main-toolbar.ui:160
 | 
			
		||||
-msgid "Forward"
 | 
			
		||||
-msgstr "Yönlendir"
 | 
			
		||||
-
 | 
			
		||||
-#: ui/main-toolbar.ui:265
 | 
			
		||||
-msgid "Toggle find bar"
 | 
			
		||||
-msgstr "Bulma çubuğunu aç"
 | 
			
		||||
-
 | 
			
		||||
-#: ui/main-toolbar.ui:286
 | 
			
		||||
-msgid "_Archive"
 | 
			
		||||
-msgstr "_Arşivle"
 | 
			
		||||
-
 | 
			
		||||
 #: ui/main-toolbar-menus.ui:21
 | 
			
		||||
 msgid "Toggle as _Junk"
 | 
			
		||||
 msgstr "_Gereksiz olarak imle"
 | 
			
		||||
@@ -3681,6 +3639,41 @@ msgstr "_Kimlik Doğrula"
 | 
			
		||||
 msgid "Geary update in progress…"
 | 
			
		||||
 msgstr "Geary güncellemesi sürüyor…"
 | 
			
		||||
 
 | 
			
		||||
+#~ msgid "Position of folder list pane"
 | 
			
		||||
+#~ msgstr "Klasör listesi bölmesinin konumu"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Position of the folder list Paned grabber."
 | 
			
		||||
+#~ msgstr "Klasör listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Position of folder list pane when horizontal"
 | 
			
		||||
+#~ msgstr "Klasör listesi bölmesinin yataykenki konumu"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid ""
 | 
			
		||||
+#~ "Position of the folder list Paned grabber in the horizontal orientation."
 | 
			
		||||
+#~ msgstr "Yatay yönelimde klasör listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Position of folder list pane when vertical"
 | 
			
		||||
+#~ msgstr "Klasör listesi bölmesinin dikeykenki konumu"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid ""
 | 
			
		||||
+#~ "Position of the folder list Paned grabber in the vertical orientation."
 | 
			
		||||
+#~ msgstr "Dikey yönelimde klasör listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Orientation of the folder list pane"
 | 
			
		||||
+#~ msgstr "Klasör listesi bölmesinin konumlandırması"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "True if the folder list Paned is in the horizontal orientation."
 | 
			
		||||
+#~ msgstr "Eğer klasör listesi bölmesi yatay yönelimdeyse doğru."
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Position of message list pane"
 | 
			
		||||
+#~ msgstr "İleti listesi bölmesinin konumu"
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Position of the message list Paned grabber."
 | 
			
		||||
+#~ msgstr "İleti listesi bölmesi yakalayıcının konumu."
 | 
			
		||||
+
 | 
			
		||||
+#~ msgid "Use _three pane view"
 | 
			
		||||
+#~ msgstr "_Üç bölmeli görünümü kullan"
 | 
			
		||||
+
 | 
			
		||||
 #~ msgid "Desktop Notifications"
 | 
			
		||||
 #~ msgstr "Masaüstü Bildirimleri"
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.29.2
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user