[geary/wip/714104-refine-account-dialog: 140/180] Add initial replacement account server details pane.



commit a6ed03c4df479cd2c5c54bbe16f424acb663d795
Author: Michael James Gratton <mike vee net>
Date:   Mon Jun 4 18:28:22 2018 +1000

    Add initial replacement account server details pane.

 po/POTFILES.in                                     |   2 +
 src/client/accounts/accounts-editor-edit-pane.vala |   2 +-
 src/client/accounts/accounts-editor-row.vala       |   1 +
 .../accounts/accounts-editor-servers-pane.vala     | 413 +++++++++++++++++++++
 src/client/meson.build                             |   1 +
 ui/accounts_editor_servers_pane.ui                 | 138 +++++++
 ui/geary.css                                       |  39 +-
 ui/org.gnome.Geary.gresource.xml                   |   1 +
 8 files changed, 594 insertions(+), 3 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6e2e5fc4..0eee4f71 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -21,6 +21,7 @@ src/client/accounts/accounts-editor.vala
 src/client/accounts/accounts-editor-edit-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/add-edit-page.vala
 src/client/accounts/editor.vala
 src/client/accounts/goa-service-information.vala
@@ -413,6 +414,7 @@ ui/account_spinner.glade
 ui/accounts_editor.ui
 ui/accounts_editor_edit_pane.ui
 ui/accounts_editor_remove_pane.ui
+ui/accounts_editor_servers_pane.ui
 ui/certificate_warning_dialog.glade
 ui/composer-headerbar.ui
 ui/composer-link-popover.ui
