[geary/wip/714922-multiple-addresses-2: 5/5] First work on UI for adding/removing add'tl email addresses



commit 025403f0d50cb782f34d0c9c2e0445214026cd15
Author: Jim Nelson <jim yorba org>
Date:   Tue Feb 10 14:07:28 2015 -0800

    First work on UI for adding/removing add'tl email addresses

 po/POTFILES.in                                     |    2 +
 src/CMakeLists.txt                                 |    1 +
 .../accounts/account-dialog-add-edit-pane.vala     |    5 +-
 .../account-dialog-edit-alternate-emails-pane.vala |  113 ++++++++++++
 src/client/accounts/account-dialog.vala            |   17 ++
 src/client/accounts/add-edit-page.vala             |   11 ++
 src/engine/api/geary-account-information.vala      |   10 +
 ui/CMakeLists.txt                                  |    1 +
 ui/edit_alternate_emails.glade                     |  188 ++++++++++++++++++++
 ui/login.glade                                     |   13 ++-
 10 files changed, 359 insertions(+), 2 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e8e88cb..2b953c9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -4,6 +4,7 @@ desktop/geary-autostart.desktop.in
 [type: gettext/ini]desktop/geary-attach.contract.in
 src/client/accounts/account-dialog-account-list-pane.vala
 src/client/accounts/account-dialog-add-edit-pane.vala
+src/client/accounts/account-dialog-edit-alternate-emails-pane.vala
 src/client/accounts/account-dialog-pane.vala
 src/client/accounts/account-dialog-remove-confirm-pane.vala
 src/client/accounts/account-dialog-remove-fail-pane.vala
@@ -371,6 +372,7 @@ src/mailer/main.vala
 [type: gettext/glade]ui/certificate_warning_dialog.glade
 [type: gettext/glade]ui/composer_accelerators.ui
 [type: gettext/glade]ui/composer.glade
+[type: gettext/glade]ui/edit_alternate_emails.glade
 [type: gettext/glade]ui/find_bar.glade
 [type: gettext/glade]ui/login.glade
 [type: gettext/glade]ui/message.glade
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6ee272d..5c9cd27 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -317,6 +317,7 @@ client/application/secret-mediator.vala
 client/accounts/account-dialog.vala
 client/accounts/account-dialog-account-list-pane.vala
 client/accounts/account-dialog-add-edit-pane.vala
+client/accounts/account-dialog-edit-alternate-emails-pane.vala
 client/accounts/account-dialog-pane.vala
 client/accounts/account-dialog-remove-confirm-pane.vala
 client/accounts/account-dialog-remove-fail-pane.vala
