From 3c06c0969e983a61510184a04842b1beae2ae497 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Sun, 9 Sep 2018 18:39:44 +1000 Subject: [PATCH] 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. --- .../accounts/accounts-editor-edit-pane.vala | 11 +- .../accounts/accounts-editor-list-pane.vala | 30 ++++- .../accounts-editor-servers-pane.vala | 50 ++++++++- src/client/accounts/accounts-editor.vala | 5 +- src/client/accounts/accounts-manager.vala | 103 ++++++++++++++++++ .../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 8ec931e7..ebef8fc6 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 { } 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 server_row = + row as Accounts.EditorRow; + if (server_row != null) { + server_row.activated(this); + } + } + } private class Accounts.AccountProviderRow : AccountRow { + 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,9 +27,11 @@ 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 + 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 @@ - + Remove Account True True 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 @@ False none + @@ -132,6 +133,7 @@ False none + @@ -171,6 +173,7 @@ False none +