diff --git a/src/client/accounts/accounts-editor-edit-pane.vala 
b/src/client/accounts/accounts-editor-edit-pane.vala
index 2807eb51..b46c61d4 100644
--- a/src/client/accounts/accounts-editor-edit-pane.vala
+++ b/src/client/accounts/accounts-editor-edit-pane.vala
@@ -90,7 +90,7 @@ public class Accounts.EditorEditPane : Gtk.Grid {
 
     [GtkCallback]
     private void on_server_settings_clicked() {
-
+        this.editor.push(new EditorServersPane(this.editor, this.account));
     }
 
     [GtkCallback]
diff --git a/src/client/accounts/accounts-editor-row.vala b/src/client/accounts/accounts-editor-row.vala
index f142897b..0b9159eb 100644
--- a/src/client/accounts/accounts-editor-row.vala
+++ b/src/client/accounts/accounts-editor-row.vala
@@ -55,6 +55,7 @@ internal class Accounts.AddRow : EditorRow {
 
 
     public AddRow() {
+        get_style_context().add_class("geary-add-row");
         Gtk.Image add_icon = new Gtk.Image.from_icon_name(
             "list-add-symbolic", Gtk.IconSize.BUTTON
         );
diff --git a/src/client/accounts/accounts-editor-servers-pane.vala 
b/src/client/accounts/accounts-editor-servers-pane.vala
new file mode 100644
index 00000000..ebb4ec15
--- /dev/null
+++ b/src/client/accounts/accounts-editor-servers-pane.vala
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 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.
+ */
+
+/**
+ * The main account editor window.
+ */
+[GtkTemplate (ui = "/org/gnome/Geary/accounts_editor_servers_pane.ui")]
+public class Accounts.EditorServersPane : Gtk.Grid {
+
+
+    private weak Editor editor; // circular ref
+    private Geary.AccountInformation account;
+
+    [GtkChild]
+    private Gtk.ListBox details_list;
+
+    [GtkChild]
+    private Gtk.ListBox receiving_list;
+
+    [GtkChild]
+    private Gtk.ListBox sending_list;
+
+
+    public EditorServersPane(Editor editor, Geary.AccountInformation account) {
+        this.editor = editor;
+        this.account = account;
+
+        this.details_list.set_header_func(Editor.seperator_headers);
+        this.details_list.add(new ServiceProviderRow(this.account));
+        // 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 EmailPrefetchRow(this.account));
+        this.details_list.add(new SaveDraftsRow(this.account));
+
+        this.receiving_list.set_header_func(Editor.seperator_headers);
+        build_service(account.imap, this.receiving_list);
+
+        this.sending_list.set_header_func(Editor.seperator_headers);
+        build_service(account.smtp, this.sending_list);
+    }
+
+    private void build_service(Geary.ServiceInformation service,
+                               Gtk.ListBox settings_list) {
+        settings_list.add(new ServiceHostRow(this.account, service));
+        settings_list.add(new ServiceSecurityRow(this.account, service));
+        settings_list.add(new ServiceAuthRow(this.account, service));
+    }
+
+}
+
+
+private abstract class Accounts.ServerAccountRow<V> : LabelledEditorRow {
+
+
+    protected Geary.AccountInformation account;
+
+    protected V value;
+
+
+    public ServerAccountRow(Geary.AccountInformation account,
+                            string label,
+                            V value) {
+        base(label);
+        this.account = account;
+
+        set_dim_label(true);
+
+        this.value = value;
+
+        Gtk.Widget? widget = value as Gtk.Widget;
+        if (widget != null) {
+            widget.valign = Gtk.Align.CENTER;
+            widget.show();
+            this.layout.add(widget);
+        }
+    }
+
+    public abstract void update();
+
+}
+
+
+private class Accounts.ServiceProviderRow : ServerAccountRow<Gtk.Label> {
+
+
+    public ServiceProviderRow(Geary.AccountInformation account) {
+        base(
+            account,
+            // Translators: This label describes service hosting the
+            // email account, e.g. GMail, Yahoo, Outlook.com, or some
+            // other generic IMAP service.
+            _("Service provider"),
+            new Gtk.Label("")
+        );
+
+        update();
+    }
+
+    public override void update() {
+        string? details = this.account.service_label;
+        switch (this.account.service_provider) {
+        case Geary.ServiceProvider.GMAIL:
+            details = _("GMail");
+            break;
+
+        case Geary.ServiceProvider.OUTLOOK:
+            details = _("Outlook.com");
+            break;
+
+        case Geary.ServiceProvider.YAHOO:
+            details = _("Yahoo");
+            break;
+        }
+        this.value.set_text(details);
+        // Can't change this, so dim it out
+        this.value.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
+    }
+
+}
+
+
+private class Accounts.AccountProviderRow : ServerAccountRow<Gtk.Label> {
+
+
+    public AccountProviderRow(Geary.AccountInformation account) {
+        base(
+            account,
+            // Translators: This label describes the program that
+            // created the account, e.g. an SSO service like GOA, or
+            // locally by Geary.
+            _("Account source"),
+            new Gtk.Label("")
+        );
+
+        update();
+    }
+
+    public override void update() {
+        string? source = null;
+        if (this.account.imap.mediator is GoaMediator) {
+            source = _("GNOME Online Accounts");
+        } else {
+            source = _("Geary");
+        }
+        this.value.set_text(source);
+        // Can't change this, so dim it out
+        this.value.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
+    }
+
+}
+
+
+private class Accounts.SaveDraftsRow : ServerAccountRow<Gtk.Switch> {
+
+
+    public SaveDraftsRow(Geary.AccountInformation account) {
+        base(
+            account,
+            // Translators: This label describes an account
+            // preference.
+            _("Save drafts on server"),
+            new Gtk.Switch()
+        );
+
+        update();
+    }
+
+    public override void update() {
+        this.value.state = this.account.save_drafts;
+    }
+
+}
+
+
+private class Accounts.EmailPrefetchRow : ServerAccountRow<Gtk.ComboBoxText> {
+
+
+    private static bool row_separator(Gtk.TreeModel model, Gtk.TreeIter iter) {
+        GLib.Value v;
+        model.get_value(iter, 0, out v);
+        return v.get_string() == ".";
+    }
+
+
+    public EmailPrefetchRow(Geary.AccountInformation account) {
+        Gtk.ComboBoxText combo = new Gtk.ComboBoxText();
+        combo.set_row_separator_func(row_separator);
+        combo.append("14", _("2 weeks back")); // IDs are # of days
+        combo.append("30", _("1 month back"));
+        combo.append("90", _("3 months back"));
+        combo.append("180", _("6 months back"));
+        combo.append("365", _("1 year back"));
+        combo.append("730", _("2 years back"));
+        combo.append("1461", _("4 years back"));
+        combo.append(".", "."); // Separator
+        combo.append("-1", _("Everything"));
+
+        base(
+            account,
+            // Translators: This label describes the account
+            // preference for the length of time (weeks, months or
+            // years) that past email should be downloaded.
+            _("Download mail"),
+            combo
+        );
+
+        update();
+    }
+
+    public override void update() {
+        this.value.set_active_id(this.account.prefetch_period_days.to_string());
+    }
+
+}
+
+
+private abstract class Accounts.ServerServiceRow<V> : ServerAccountRow<V> {
+
+
+    protected Geary.ServiceInformation service;
+
+    public virtual bool is_value_editable {
+        get {
+            return (
+                this.account.service_provider == Geary.ServiceProvider.OTHER &&
+                !this.is_goa_account
+            );
+        }
+    }
+
+    // XXX convenience method until we get a better way of doing this.
+    protected bool is_goa_account {
+        get { return (this.service.mediator is GoaMediator); }
+    }
+
+
+    public ServerServiceRow(Geary.AccountInformation account,
+                            Geary.ServiceInformation service,
+                            string label,
+                            V value) {
+        base(account, label, value);
+        this.service = service;
+
+        Gtk.Widget? widget = value as Gtk.Widget;
+        if (widget != null && !this.is_value_editable) {
+            if (widget is Gtk.Label) {
+                widget.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
+            } else {
+                widget.set_sensitive(false);
+            }
+        }
+    }
+
+}
+
+
+private class Accounts.ServiceHostRow : ServerServiceRow<Gtk.Label> {
+
+    public ServiceHostRow(Geary.AccountInformation account,
+                          Geary.ServiceInformation service) {
+        string label = _("Unknown");
+        switch (service.protocol) {
+        case Geary.Protocol.IMAP:
+            // Translators: This label describes the host name or IP
+            // address and port used by an account's IMAP service.
+            label = _("IMAP server");
+            break;
+
+        case Geary.Protocol.SMTP:
+            // Translators: This label describes the host name or IP
+            // address and port used by an account's SMTP service.
+            label = _("SMTP server");
+            break;
+        }
+
+        base(
+            account,
+            service,
+            label,
+            new Gtk.Label("")
+        );
+
+        update();
+    }
+
+    public override void update() {
+        this.value.set_text(
+            Geary.String.is_empty(this.service.host)
+                ? _("None")
+                : "%s:%d".printf(this.service.host, this.service.port)
+        );
+    }
+
+}
+
+
+private class Accounts.ServiceSecurityRow :
+    ServerServiceRow<Gtk.ComboBoxText> {
+
+    private const string INSECURE_ICON = "channel-insecure-symbolic";
+    private const string SECURE_ICON = "channel-secure-symbolic";
+
+    public ServiceSecurityRow(Geary.AccountInformation account,
+                              Geary.ServiceInformation service) {
+        Gtk.ListStore store = new Gtk.ListStore(
+            3, typeof(string), typeof(string), typeof(string)
+        );
+               Gtk.TreeIter iter;
+               store.append(out iter);
+               store.set(iter, 0, "none", 1, INSECURE_ICON, 2, _("None"));
+               store.append(out iter);
+               store.set(iter, 0, "start-tls", 1, SECURE_ICON, 2, _("StartTLS"));
+               store.append(out iter);
+               store.set(iter, 0, "tls", 1, SECURE_ICON, 2, _("TLS"));
+
+        Gtk.ComboBox combo = new Gtk.ComboBox.with_model(store);
+        combo.set_id_column(0);
+
+        Gtk.CellRendererText text_renderer = new Gtk.CellRendererText();
+               combo.pack_start(text_renderer, true);
+               combo.add_attribute(text_renderer, "text", 2);
+
+        Gtk.CellRendererPixbuf icon_renderer = new Gtk.CellRendererPixbuf();
+               combo.pack_start(icon_renderer, true);
+               combo.add_attribute(icon_renderer, "icon_name", 1);
+
+        base(
+            account,
+            service,
+            // Translators: This label describes what form of secure
+            // connection (TLS, StartTLS, etc) used by an account's
+            // IMAP or SMTP service.
+            _("Transport security"),
+            combo
+        );
+
+        update();
+    }
+
+    public override void update() {
+        if (this.service.use_ssl) {
+            this.value.set_active_id("tls");
+        } else if (this.service.use_starttls) {
+            this.value.set_active_id("start-tls");
+        } else {
+            this.value.set_active_id("none");
+        }
+    }
+
+}
+
+
+private class Accounts.ServiceAuthRow : ServerServiceRow<Gtk.Label> {
+
+    public ServiceAuthRow(Geary.AccountInformation account,
+                          Geary.ServiceInformation service) {
+        base(
+            account,
+            service,
+            // Translators: This label describes the authentication
+            // scheme used by an account's IMAP or SMTP service.
+            _("Login"),
+            new Gtk.Label("")
+        );
+
+        update();
+    }
+
+    public override void update() {
+        string? label = null;
+        if (this.service.credentials != null) {
+            string method = _("Unknown");
+            switch (this.service.credentials.supported_method) {
+            case Geary.Credentials.Method.PASSWORD:
+                // Translators: This is used when an account's IMAP or
+                // SMTP service uses password auth. The string
+                // replacement is the service's login name.
+                method = _("%s with password");
+                break;
+
+            case Geary.Credentials.Method.OAUTH2:
+                // Translators: This is used when an account's IMAP or
+                // SMTP service uses OAuth2. The string replacement is
+                // the service's login name.
+                method = _("%s via OAuth2");
+                break;
+            }
+
+            string? login = this.service.credentials.user;
+            if (Geary.String.is_empty(login)) {
+                login = _("Unknown");
+            }
+
+            label = method.printf(login);
+        } else if (this.service.protocol == Geary.Protocol.SMTP &&
+                   this.service.smtp_use_imap_credentials) {
+            label = _("Use IMAP server login");
+        } else {
+            // Translators: This is used when no auth scheme is used
+            // by an account's IMAP or SMTP service.
+            label = _("None");
+        }
+        this.value.set_text(label);
+    }
+
+}
diff --git a/src/client/meson.build b/src/client/meson.build
index 619a41de..e106bb86 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -23,6 +23,7 @@ geary_client_vala_sources = files(
   'accounts/accounts-editor-edit-pane.vala',
   'accounts/accounts-editor-remove-pane.vala',
   'accounts/accounts-editor-row.vala',
+  'accounts/accounts-editor-servers-pane.vala',
   'accounts/add-edit-page.vala',
   'accounts/goa-service-information.vala',
   'accounts/local-service-information.vala',
diff --git a/ui/accounts_editor_servers_pane.ui b/ui/accounts_editor_servers_pane.ui
new file mode 100644
index 00000000..9b56ad9f
--- /dev/null
+++ b/ui/accounts_editor_servers_pane.ui
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.0 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="AccountsEditorServersPane" parent="GtkGrid">
+    <property name="name">1</property>
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+        <property name="hscrollbar_policy">never</property>
+        <property name="min_content_height">400</property>
+        <child>
+          <object class="GtkViewport">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkGrid">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkFrame">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkListBox" id="receiving_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="selection_mode">none</property>
+                      </object>
+                    </child>
+                    <child type="label_item">
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">2</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">Receiving</property>
+                    <style>
+                      <class name="geary-settings-heading"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkListBox" id="sending_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="selection_mode">none</property>
+                      </object>
+                    </child>
+                    <child type="label_item">
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">4</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">Sending</property>
+                    <style>
+                      <class name="geary-settings-heading"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkListBox" id="details_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="selection_mode">none</property>
+                      </object>
+                    </child>
+                    <child type="label_item">
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                  </packing>
+                </child>
+                <style>
+                  <class name="geary-account-view"/>
+                </style>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/ui/geary.css b/ui/geary.css
index 320b4f86..359be70b 100644
--- a/ui/geary.css
+++ b/ui/geary.css
@@ -200,8 +200,43 @@ label.geary-settings-heading {
   margin-bottom: 12px;
 }
 
-row.geary-settings  {
-  padding: 18px;
+row.geary-settings {
+  padding: 0px;
+}
+
+row.geary-settings > grid > * {
+  margin: 0px;
+  padding: 0px;
+}
+
+row.geary-settings > grid > * {
+  margin: 18px 0;
+}
+
+row.geary-settings > grid > *:first-child:dir(ltr),
+row.geary-settings > grid > *:last-child:dir(rtl) {
+  margin-left: 18px;
+}
+
+row.geary-settings > grid > *:last-child:dir(ltr),
+row.geary-settings > grid > *:first-child:dir(rtl) {
+  margin-right: 18px;
+}
+
+row.geary-settings > grid > image:dir(ltr) {
+  margin-right: 6px;
+}
+row.geary-settings > grid > image:dir(rtl) {
+  margin-left: 6px;
+}
+
+row.geary-settings > grid > combobox,
+row.geary-settings:not(.geary-add-row) > grid > image,
+row.geary-settings > grid > switch {
+  /* These use more space than labels, so set their valign to center
+  when adding them and free up some space around them here to keep a
+  consistent row height. */
+  margin: 0 12px;
 }
 
 buttonbox.geary-settings  {
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
index 5173427c..011ec159 100644
--- a/ui/org.gnome.Geary.gresource.xml
+++ b/ui/org.gnome.Geary.gresource.xml
@@ -7,6 +7,7 @@
     <file compressed="true" preprocess="xml-stripblanks">accounts_editor.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">accounts_editor_edit_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">certificate_warning_dialog.glade</file>
     <file compressed="true">client-web-view.js</file>
     <file compressed="true">client-web-view-allow-remote-images.js</file>


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