diff --git a/src/client/accounts/account-dialog-add-edit-pane.vala 
b/src/client/accounts/account-dialog-add-edit-pane.vala
index 398c9eb..65d30ed 100644
--- a/src/client/accounts/account-dialog-add-edit-pane.vala
+++ b/src/client/accounts/account-dialog-add-edit-pane.vala
@@ -17,6 +17,8 @@ public class AccountDialogAddEditPane : AccountDialogPane {
     
     public signal void size_changed();
     
+    public signal void edit_alternate_emails(string email_address);
+    
     public AccountDialogAddEditPane(Gtk.Stack stack) {
         base(stack);
         
@@ -35,7 +37,8 @@ public class AccountDialogAddEditPane : AccountDialogPane {
         ok_button.clicked.connect(on_ok);
         cancel_button.clicked.connect(() => { cancel(); });
         
-        add_edit_page.size_changed.connect(() => { size_changed(); } );
+        add_edit_page.size_changed.connect(() => { size_changed(); });
+        add_edit_page.edit_alternate_emails.connect(() => { 
edit_alternate_emails(add_edit_page.email_address); });
         
         pack_start(add_edit_page);
         pack_start(button_box, false, false);
diff --git a/src/client/accounts/account-dialog-edit-alternate-emails-pane.vala 
b/src/client/accounts/account-dialog-edit-alternate-emails-pane.vala
new file mode 100644
index 0000000..64bb559
--- /dev/null
+++ b/src/client/accounts/account-dialog-edit-alternate-emails-pane.vala
@@ -0,0 +1,113 @@
+/* Copyright 2015 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+public class AccountDialogEditAlternateEmailsPane : AccountDialogPane {
+    private class ListItem : Gtk.Label {
+        public Geary.RFC822.MailboxAddress mailbox;
+        
+        public ListItem(Geary.RFC822.MailboxAddress mailbox) {
+            this.mailbox = mailbox;
+            
+            label = "<b>%s</b>".printf(mailbox.address);
+            use_markup = true;
+            ellipsize = Pango.EllipsizeMode.END;
+        }
+    }
+    
+    public string? email { get; private set; default = null; }
+    
+    public bool changed { get; private set; default = false; }
+    
+    public string? selected { get; private set; default = null; }
+    
+    private Gtk.Label title_label;
+    private Gtk.Entry email_entry;
+    private Gtk.Button add_button;
+    private Gtk.ListBox address_listbox;
+    private Gtk.ToolButton delete_button;
+    private Gtk.Button cancel_button;
+    private Gtk.Button save_button;
+    
+    private Geary.RFC822.MailboxAddress? primary_mailbox = null;
+    private Gee.HashSet<string> email_addresses = new Gee.HashSet<string>(
+        Geary.String.stri_hash, Geary.String.stri_equal);
+    
+    public signal void cancelled();
+    
+    public AccountDialogEditAlternateEmailsPane(Gtk.Stack stack) {
+        base (stack);
+        
+        Gtk.Builder builder = GearyApplication.instance.create_builder("edit_alternate_emails.glade");
+        
+        // Primary container
+        pack_start((Gtk.Widget) builder.get_object("container"));
+        
+        title_label = (Gtk.Label) builder.get_object("title_label");
+        email_entry = (Gtk.Entry) builder.get_object("email_entry");
+        add_button = (Gtk.Button) builder.get_object("add_button");
+        address_listbox = (Gtk.ListBox) builder.get_object("address_listbox");
+        delete_button = (Gtk.ToolButton) builder.get_object("delete_button");
+        cancel_button = (Gtk.Button) builder.get_object("cancel_button");
+        save_button = (Gtk.Button) builder.get_object("save_button");
+        
+        email_entry.bind_property("text", add_button, "sensitive", BindingFlags.SYNC_CREATE,
+            transform_email_to_sensitive);
+        bind_property("changed", save_button, "sensitive", BindingFlags.SYNC_CREATE);
+        bind_property("selected", delete_button, "sensitive", BindingFlags.SYNC_CREATE);
+        
+        cancel_button.clicked.connect(() => { cancelled(); });
+        add_button.clicked.connect(on_add_clicked);
+    }
+    
+    private bool transform_email_to_sensitive(Binding binding, Value source, ref Value target) {
+        target = Geary.RFC822.MailboxAddress.is_valid_address(email_entry.text);
+        
+        return true;
+    }
+    
+    public void set_account(Geary.AccountInformation account_info) {
+        email = account_info.email;
+        primary_mailbox = account_info.get_primary_mailbox_address();
+        changed = false;
+        
+        // reset/clear widgets
+        title_label.label = _("Additional addresses for %s").printf(account_info.email);
+        email_entry.text = "";
+        
+        // clear listbox
+        foreach (Gtk.Widget widget in address_listbox.get_children())
+            address_listbox.remove(widget);
+        
+        // Add all except for primary; this does not constitute a change per se
+        foreach (string email_address in account_info.get_all_email_addresses())
+            add_email_address(email_address, false);
+    }
+    
+    private void add_email_address(string email_address, bool is_change) {
+        if (email_addresses.contains(email_address))
+            return;
+        
+        if (!Geary.RFC822.MailboxAddress.is_valid_address(email_address))
+            return;
+        
+        if (Geary.String.stri_equal(email_address, primary_mailbox.address))
+            return;
+        
+        email_addresses.add(email_address);
+        
+        ListItem item = new ListItem(new Geary.RFC822.MailboxAddress(null, email_address));
+        item.show_all();
+        address_listbox.add(item);
+        
+        if (is_change)
+            changed = true;
+    }
+    
+    private void on_add_clicked() {
+        add_email_address(email_entry.text, true);
+    }
+}
+
diff --git a/src/client/accounts/account-dialog.vala b/src/client/accounts/account-dialog.vala
index 1d42763..1e48847 100644
--- a/src/client/accounts/account-dialog.vala
+++ b/src/client/accounts/account-dialog.vala
@@ -13,6 +13,7 @@ public class AccountDialog : Gtk.Dialog {
     private AccountDialogSpinnerPane spinner_pane;
     private AccountDialogRemoveConfirmPane remove_confirm_pane;
     private AccountDialogRemoveFailPane remove_fail_pane;
+    private AccountDialogEditAlternateEmailsPane edit_alternate_emails_pane;
     private Gtk.HeaderBar headerbar = new Gtk.HeaderBar();
     
     public AccountDialog(Gtk.Window parent) {
@@ -33,6 +34,7 @@ public class AccountDialog : Gtk.Dialog {
         spinner_pane = new AccountDialogSpinnerPane(stack);
         remove_confirm_pane = new AccountDialogRemoveConfirmPane(stack);
         remove_fail_pane = new AccountDialogRemoveFailPane(stack);
+        edit_alternate_emails_pane = new AccountDialogEditAlternateEmailsPane(stack);
         
         // Connect signals from pages.
         account_list_pane.add_account.connect(on_add_account);
@@ -41,9 +43,11 @@ public class AccountDialog : Gtk.Dialog {
         add_edit_pane.ok.connect(on_save_add_or_edit);
         add_edit_pane.cancel.connect(on_cancel_back_to_list);
         add_edit_pane.size_changed.connect(() => { resize(1, 1); });
+        add_edit_pane.edit_alternate_emails.connect(on_edit_alternate_emails);
         remove_confirm_pane.ok.connect(on_delete_account_confirmed);
         remove_confirm_pane.cancel.connect(on_cancel_back_to_list);
         remove_fail_pane.ok.connect(on_cancel_back_to_list);
+        edit_alternate_emails_pane.cancelled.connect(on_cancel_back_to_editor);
         
         // Set default page.
         account_list_pane.present();
@@ -132,6 +136,15 @@ public class AccountDialog : Gtk.Dialog {
         }
     }
     
+    private void on_edit_alternate_emails(string email_address) {
+        Geary.AccountInformation? account_info = get_account_info_for_email(email_address);
+        if (account_info == null)
+            return;
+        
+        edit_alternate_emails_pane.set_account(account_info);
+        edit_alternate_emails_pane.present();
+    }
+    
     private void on_delete_account_confirmed(Geary.AccountInformation? account) {
         assert(account != null); // Should not be able to happen since we checked earlier.
         
@@ -197,5 +210,9 @@ public class AccountDialog : Gtk.Dialog {
     private void on_cancel_back_to_list() {
         account_list_pane.present();
     }
+    
+    private void on_cancel_back_to_editor() {
+        add_edit_pane.present();
+    }
 }
 
diff --git a/src/client/accounts/add-edit-page.vala b/src/client/accounts/add-edit-page.vala
index 80ec59e..226a990 100644
--- a/src/client/accounts/add-edit-page.vala
+++ b/src/client/accounts/add-edit-page.vala
@@ -169,6 +169,7 @@ public class AddEditPage : Gtk.Box {
     private Gtk.ComboBoxText combo_service;
     private Gtk.CheckButton check_remember_password;
     private Gtk.CheckButton check_save_sent_mail;
+    private Gtk.Button alternate_email_button;
 
     // Signature
     private Gtk.Box composer_container;
@@ -215,6 +216,8 @@ public class AddEditPage : Gtk.Box {
     
     public signal void size_changed();
     
+    public signal void edit_alternate_emails();
+    
     public AddEditPage() {
         Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4);
         
@@ -239,6 +242,7 @@ public class AddEditPage : Gtk.Box {
         entry_password = (Gtk.Entry) builder.get_object("entry: password");
         check_remember_password = (Gtk.CheckButton) builder.get_object("check: remember_password");
         check_save_sent_mail = (Gtk.CheckButton) builder.get_object("check: save_sent_mail");
+        alternate_email_button = (Gtk.Button) builder.get_object("button: edit_alternate_email");
         label_error = (Gtk.Label) builder.get_object("label: error");
         other_info = (Gtk.Alignment) builder.get_object("container: other_info");
         
@@ -328,6 +332,7 @@ public class AddEditPage : Gtk.Box {
         check_smtp_use_imap_credentials.toggled.connect(on_changed);
         check_smtp_noauth.toggled.connect(on_changed);
         check_save_drafts.toggled.connect(on_changed);
+        alternate_email_button.clicked.connect(on_alternate_email_button_clicked);
         
         entry_email.changed.connect(on_email_changed);
         entry_password.changed.connect(on_password_changed);
@@ -496,6 +501,10 @@ public class AddEditPage : Gtk.Box {
         info_changed();
     }
     
+    private void on_alternate_email_button_clicked() {
+        edit_alternate_emails();
+    }
+    
     // Prevent non-printable characters in nickname field.
     private void on_nickname_insert_text(Gtk.Editable e, string text, int length, ref int position) {
         unichar c;
@@ -696,12 +705,14 @@ public class AddEditPage : Gtk.Box {
     // Updates UI based on various options.
     internal void update_ui() {
         base.show_all();
+        
         welcome_box.visible = mode == PageMode.WELCOME;
         entry_nickname.visible = label_nickname.visible = mode != PageMode.WELCOME;
         storage_container.visible = mode == PageMode.EDIT;
         check_save_sent_mail.visible = mode == PageMode.EDIT;
         check_save_drafts.visible = mode == PageMode.EDIT;
         composer_container.visible = mode == PageMode.EDIT;
+        alternate_email_button.visible = mode == PageMode.EDIT;
         
         if (get_service_provider() == Geary.ServiceProvider.OTHER) {
             // Display all options for custom providers.
diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala
index e87edfb..1dde784 100644
--- a/src/engine/api/geary-account-information.vala
+++ b/src/engine/api/geary-account-information.vala
@@ -60,7 +60,17 @@ public class Geary.AccountInformation : BaseObject {
     
     public string real_name { get; set; }
     public string nickname { get; set; }
+    /**
+     * The primary email address for the account.
+     *
+     * @see get_all_email_addresses
+     */
     public string email { get; set; }
+    /**
+     * A list of additional email addresses this account accepts.
+     *
+     * @see get_all_email_addresses
+     */
     public Gee.List<string>? alternate_emails { get; set; }
     public Geary.ServiceProvider service_provider { get; set; }
     public int prefetch_period_days { get; set; }
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
index bb1329f..c403483 100644
--- a/ui/CMakeLists.txt
+++ b/ui/CMakeLists.txt
@@ -8,6 +8,7 @@ install(FILES app_menu.interface DESTINATION ${UI_DEST})
 install(FILES certificate_warning_dialog.glade DESTINATION ${UI_DEST})
 install(FILES composer.glade DESTINATION ${UI_DEST})
 install(FILES composer_accelerators.ui DESTINATION ${UI_DEST})
+install(FILES edit_alternate_emails.glade DESTINATION ${UI_DEST})
 install(FILES find_bar.glade DESTINATION ${UI_DEST})
 install(FILES login.glade DESTINATION ${UI_DEST})
 install(FILES message.glade DESTINATION ${UI_DEST})
diff --git a/ui/edit_alternate_emails.glade b/ui/edit_alternate_emails.glade
new file mode 100644
index 0000000..9a43861
--- /dev/null
+++ b/ui/edit_alternate_emails.glade
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkBox" id="container">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">4</property>
+    <child>
+      <object class="GtkLabel" id="title_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_bottom">8</property>
+        <property name="label">(added in code)</property>
+        <attributes>
+          <attribute name="weight" value="bold"/>
+        </attributes>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox" id="box1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">4</property>
+        <child>
+          <object class="GtkEntry" id="email_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+            <property name="input_purpose">email</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="add_button">
+            <property name="label" translatable="yes">_Add</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="can_default">True</property>
+            <property name="has_default">True</property>
+            <property name="receives_default">True</property>
+            <property name="use_underline">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScrolledWindow" id="scrolledwindow1">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="vexpand">True</property>
+        <property name="shadow_type">in</property>
+        <child>
+          <object class="GtkViewport" id="viewport1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkListBox" id="address_listbox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="vexpand">True</property>
+                <property name="activate_on_single_click">False</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToolbar" id="toolbar1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="toolbar_style">icons</property>
+        <property name="show_arrow">False</property>
+        <property name="icon_size">2</property>
+        <child>
+          <object class="GtkToolButton" id="delete_button">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="tooltip_text" translatable="yes">Remove email address</property>
+            <property name="use_underline">True</property>
+            <property name="icon_name">list-remove-symbolic</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="homogeneous">True</property>
+          </packing>
+        </child>
+        <style>
+          <class name="inline-toolbar"/>
+        </style>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Some email services require additional addresses be 
configured on the server.  Contact your email provider for more information.</property>
+        <property name="wrap">True</property>
+        <attributes>
+          <attribute name="style" value="italic"/>
+        </attributes>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">4</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButtonBox" id="buttonbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="valign">end</property>
+        <property name="margin_top">8</property>
+        <property name="vexpand">False</property>
+        <property name="spacing">8</property>
+        <property name="homogeneous">True</property>
+        <property name="layout_style">end</property>
+        <child>
+          <object class="GtkButton" id="cancel_button">
+            <property name="label" translatable="yes">_Cancel</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="use_underline">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="save_button">
+            <property name="label" translatable="yes">_Save</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="use_underline">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">5</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/ui/login.glade b/ui/login.glade
index 1e85ad0..8eb92e3 100644
--- a/ui/login.glade
+++ b/ui/login.glade
@@ -298,7 +298,18 @@
           </packing>
         </child>
         <child>
-          <placeholder/>
+          <object class="GtkButton" id="button: edit_alternate_email">
+            <property name="label" translatable="yes">Add_itional email addresses…</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="use_underline">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">7</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
         </child>
         <child>
           <placeholder/>


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