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 + * + * 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 : 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 { + + + 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 { + + + 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 { + + + 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 { + + + 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 : ServerAccountRow { + + + 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 { + + 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 { + + 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 { + + 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 @@ + + + + + + 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 @@ accounts_editor.ui accounts_editor_edit_pane.ui accounts_editor_remove_pane.ui + accounts_editor_servers_pane.ui certificate_warning_dialog.glade client-web-view.js client-web-view-allow-remote-images.js