[geary/wip/714104-refine-account-dialog] Improve handling of GOA accounts in the account editor



commit 1013e462e6f2dc87eb58aeb3725e2284206b3e30
Author: Michael Gratton <mike vee net>
Date:   Sun Sep 9 18:39:44 2018 +1000

    Improve handling of GOA accounts in the account editor
    
    Show GNOME settings when adding a supported GOA service type and
    it is installed, otherwise show Geary's custom password-based impl.
    
    For GOA accounts, hide the Remove button, and enable opening the
    account in GNOME Settings from the server pane.

 src/client/accounts/accounts-editor-edit-pane.vala |  11 ++-
 src/client/accounts/accounts-editor-list-pane.vala |  30 +++++-
 .../accounts/accounts-editor-servers-pane.vala     |  50 +++++++++-
 src/client/accounts/accounts-editor.vala           |   5 +-
 src/client/accounts/accounts-manager.vala          | 103 +++++++++++++++++++++
 src/client/accounts/goa-service-information.vala   |   2 +-
 ui/accounts_editor_edit_pane.ui                    |   2 +-
 ui/accounts_editor_servers_pane.ui                 |   3 +
 8 files changed, 192 insertions(+), 14 deletions(-)
---
diff --git a/src/client/accounts/accounts-editor-edit-pane.vala 
b/src/client/accounts/accounts-editor-edit-pane.vala
index ee2fb119..8df1f45c 100644
--- a/src/client/accounts/accounts-editor-edit-pane.vala
+++ b/src/client/accounts/accounts-editor-edit-pane.vala
@@ -48,6 +48,9 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
     [GtkChild]
     private Gtk.Button undo_button;
 
+    [GtkChild]
+    private Gtk.Button remove_button;
+
 
     public EditorEditPane(Editor editor, Geary.AccountInformation account) {
         this.editor = editor;
@@ -106,6 +109,10 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
         this.settings_list.set_header_func(Editor.seperator_headers);
         this.settings_list.add(new EmailPrefetchRow(this));
 
+        this.remove_button.set_visible(
+            !this.editor.accounts.is_goa_account(account)
+        );
+
         this.account.information_changed.connect(on_account_changed);
         update_header();
 
@@ -189,7 +196,9 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
 
     [GtkCallback]
     private void on_remove_account_clicked() {
-        this.editor.push(new EditorRemovePane(this.editor, this.account));
+        if (!this.editor.accounts.is_goa_account(account)) {
+            this.editor.push(new EditorRemovePane(this.editor, this.account));
+        }
     }
 
     [GtkCallback]
diff --git a/src/client/accounts/accounts-editor-list-pane.vala 
b/src/client/accounts/accounts-editor-list-pane.vala
index 4f3ad517..c54afb14 100644
--- a/src/client/accounts/accounts-editor-list-pane.vala
+++ b/src/client/accounts/accounts-editor-list-pane.vala
@@ -28,9 +28,9 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane {
     }
 
 
-    protected weak Accounts.Editor editor { get; set; }
+    internal Manager accounts { get; private set; }
 
-    private Manager accounts;
+    protected weak Accounts.Editor editor { get; set; }
 
     private Application.CommandStack commands = new Application.CommandStack();
 
@@ -67,8 +67,10 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane {
 
     public EditorListPane(Editor editor) {
         this.editor = editor;
-        this.accounts =
-            ((GearyApplication) editor.application).controller.account_manager;
+
+        // keep our own copy of this so we can disconnect from its signals
+        // without worrying about the editor's lifecycle
+        this.accounts = editor.accounts;
 
         this.pane_content.set_focus_vadjustment(this.pane_adjustment);
 
@@ -404,7 +406,25 @@ private class Accounts.AddServiceProviderRow : EditorRow<EditorListPane> {
     }
 
     public override void activated(EditorListPane pane) {
-        pane.show_add_account(this.provider);
+        pane.accounts.add_goa_account.begin(
+            this.provider, null,
+            (obj, res) => {
+                bool add_local = false;
+                try {
+                    pane.accounts.add_goa_account.end(res);
+                } catch (Error.INVALID err) {
+                    // Not a supported type, so don't bother logging the error
+                    add_local = true;
+                } catch (GLib.Error err) {
+                    debug("Failed to add %s via GOA: %s",
+                          this.provider.to_string(), err.message);
+                    add_local = true;
+                }
+
+                if (add_local) {
+                    pane.show_add_account(this.provider);
+                }
+            });
     }
 
 }
diff --git a/src/client/accounts/accounts-editor-servers-pane.vala 
b/src/client/accounts/accounts-editor-servers-pane.vala
index 43cd001d..733ae331 100644
--- a/src/client/accounts/accounts-editor-servers-pane.vala
+++ b/src/client/accounts/accounts-editor-servers-pane.vala
@@ -51,7 +51,9 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
         );
         // Only add an account provider if it is esoteric enough.
         if (this.account.imap.mediator is GoaMediator) {
-            this.details_list.add(new AccountProviderRow(this.account));
+            this.details_list.add(
+                new AccountProviderRow(editor.accounts, this.account)
+            );
         }
         this.details_list.add(new SaveDraftsRow(this.account));
 
@@ -119,14 +121,25 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
         update_header();
     }
 
+    [GtkCallback]
+    private void on_activate(Gtk.ListBoxRow row) {
+        Accounts.EditorRow<EditorServersPane> server_row =
+            row as Accounts.EditorRow<EditorServersPane>;
+        if (server_row != null) {
+            server_row.activated(this);
+        }
+    }
+
 }
 
 
 private class Accounts.AccountProviderRow :
     AccountRow<EditorServersPane,Gtk.Label> {
 
+    private Manager accounts;
 
-    public AccountProviderRow(Geary.AccountInformation account) {
+    public AccountProviderRow(Manager accounts,
+                              Geary.AccountInformation account) {
         base(
             account,
             // Translators: This label describes the program that
@@ -136,21 +149,48 @@ private class Accounts.AccountProviderRow :
             new Gtk.Label("")
         );
 
-        // Can't change this, so dim it out
-        this.value.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
-        this.set_activatable(false);
+        this.accounts = accounts;
 
         update();
     }
 
     public override void update() {
         string? source = null;
+        bool enabled = false;
         if (this.account.imap.mediator is GoaMediator) {
             source = _("GNOME Online Accounts");
+            enabled = true;
         } else {
             source = _("Geary");
         }
+
         this.value.set_text(source);
+        this.set_activatable(enabled);
+        Gtk.StyleContext style = this.value.get_style_context();
+        if (enabled) {
+            style.remove_class(Gtk.STYLE_CLASS_DIM_LABEL);
+        } else {
+            style.add_class(Gtk.STYLE_CLASS_DIM_LABEL);
+        }
+    }
+
+    public override void activated(EditorServersPane pane) {
+        if (this.accounts.is_goa_account(this.account)) {
+            this.accounts.show_goa_account.begin(
+                account, null,
+                (obj, res) => {
+                    try {
+                        this.accounts.show_goa_account.end(res);
+                    } catch (GLib.Error err) {
+                        // XXX display an error to the user
+                        debug(
+                            "Failed to show GOA account \"%s\": %s",
+                            account.id,
+                            err.message
+                        );
+                    }
+                });
+        }
     }
 
 }
diff --git a/src/client/accounts/accounts-editor.vala b/src/client/accounts/accounts-editor.vala
index f69c116e..9f37b86b 100644
--- a/src/client/accounts/accounts-editor.vala
+++ b/src/client/accounts/accounts-editor.vala
@@ -27,8 +27,10 @@ public class Accounts.Editor : Gtk.Dialog {
     }
 
 
-    private SimpleActionGroup actions = new SimpleActionGroup();
+    internal Manager accounts { get; private set; }
+
 
+    private SimpleActionGroup actions = new SimpleActionGroup();
 
     private Gtk.Stack editor_panes = new Gtk.Stack();
     private EditorListPane editor_list_pane;
@@ -39,6 +41,7 @@ public class Accounts.Editor : Gtk.Dialog {
 
     public Editor(GearyApplication application, Gtk.Window parent) {
         this.application = application;
+        this.accounts = application.controller.account_manager;
 
         set_default_size(700, 450);
         set_icon_name(GearyApplication.APP_ID);
diff --git a/src/client/accounts/accounts-manager.vala b/src/client/accounts/accounts-manager.vala
index 8a6fed26..fe53b3c4 100644
--- a/src/client/accounts/accounts-manager.vala
+++ b/src/client/accounts/accounts-manager.vala
@@ -417,6 +417,56 @@ public class Accounts.Manager : GLib.Object {
         }
     }
 
+    /**
+     * Determines if an account is a GOA account or not.
+     */
+    public bool is_goa_account(Geary.AccountInformation account) {
+        return (account.imap is GoaServiceInformation);
+    }
+
+    /**
+     * Opens GNOME Settings to add an account of a particular type.
+     *
+     * Throws an error if it was not possible to open GNOME Settings,
+     * or if the given type is not supported for by GOA.
+     */
+    public async void add_goa_account(Geary.ServiceProvider type,
+                                      GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        switch (type) {
+        case Geary.ServiceProvider.GMAIL:
+            yield open_goa_settings("add", "google", cancellable);
+            break;
+
+        case Geary.ServiceProvider.OUTLOOK:
+            yield open_goa_settings("add", "windows_live", cancellable);
+            break;
+
+        default:
+            throw new Error.INVALID("Not supported for GOA");
+        }
+    }
+
+    /**
+     * Opens GOA settings for the given account in GNOME Settings.
+     *
+     * Throws an error if it was not possible to open GNOME Settings,
+     * or if the given account is not backed by GOA.
+     */
+    public async void show_goa_account(Geary.AccountInformation account,
+                                       GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        GoaServiceInformation? goa_service =
+           account.imap as GoaServiceInformation;
+        if (goa_service == null) {
+            throw new Error.INVALID("Not a GOA Account");
+        }
+
+        yield open_goa_settings(
+            goa_service.account.account.id, null, cancellable
+        );
+    }
+
     /**
      * Loads an account info from a config directory.
      *
@@ -864,6 +914,59 @@ public class Accounts.Manager : GLib.Object {
         }
     }
 
+    private async void open_goa_settings(string action,
+                                         string? param,
+                                         GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        // This method was based on the implementation from:
+        // https://gitlab.gnome.org/GNOME/gnome-calendar/blob/master/src/gcal-source-dialog.c,
+        // Courtesy Georges Basile Stavracas Neto <georges stavracas gmail com>
+        GLib.DBusProxy settings = yield new GLib.DBusProxy.for_bus(
+            GLib.BusType.SESSION,
+            GLib.DBusProxyFlags.NONE,
+            null,
+            "org.gnome.ControlCenter",
+            "/org/gnome/ControlCenter",
+            "org.gtk.Actions",
+            cancellable
+        );
+
+        // @s "launch-panel"
+        // @av [<@(sav) ("online-accounts", [<@s "add">, <@s "google">])>]
+        // @a{sv} {}
+
+        GLib.Variant[] args = new GLib.Variant[] {
+            new GLib.Variant.variant(new GLib.Variant.string(action))
+        };
+        if (param != null) {
+            args += new GLib.Variant.variant(new GLib.Variant.string(param));
+        }
+
+        GLib.Variant command = new GLib.Variant.tuple(
+            new GLib.Variant[] {
+                new GLib.Variant.string("online-accounts"),
+                new GLib.Variant.array(GLib.VariantType.VARIANT, args)
+            }
+        );
+
+        GLib.Variant params = new GLib.Variant.tuple(
+            new GLib.Variant[] {
+                new GLib.Variant.string("launch-panel"),
+                new GLib.Variant.array(
+                    GLib.VariantType.VARIANT,
+                    new GLib.Variant[] {
+                        new GLib.Variant.variant(command)
+                    }
+                ),
+                new GLib.Variant("a{sv}")
+            }
+        );
+
+        yield settings.call(
+            "Activate", params, GLib.DBusCallFlags.NONE, -1, cancellable
+        );
+    }
+
     private void on_goa_account_added(Goa.Object account) {
         // XXX get a cancellable for this.
         this.create_goa_account.begin(account, null);
diff --git a/src/client/accounts/goa-service-information.vala 
b/src/client/accounts/goa-service-information.vala
index d976a0c6..06e81f2a 100644
--- a/src/client/accounts/goa-service-information.vala
+++ b/src/client/accounts/goa-service-information.vala
@@ -10,7 +10,7 @@
 public class GoaServiceInformation : Geary.ServiceInformation {
 
 
-    private Goa.Object account;
+    internal Goa.Object account { get; private set; }
 
     public GoaServiceInformation(Geary.Protocol protocol,
                                  GoaMediator mediator,
diff --git a/ui/accounts_editor_edit_pane.ui b/ui/accounts_editor_edit_pane.ui
index cd02476b..b59a88b7 100644
--- a/ui/accounts_editor_edit_pane.ui
+++ b/ui/accounts_editor_edit_pane.ui
@@ -254,7 +254,7 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkButton">
+                      <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>
diff --git a/ui/accounts_editor_servers_pane.ui b/ui/accounts_editor_servers_pane.ui
index f2e5da9f..f54e07f2 100644
--- a/ui/accounts_editor_servers_pane.ui
+++ b/ui/accounts_editor_servers_pane.ui
@@ -93,6 +93,7 @@
                         <property name="can_focus">False</property>
                         <property name="selection_mode">none</property>
                         <signal name="keynav-failed" handler="on_list_keynav_failed" swapped="no"/>
+                        <signal name="row-activated" handler="on_activate" swapped="no"/>
                       </object>
                     </child>
                     <child type="label_item">
@@ -132,6 +133,7 @@
                         <property name="can_focus">False</property>
                         <property name="selection_mode">none</property>
                         <signal name="keynav-failed" handler="on_list_keynav_failed" swapped="no"/>
+                        <signal name="row-activated" handler="on_activate" swapped="no"/>
                       </object>
                     </child>
                     <child type="label_item">
@@ -171,6 +173,7 @@
                         <property name="can_focus">False</property>
                         <property name="selection_mode">none</property>
                         <signal name="keynav-failed" handler="on_list_keynav_failed" swapped="no"/>
+                        <signal name="row-activated" handler="on_activate" swapped="no"/>
                       </object>
                     </child>
                     <child type="label_item">


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