Closes #6201 First batch of work for account manager. "Add account" functionality is complete (though Geary will still only display one email account in the main UI)

This commit is contained in:
Eric Gregory 2013-01-22 18:23:07 -08:00
parent a3df18a590
commit e49835426c
14 changed files with 1594 additions and 996 deletions

View file

@ -202,13 +202,19 @@ client/geary-config.vala
client/geary-controller.vala
client/main.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-spinner-page.vala
client/accounts/add-edit-page.vala
client/accounts/login-dialog.vala
client/composer/composer-window.vala
client/composer/contact-entry-completion.vala
client/composer/email-entry.vala
client/composer/webview-edit-fixer.vala
client/dialogs/alert-dialog.vala
client/dialogs/login-dialog.vala
client/dialogs/password-dialog.vala
client/dialogs/preferences-dialog.vala

View file

@ -0,0 +1,95 @@
/* Copyright 2013 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.
*/
// List of accounts. Used with AccountDialog.
public class AccountDialogAccountListPane : Gtk.Box {
private Gtk.TreeView list_view;
private Gtk.ListStore list_model = new Gtk.ListStore(1, typeof (string));
private Gtk.ActionGroup actions;
public signal void add_account();
public signal void close();
public AccountDialogAccountListPane() {
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4);
Gtk.Builder builder = GearyApplication.instance.create_builder("account_list.glade");
pack_end((Gtk.Box) builder.get_object("container"));
list_view = (Gtk.TreeView) builder.get_object("account_list");
list_view.set_model(list_model);
list_view.insert_column_with_attributes (-1, "Account", new Gtk.CellRendererText (), "text", 0);
actions = (Gtk.ActionGroup) builder.get_object("account list actions");
actions.get_action("close").activate.connect(() => { close(); });
actions.get_action("add_account").activate.connect(() => { add_account(); });
// Theme hint: "join" the toolbar to the scrolled window above it.
Gtk.Toolbar toolbar = (Gtk.Toolbar) builder.get_object("toolbar");
Gtk.ScrolledWindow scroll = (Gtk.ScrolledWindow) builder.get_object("scrolledwindow");
toolbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP);
scroll.get_style_context().set_junction_sides(Gtk.JunctionSides.BOTTOM);
// Add email accounts to the list.
try {
foreach (string address in Geary.Engine.instance.get_accounts().keys)
add_account_to_list(address);
} catch (Error e) {
debug("Error enumerating accounts: %s", e.message);
}
// Watch for accounts to be added/removed.
Geary.Engine.instance.account_added.connect(on_account_added);
Geary.Engine.instance.account_removed.connect(on_account_removed);
}
private void on_account_added(Geary.AccountInformation account) {
Gtk.TreeIter? iter = list_contains(account.email);
if (iter != null)
return; // Already listed.
add_account_to_list(account.email);
}
private void on_account_removed(Geary.AccountInformation account) {
remove_account_from_list(account.email);
}
// Adds an account to the list.
// Note: does NOT check if the account is already listed.
private void add_account_to_list(string address) {
Gtk.TreeIter iter;
list_model.append(out iter);
list_model.set(iter, 0, address);
}
// Removes an account on the list.
private void remove_account_from_list(string address) {
Gtk.TreeIter? iter = list_contains(address);
if (iter == null)
return;
list_model.remove(iter);
}
// Returns TreeIter of the address in the account list, else null.
private Gtk.TreeIter? list_contains(string address) {
Gtk.TreeIter iter;
if (!list_model.get_iter_first(out iter))
return null;
do {
string list_address = "";
list_model.get(iter, 0, out list_address);
if (list_address == address)
return iter;
} while (list_model.iter_next(ref iter));
return null;
}
}

View file

@ -0,0 +1,44 @@
/* Copyright 2013 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.
*/
// Add or edit an account. Used with AccountDialog.
public class AccountDialogAddEditPane : Gtk.Box {
public AddEditPage add_edit_page { get; private set; default = new AddEditPage(); }
private Gtk.ButtonBox button_box = new Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL);
private Gtk.Button ok_button = new Gtk.Button.from_stock(Gtk.Stock.ADD);
private Gtk.Button cancel_button = new Gtk.Button.from_stock(Gtk.Stock.CANCEL);
public signal void ok(Geary.AccountInformation info);
public signal void cancel();
public signal void size_changed();
public AccountDialogAddEditPane() {
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4);
add_edit_page.show_welcome(false);
button_box.set_layout(Gtk.ButtonBoxStyle.END);
button_box.expand = false;
button_box.spacing = 6;
button_box.pack_start(cancel_button, false, false, 0);
button_box.pack_start(ok_button, false, false, 0);
ok_button.can_default = true;
ok_button.clicked.connect(on_ok);
cancel_button.clicked.connect(() => { cancel(); });
add_edit_page.size_changed.connect(() => { size_changed(); } );
pack_start(add_edit_page);
pack_start(button_box);
}
private void on_ok() {
ok(add_edit_page.get_account_information());
}
}

View file

@ -0,0 +1,78 @@
/* Copyright 2013 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 AccountDialog : Gtk.Dialog {
private const int MARGIN = 12;
private Gtk.Notebook notebook = new Gtk.Notebook();
private AccountDialogAccountListPane account_list_pane = new AccountDialogAccountListPane();
private AccountDialogAddEditPane add_edit_pane = new AccountDialogAddEditPane();
private AccountSpinnerPage spinner_pane = new AccountSpinnerPage();
private int add_edit_page_number;
private int account_list_page_number;
private int spinner_page_number;
public AccountDialog() {
set_size_request(450, -1); // Sets min size.
title = _("Accounts");
get_content_area().margin_top = MARGIN;
get_content_area().margin_left = MARGIN;
get_content_area().margin_right = MARGIN;
// Add pages to notebook.
account_list_page_number = notebook.append_page(account_list_pane, null);
add_edit_page_number = notebook.append_page(add_edit_pane, null);
spinner_page_number = notebook.append_page(spinner_pane, null);
// Connect signals from pages.
account_list_pane.close.connect(on_close);
account_list_pane.add_account.connect(on_add_account);
add_edit_pane.ok.connect(on_add_or_edit_account);
add_edit_pane.cancel.connect(on_cancel_add_edit);
add_edit_pane.size_changed.connect(() => { resize(1, 1); });
// Set default page.
notebook.set_current_page(account_list_page_number);
notebook.show_border = false;
notebook.show_tabs = false;
get_content_area().pack_start(notebook, true, true, 0);
notebook.show_all(); // Required due to longstanding Gtk.Notebook bug
}
private void on_close() {
response(Gtk.ResponseType.CLOSE);
}
private void on_add_account() {
notebook.set_current_page(add_edit_page_number);
}
private void on_add_or_edit_account(Geary.AccountInformation info) {
// TODO: Edit existing account.
// Show the busy spinner.
notebook.set_current_page(spinner_page_number);
// Validate account.
GearyApplication.instance.validate_async.begin(info, null, on_add_or_edit_account_completed);
}
private void on_add_or_edit_account_completed(Object? source, AsyncResult result) {
// If account was successfully added return to the account list. Otherwise, go back to the
// account add page so the user can try again.
if (GearyApplication.instance.validate_async.end(result))
notebook.set_current_page(account_list_page_number);
else
notebook.set_current_page(add_edit_page_number);
}
private void on_cancel_add_edit() {
notebook.set_current_page(account_list_page_number);
}
}

View file

@ -0,0 +1,16 @@
/* Copyright 2013 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.
*/
// Shows a simple spinner and a message indicating the account is being validated.
public class AccountSpinnerPage : Gtk.Box {
public AccountSpinnerPage() {
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4);
Gtk.Builder builder = GearyApplication.instance.create_builder("account_spinner.glade");
pack_end((Gtk.Box) builder.get_object("container"));
}
}

View file

@ -0,0 +1,470 @@
/* Copyright 2011-2013 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.
*/
// Page for adding or editing an account.
public class AddEditPage : Gtk.Box {
public string real_name {
get { return entry_real_name.text; }
set { entry_real_name.text = value; }
}
public string email_address {
get { return entry_email.text; }
set { entry_email.text = value; }
}
public string password {
get { return entry_password.text; }
set { entry_password.text = value; }
}
public string imap_username {
get { return entry_imap_username.text; }
set { entry_imap_username.text = value; }
}
public string imap_password {
get { return entry_imap_password.text; }
set { entry_imap_password.text = value; }
}
public bool remember_password {
get { return check_remember_password.active; }
set { check_remember_password.active = value; }
}
public string smtp_username {
get { return entry_smtp_username.text; }
set { entry_smtp_username.text = value; }
}
public string smtp_password {
get { return entry_smtp_password.text; }
set { entry_smtp_password.text = value; }
}
public string imap_host {
get { return entry_imap_host.text; }
set { entry_imap_host.text = value; }
}
public uint16 imap_port {
get { return (uint16) int.parse(entry_imap_port.text.strip()); }
set { entry_imap_port.text = value.to_string(); }
}
public bool imap_ssl {
get { return combo_imap_encryption.active == Encryption.SSL; }
set {
if (value)
combo_imap_encryption.active = Encryption.SSL;
}
}
public bool imap_starttls {
get { return combo_imap_encryption.active == Encryption.STARTTLS; }
set {
if (value)
combo_imap_encryption.active = Encryption.STARTTLS;
}
}
public string smtp_host {
get { return entry_smtp_host.text; }
set { entry_smtp_host.text = value; }
}
public uint16 smtp_port {
get { return (uint16) int.parse(entry_smtp_port.text.strip()); }
set { entry_smtp_port.text = value.to_string(); }
}
public bool smtp_ssl {
get { return combo_smtp_encryption.active == Encryption.SSL; }
set {
if (value)
combo_smtp_encryption.active = Encryption.SSL;
}
}
public bool smtp_starttls {
get { return combo_smtp_encryption.active == Encryption.STARTTLS; }
set {
if (value)
combo_smtp_encryption.active = Encryption.STARTTLS;
}
}
// these are tied to the values in the Glade file
private enum Encryption {
NONE = 0,
SSL = 1,
STARTTLS = 2
}
private bool welcome_mode = true;
private Gtk.Widget container_widget;
private Gtk.Box welcome_box;
private Gtk.Entry entry_email;
private Gtk.Label label_password;
private Gtk.Entry entry_password;
private Gtk.Entry entry_real_name;
private Gtk.ComboBoxText combo_service;
private Gtk.CheckButton check_remember_password;
private Gtk.Alignment other_info;
// IMAP info widgets
private Gtk.Entry entry_imap_host;
private Gtk.Entry entry_imap_port;
private Gtk.Entry entry_imap_username;
private Gtk.Entry entry_imap_password;
private Gtk.ComboBox combo_imap_encryption;
// SMTP info widgets
private Gtk.Entry entry_smtp_host;
private Gtk.Entry entry_smtp_port;
private Gtk.Entry entry_smtp_username;
private Gtk.Entry entry_smtp_password;
private Gtk.ComboBox combo_smtp_encryption;
private bool edited_imap_port = false;
private bool edited_smtp_port = false;
public signal void info_changed();
public signal void size_changed();
public AddEditPage() {
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4);
Gtk.Builder builder = GearyApplication.instance.create_builder("login.glade");
// Primary container.
container_widget = (Gtk.Widget) builder.get_object("container");
pack_start(container_widget);
welcome_box = (Gtk.Box) builder.get_object("welcome_box");
Gtk.Label label_welcome = (Gtk.Label) builder.get_object("label-welcome");
label_welcome.set_markup("<span size=\"large\"><b>%s</b></span>\n%s".printf(
_("Welcome to Geary."), _("Enter your account information to get started.")));
entry_real_name = (Gtk.Entry) builder.get_object("entry: real_name");
combo_service = (Gtk.ComboBoxText) builder.get_object("combo: service");
entry_email = (Gtk.Entry) builder.get_object("entry: email");
label_password = (Gtk.Label) builder.get_object("label: password");
entry_password = (Gtk.Entry) builder.get_object("entry: password");
check_remember_password = (Gtk.CheckButton) builder.get_object("check: remember_password");
other_info = (Gtk.Alignment) builder.get_object("container: other_info");
// IMAP info widgets.
entry_imap_host = (Gtk.Entry) builder.get_object("entry: imap host");
entry_imap_port = (Gtk.Entry) builder.get_object("entry: imap port");
entry_imap_username = (Gtk.Entry) builder.get_object("entry: imap username");
entry_imap_password = (Gtk.Entry) builder.get_object("entry: imap password");
combo_imap_encryption = (Gtk.ComboBox) builder.get_object("combo: imap encryption");
// SMTP info widgets.
entry_smtp_host = (Gtk.Entry) builder.get_object("entry: smtp host");
entry_smtp_port = (Gtk.Entry) builder.get_object("entry: smtp port");
entry_smtp_username = (Gtk.Entry) builder.get_object("entry: smtp username");
entry_smtp_password = (Gtk.Entry) builder.get_object("entry: smtp password");
combo_smtp_encryption = (Gtk.ComboBox) builder.get_object("combo: smtp encryption");
// Build list of service providers.
foreach (Geary.ServiceProvider p in Geary.ServiceProvider.get_providers())
combo_service.append_text(p.display_name());
// Set defaults.
set_service_provider(Geary.ServiceProvider.GMAIL);
imap_ssl = true;
smtp_ssl = true;
combo_service.changed.connect(update_ui);
entry_email.changed.connect(on_changed);
entry_password.changed.connect(on_changed);
entry_real_name.changed.connect(on_changed);
check_remember_password.toggled.connect(on_changed);
combo_service.changed.connect(on_changed);
entry_imap_host.changed.connect(on_changed);
entry_imap_port.changed.connect(on_changed);
entry_imap_username.changed.connect(on_changed);
entry_imap_password.changed.connect(on_changed);
entry_smtp_host.changed.connect(on_changed);
entry_smtp_port.changed.connect(on_changed);
entry_smtp_username.changed.connect(on_changed);
entry_smtp_password.changed.connect(on_changed);
entry_email.changed.connect(on_email_changed);
entry_password.changed.connect(on_password_changed);
combo_imap_encryption.changed.connect(on_imap_encryption_changed);
combo_smtp_encryption.changed.connect(on_smtp_encryption_changed);
entry_imap_port.insert_text.connect(on_port_insert_text);
entry_smtp_port.insert_text.connect(on_port_insert_text);
// Shows/hides settings.
update_ui();
}
public void set_all_info(
string? initial_real_name = null,
string? initial_email = null,
string? initial_imap_username = null,
string? initial_imap_password = null,
bool initial_remember_password = true,
string? initial_smtp_username = null,
string? initial_smtp_password = null,
int initial_service_provider = -1,
string? initial_default_imap_host = null,
uint16 initial_default_imap_port = Geary.Imap.ClientConnection.DEFAULT_PORT_SSL,
bool initial_default_imap_ssl = true,
bool initial_default_imap_starttls = false,
string? initial_default_smtp_host = null,
uint16 initial_default_smtp_port = Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL,
bool initial_default_smtp_ssl = true,
bool initial_default_smtp_starttls = false) {
// Set defaults (other than service provider, which is set above)
real_name = initial_real_name ?? "";
email_address = initial_email ?? "";
bool use_imap_password = initial_imap_password == initial_smtp_password &&
initial_imap_password != null;
password = use_imap_password ? initial_imap_password : "";
remember_password = initial_remember_password;
// Set defaults for IMAP info
imap_host = initial_default_imap_host ?? "";
imap_port = initial_default_imap_port;
imap_username = initial_imap_username ?? "";
imap_password = initial_imap_password ?? "";
imap_ssl = initial_default_imap_ssl;
imap_starttls = initial_default_imap_starttls;
// Set defaults for SMTP info
smtp_host = initial_default_smtp_host ?? "";
smtp_port = initial_default_smtp_port;
smtp_username = initial_smtp_username ?? "";
smtp_password = initial_smtp_password ?? "";
imap_ssl = initial_default_imap_ssl;
imap_starttls = initial_default_imap_starttls;
if (Geary.String.is_empty(real_name))
entry_real_name.grab_focus();
else
entry_email.grab_focus();
}
// Puts this page into welcome mode which shows the "Welcome to Geary" message, etc.
// Default is true.
public void show_welcome(bool welcome) {
welcome_mode = welcome;
update_ui();
}
// TODO: Only reset if not manually set by user.
private void on_email_changed() {
entry_imap_username.text = entry_email.text;
entry_smtp_username.text = entry_email.text;
}
// TODO: Only reset if not manually set by user.
private void on_password_changed() {
entry_imap_password.text = entry_password.text;
entry_smtp_password.text = entry_password.text;
}
private void on_changed() {
info_changed();
}
private void on_port_insert_text(Gtk.Editable e, string text, int length, ref int position) {
// Prevent non-numerical characters and ensure port is <= uint16.MAX
if (!uint64.try_parse(text) || uint64.parse(((Gtk.Entry) e).text) > uint16.MAX) {
Signal.stop_emission_by_name(e, "insert-text");
} else {
if (e == entry_imap_port)
edited_imap_port = true;
else if (e == entry_smtp_port)
edited_smtp_port = true;
}
}
private void on_imap_encryption_changed() {
if (edited_imap_port)
return;
imap_port = get_default_imap_port();
edited_imap_port = false;
}
private uint16 get_default_imap_port() {
switch (combo_imap_encryption.active) {
case Encryption.SSL:
return Geary.Imap.ClientConnection.DEFAULT_PORT_SSL;
case Encryption.NONE:
case Encryption.STARTTLS:
default:
return Geary.Imap.ClientConnection.DEFAULT_PORT;
}
}
private void on_smtp_encryption_changed() {
if (edited_smtp_port)
return;
smtp_port = get_default_smtp_port();
edited_smtp_port = false;
}
private uint16 get_default_smtp_port() {
switch (combo_smtp_encryption.active) {
case Encryption.SSL:
return Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL;
case Encryption.STARTTLS:
return Geary.Smtp.ClientConnection.DEFAULT_PORT_STARTTLS;
case Encryption.NONE:
default:
return Geary.Smtp.ClientConnection.DEFAULT_PORT;
}
}
public bool is_complete() {
switch (get_service_provider()) {
case Geary.ServiceProvider.OTHER:
if (Geary.String.is_empty_or_whitespace(email_address) ||
Geary.String.is_empty_or_whitespace(imap_host) ||
Geary.String.is_empty_or_whitespace(imap_port.to_string()) ||
Geary.String.is_empty_or_whitespace(imap_username) ||
Geary.String.is_empty_or_whitespace(imap_password) ||
Geary.String.is_empty_or_whitespace(smtp_host) ||
Geary.String.is_empty_or_whitespace(smtp_port.to_string()) ||
Geary.String.is_empty_or_whitespace(smtp_username) ||
Geary.String.is_empty_or_whitespace(smtp_password))
return false;
break;
// GMAIL and YAHOO
default:
if (Geary.String.is_empty_or_whitespace(email_address) ||
Geary.String.is_empty_or_whitespace(password))
return false;
break;
}
return true;
}
public Geary.AccountInformation? get_account_information() {
Geary.AccountInformation account_information;
Geary.Credentials imap_credentials = new Geary.Credentials(imap_username.strip(), imap_password.strip());
Geary.Credentials smtp_credentials = new Geary.Credentials(smtp_username.strip(), smtp_password.strip());
try {
account_information = Geary.Engine.instance.get_accounts().get(email_address);
if (account_information == null)
account_information = Geary.Engine.instance.create_orphan_account(email_address);
} catch (Error err) {
debug("Unable to open account information for %s: %s", email_address, err.message);
return null;
}
account_information.real_name = real_name.strip();
account_information.imap_credentials = imap_credentials;
account_information.smtp_credentials = smtp_credentials;
account_information.imap_remember_password = remember_password;
account_information.smtp_remember_password = remember_password;
account_information.service_provider = get_service_provider();
account_information.default_imap_server_host = imap_host;
account_information.default_imap_server_port = imap_port;
account_information.default_imap_server_ssl = imap_ssl;
account_information.default_imap_server_starttls = imap_starttls;
account_information.default_smtp_server_host = smtp_host.strip();
account_information.default_smtp_server_port = smtp_port;
account_information.default_smtp_server_ssl = smtp_ssl;
account_information.default_smtp_server_starttls = smtp_starttls;
on_changed();
return account_information;
}
// Updates UI based on various options.
private void update_ui() {
base.show_all();
welcome_box.visible = welcome_mode;
if (get_service_provider() == Geary.ServiceProvider.OTHER) {
// Display all options for custom providers.
label_password.hide();
entry_password.hide();
other_info.show();
set_other_info_sensitive(true);
} else {
// For special-cased providers, only display necessary info.
label_password.show();
entry_password.show();
other_info.hide();
// TODO: Will be used by upcoming edit mode to display greyed-out other info.
set_other_info_sensitive(welcome_mode);
// For supported providers, fill out the rest of the form automagically.
imap_username = email_address;
smtp_username = email_address;
imap_password = password;
smtp_password = password;
}
size_changed();
}
public Geary.ServiceProvider get_service_provider() {
return (Geary.ServiceProvider) combo_service.get_active();
}
public void set_service_provider(Geary.ServiceProvider provider) {
foreach (Geary.ServiceProvider p in Geary.ServiceProvider.get_providers()) {
if (p == provider)
combo_service.set_active(p);
}
if (combo_service.get_active() == -1)
combo_service.set_active(0);
}
// Greys out "other info" (server settings, etc.)
public void set_other_info_sensitive(bool sensitive) {
entry_imap_host.sensitive = sensitive;
entry_imap_port.sensitive = sensitive;
entry_imap_username.sensitive = sensitive;
entry_imap_password.sensitive = sensitive;
combo_imap_encryption.sensitive = sensitive;
entry_smtp_host.sensitive = sensitive;
entry_smtp_port.sensitive = sensitive;
entry_smtp_username.sensitive = sensitive;
entry_smtp_password.sensitive = sensitive;
combo_smtp_encryption.sensitive = sensitive;
}
// Since users of this class embed it in a Gtk.Notebook, we're forced to override this method
// to prevent hidden UI elements from appearing.
public override void show_all() {
// Note that update_ui() calls base.show_all(), so no need to do that here.
update_ui();
}
}

View file

@ -0,0 +1,85 @@
/* Copyright 2011-2013 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.
*/
// Displays a dialog for collecting the user's login data.
public class LoginDialog : Gtk.Dialog {
private Gtk.Button ok_button;
private Gtk.Button cancel_button;
private AddEditPage page = new AddEditPage();
private AccountSpinnerPage spinner_page = new AccountSpinnerPage();
public LoginDialog() {
Object();
set_type_hint(Gdk.WindowTypeHint.DIALOG);
set_size_request(450, -1); // Sets min width.
page.margin = 5;
spinner_page.margin = 5;
get_content_area().pack_start(page, true, true, 0);
get_content_area().pack_start(spinner_page, true, true, 0);
spinner_page.visible = false;
page.size_changed.connect(() => { resize(1, 1); });
page.info_changed.connect(on_info_changed);
cancel_button = new Gtk.Button.from_stock(Gtk.Stock.CANCEL);
add_action_widget(cancel_button, Gtk.ResponseType.CANCEL);
ok_button = new Gtk.Button.from_stock(Gtk.Stock.ADD);
ok_button.can_default = true;
add_action_widget(ok_button, Gtk.ResponseType.OK);
set_default_response(Gtk.ResponseType.OK);
get_action_area().show_all();
on_info_changed();
}
public LoginDialog.from_account_information(Geary.AccountInformation initial_account_information) {
this();
set_account_information(initial_account_information);
}
public void set_real_name(string name) {
page.real_name = name;
}
public void set_account_information(Geary.AccountInformation info) {
page.set_all_info(info.real_name,
info.email,
info.imap_credentials.user,
info.imap_credentials.pass,
info.imap_remember_password && info.smtp_remember_password,
info.smtp_credentials.user,
info.smtp_credentials.pass,
info.service_provider,
info.default_imap_server_host,
info.default_imap_server_port,
info.default_imap_server_ssl,
info.default_imap_server_starttls,
info.default_smtp_server_host,
info.default_smtp_server_port,
info.default_smtp_server_ssl,
info.default_smtp_server_starttls);
}
public Geary.AccountInformation get_account_information() {
return page.get_account_information();
}
private void on_info_changed() {
if (!spinner_page.visible)
ok_button.sensitive = page.is_complete();
else
ok_button.sensitive = false;
}
// Switches between the account page and the busy spinner.
public void show_spinner(bool visible) {
spinner_page.visible = visible;
page.visible = !visible;
cancel_button.sensitive = !visible;
on_info_changed(); // sets OK button sensitivity
}
}

View file

@ -1,376 +0,0 @@
/* Copyright 2011-2012 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.
*/
// Displays a dialog for collecting the user's login data.
public class LoginDialog {
// these are tied to the values in the Glade file
private enum Encryption {
NONE = 0,
SSL = 1,
STARTTLS = 2
}
private Gtk.Dialog dialog;
private Gtk.Entry entry_email;
private Gtk.Label label_password;
private Gtk.Entry entry_password;
private Gtk.Entry entry_real_name;
private Gtk.ComboBoxText combo_service;
private Gtk.CheckButton check_remember_password;
private Gtk.Alignment other_info;
// IMAP info widgets
private Gtk.Entry entry_imap_host;
private Gtk.Entry entry_imap_port;
private Gtk.Entry entry_imap_username;
private Gtk.Entry entry_imap_password;
private Gtk.ComboBox combo_imap_encryption;
// SMTP info widgets
private Gtk.Entry entry_smtp_host;
private Gtk.Entry entry_smtp_port;
private Gtk.Entry entry_smtp_username;
private Gtk.Entry entry_smtp_password;
private Gtk.ComboBox combo_smtp_encryption;
private Gtk.Button ok_button;
private bool edited_imap_port = false;
private bool edited_smtp_port = false;
public Geary.AccountInformation account_information { get; private set; }
// TODO: Update the login dialog to use email, imap_credentials, smtp_credentials,
// imap_remember_password, and smtp_remember_password.
public LoginDialog.from_account_information(Geary.AccountInformation initial_account_information) {
this(initial_account_information.real_name,
initial_account_information.email,
initial_account_information.imap_credentials.user,
initial_account_information.imap_credentials.pass,
initial_account_information.imap_remember_password && initial_account_information.smtp_remember_password,
initial_account_information.smtp_credentials.user,
initial_account_information.smtp_credentials.pass,
initial_account_information.service_provider,
initial_account_information.default_imap_server_host,
initial_account_information.default_imap_server_port,
initial_account_information.default_imap_server_ssl,
initial_account_information.default_imap_server_starttls,
initial_account_information.default_smtp_server_host,
initial_account_information.default_smtp_server_port,
initial_account_information.default_smtp_server_ssl,
initial_account_information.default_smtp_server_starttls);
}
public LoginDialog(
string? initial_real_name = null,
string? initial_email = null,
string? initial_imap_username = null,
string? initial_imap_password = null,
bool initial_remember_password = true,
string? initial_smtp_username = null,
string? initial_smtp_password = null,
int initial_service_provider = -1,
string? initial_default_imap_host = null,
uint16 initial_default_imap_port = Geary.Imap.ClientConnection.DEFAULT_PORT_SSL,
bool initial_default_imap_ssl = true,
bool initial_default_imap_starttls = false,
string? initial_default_smtp_host = null,
uint16 initial_default_smtp_port = Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL,
bool initial_default_smtp_ssl = true,
bool initial_default_smtp_starttls = false) {
Gtk.Builder builder = GearyApplication.instance.create_builder("login.glade");
dialog = builder.get_object("LoginDialog") as Gtk.Dialog;
dialog.set_type_hint(Gdk.WindowTypeHint.DIALOG);
dialog.set_default_response(Gtk.ResponseType.OK);
Gtk.Label label_welcome = (Gtk.Label) builder.get_object("label-welcome");
label_welcome.set_markup("<span size=\"large\"><b>%s</b></span>\n%s".printf(
_("Welcome to Geary."), _("Enter your account information to get started.")));
entry_real_name = builder.get_object("entry: real_name") as Gtk.Entry;
combo_service = builder.get_object("combo: service") as Gtk.ComboBoxText;
entry_email = builder.get_object("entry: email") as Gtk.Entry;
label_password = builder.get_object("label: password") as Gtk.Label;
entry_password = builder.get_object("entry: password") as Gtk.Entry;
check_remember_password = builder.get_object("check: remember_password") as Gtk.CheckButton;
other_info = builder.get_object("container: other_info") as Gtk.Alignment;
// IMAP info widgets.
entry_imap_host = builder.get_object("entry: imap host") as Gtk.Entry;
entry_imap_port = builder.get_object("entry: imap port") as Gtk.Entry;
entry_imap_username = builder.get_object("entry: imap username") as Gtk.Entry;
entry_imap_password = builder.get_object("entry: imap password") as Gtk.Entry;
combo_imap_encryption = builder.get_object("combo: imap encryption") as Gtk.ComboBox;
// SMTP info widgets.
entry_smtp_host = builder.get_object("entry: smtp host") as Gtk.Entry;
entry_smtp_port = builder.get_object("entry: smtp port") as Gtk.Entry;
entry_smtp_username = builder.get_object("entry: smtp username") as Gtk.Entry;
entry_smtp_password = builder.get_object("entry: smtp password") as Gtk.Entry;
combo_smtp_encryption = builder.get_object("combo: smtp encryption") as Gtk.ComboBox;
combo_service.changed.connect(on_service_changed);
foreach (Geary.ServiceProvider p in Geary.ServiceProvider.get_providers()) {
combo_service.append_text(p.display_name());
if (p == initial_service_provider)
combo_service.set_active(p);
}
if (combo_service.get_active() == -1)
combo_service.set_active(0);
// Set defaults (other than service provider, which is set above)
entry_real_name.set_text(initial_real_name ?? "");
entry_email.set_text(initial_email ?? "");
bool use_imap_password = initial_imap_password == initial_smtp_password &&
initial_imap_password != null;
entry_password.set_text(use_imap_password ? initial_imap_password : "");
check_remember_password.active = initial_remember_password;
// Set defaults for IMAP info
entry_imap_host.set_text(initial_default_imap_host ?? "");
entry_imap_port.set_text(initial_default_imap_port.to_string());
entry_imap_username.set_text(initial_imap_username ?? "");
entry_imap_password.set_text(initial_imap_password ?? "");
if (initial_default_imap_ssl)
combo_imap_encryption.active = Encryption.SSL;
else if (initial_default_imap_starttls)
combo_imap_encryption.active = Encryption.STARTTLS;
else
combo_imap_encryption.active = Encryption.NONE;
// Set defaults for SMTP info
entry_smtp_host.set_text(initial_default_smtp_host ?? "");
entry_smtp_port.set_text(initial_default_smtp_port.to_string());
entry_smtp_username.set_text(initial_smtp_username ?? "");
entry_smtp_password.set_text(initial_smtp_password ?? "");
if (initial_default_smtp_ssl)
combo_smtp_encryption.active = Encryption.SSL;
else if (initial_default_smtp_starttls)
combo_smtp_encryption.active = Encryption.STARTTLS;
else
combo_smtp_encryption.active = Encryption.NONE;
if (Geary.String.is_empty(entry_real_name.text))
entry_real_name.grab_focus();
else
entry_email.grab_focus();
entry_email.changed.connect(on_changed);
entry_password.changed.connect(on_changed);
entry_real_name.changed.connect(on_changed);
check_remember_password.toggled.connect(on_changed);
combo_service.changed.connect(on_changed);
entry_imap_host.changed.connect(on_changed);
entry_imap_port.changed.connect(on_changed);
entry_imap_username.changed.connect(on_changed);
entry_imap_password.changed.connect(on_changed);
entry_smtp_host.changed.connect(on_changed);
entry_smtp_port.changed.connect(on_changed);
entry_smtp_username.changed.connect(on_changed);
entry_smtp_password.changed.connect(on_changed);
entry_email.changed.connect(on_email_changed);
entry_password.changed.connect(on_password_changed);
combo_imap_encryption.changed.connect(on_imap_encryption_changed);
combo_smtp_encryption.changed.connect(on_smtp_encryption_changed);
entry_imap_port.insert_text.connect(on_port_insert_text);
entry_smtp_port.insert_text.connect(on_port_insert_text);
dialog.add_action_widget(new Gtk.Button.from_stock(Gtk.Stock.CANCEL), Gtk.ResponseType.CANCEL);
ok_button = new Gtk.Button.from_stock(Gtk.Stock.OK);
ok_button.can_default = true;
ok_button.sensitive = is_complete();
dialog.add_action_widget(ok_button, Gtk.ResponseType.OK);
dialog.set_default_response(Gtk.ResponseType.OK);
}
// Runs the dialog.
public bool show() {
dialog.show();
dialog.get_action_area().show_all();
on_service_changed(); // shows/hides server settings
Gtk.ResponseType response = (Gtk.ResponseType) dialog.run();
if (response != Gtk.ResponseType.OK)
return false;
bool use_extra_info = get_service_provider() == Geary.ServiceProvider.OTHER;
string email = entry_email.text.strip();
string imap_username = use_extra_info ? entry_imap_username.text.strip() : email;
string imap_password = (use_extra_info ? entry_imap_password : entry_password).text.strip();
bool imap_remember_password = check_remember_password.active;
Geary.Credentials imap_credentials = new Geary.Credentials(imap_username, imap_password);
string smtp_username = use_extra_info ? entry_smtp_username.text.strip() : email;
string smtp_password = (use_extra_info ? entry_smtp_password : entry_password).text.strip();
bool smtp_remember_password = check_remember_password.active;
Geary.Credentials smtp_credentials = new Geary.Credentials(smtp_username, smtp_password);
try {
account_information = Geary.Engine.instance.get_accounts().get(email);
if (account_information == null)
account_information = Geary.Engine.instance.create_orphan_account(email);
} catch (Error err) {
debug("Unable to open account information for %s: %s", email, err.message);
return false;
}
account_information.real_name = entry_real_name.text.strip();
account_information.imap_credentials = imap_credentials;
account_information.smtp_credentials = smtp_credentials;
account_information.imap_remember_password = imap_remember_password;
account_information.smtp_remember_password = smtp_remember_password;
account_information.service_provider = get_service_provider();
account_information.default_imap_server_host = entry_imap_host.text.strip();
account_information.default_imap_server_port = (uint16) int.parse(entry_imap_port.text.strip());
account_information.default_imap_server_ssl = (combo_imap_encryption.active == Encryption.SSL);
account_information.default_imap_server_starttls = (combo_imap_encryption.active == Encryption.STARTTLS);
account_information.default_smtp_server_host = entry_smtp_host.text.strip();
account_information.default_smtp_server_port = (uint16) int.parse(entry_smtp_port.text.strip());
account_information.default_smtp_server_ssl = (combo_smtp_encryption.active == Encryption.SSL);
account_information.default_smtp_server_starttls = (combo_smtp_encryption.active == Encryption.STARTTLS);
on_changed();
dialog.destroy();
return true;
}
// TODO: Only reset if not manually set by user.
private void on_email_changed() {
entry_imap_username.text = entry_email.text;
entry_smtp_username.text = entry_email.text;
}
// TODO: Only reset if not manually set by user.
private void on_password_changed() {
entry_imap_password.text = entry_password.text;
entry_smtp_password.text = entry_password.text;
}
private void on_service_changed() {
if (get_service_provider() == Geary.ServiceProvider.OTHER) {
label_password.hide();
entry_password.hide();
check_remember_password.label = _("Re_member passwords");
other_info.show();
} else {
label_password.show();
entry_password.show();
check_remember_password.label = _("Re_member password");
other_info.hide();
dialog.resize(1, 1);
}
}
private void on_changed() {
ok_button.sensitive = is_complete();
}
private void on_port_insert_text(Gtk.Editable e, string text, int length, ref int position) {
// Prevent non-numerical characters and ensure port is <= uint16.MAX
if (!uint64.try_parse(text) || uint64.parse(((Gtk.Entry) e).text) > uint16.MAX) {
Signal.stop_emission_by_name(e, "insert-text");
} else {
if (e == entry_imap_port)
edited_imap_port = true;
else if (e == entry_smtp_port)
edited_smtp_port = true;
}
}
private void on_imap_encryption_changed() {
if (edited_imap_port)
return;
entry_imap_port.text = get_default_imap_port().to_string();
edited_imap_port = false;
}
private uint16 get_default_imap_port() {
switch (combo_imap_encryption.active) {
case Encryption.SSL:
return Geary.Imap.ClientConnection.DEFAULT_PORT_SSL;
case Encryption.NONE:
case Encryption.STARTTLS:
default:
return Geary.Imap.ClientConnection.DEFAULT_PORT;
}
}
private void on_smtp_encryption_changed() {
if (edited_smtp_port)
return;
entry_smtp_port.text = get_default_smtp_port().to_string();
edited_smtp_port = false;
}
private uint16 get_default_smtp_port() {
switch (combo_smtp_encryption.active) {
case Encryption.SSL:
return Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL;
case Encryption.STARTTLS:
return Geary.Smtp.ClientConnection.DEFAULT_PORT_STARTTLS;
case Encryption.NONE:
default:
return Geary.Smtp.ClientConnection.DEFAULT_PORT;
}
}
private Geary.ServiceProvider get_service_provider() {
return (Geary.ServiceProvider) combo_service.get_active();
}
private bool is_valid_port(string text) {
uint64 port;
if (!uint64.try_parse(text, out port))
return false;
return (port <= uint16.MAX);
}
private bool is_complete() {
switch (get_service_provider()) {
case Geary.ServiceProvider.OTHER:
if (Geary.String.is_empty_or_whitespace(entry_email.text) ||
Geary.String.is_empty_or_whitespace(entry_imap_host.text) ||
Geary.String.is_empty_or_whitespace(entry_imap_port.text) ||
Geary.String.is_empty_or_whitespace(entry_imap_username.text) ||
Geary.String.is_empty_or_whitespace(entry_imap_password.text) ||
Geary.String.is_empty_or_whitespace(entry_smtp_host.text) ||
Geary.String.is_empty_or_whitespace(entry_smtp_port.text) ||
Geary.String.is_empty_or_whitespace(entry_smtp_username.text) ||
Geary.String.is_empty_or_whitespace(entry_smtp_password.text) ||
!is_valid_port(entry_imap_port.text) ||
!is_valid_port(entry_smtp_port.text))
return false;
break;
// GMAIL and YAHOO
default:
if (Geary.String.is_empty_or_whitespace(entry_email.text) ||
Geary.String.is_empty_or_whitespace(entry_password.text))
return false;
break;
}
return true;
}
}

View file

@ -81,6 +81,8 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
private GearyController? controller = null;
private Geary.Account? account = null;
private LoginDialog? login_dialog = null;
private File exec_dir;
public GearyApplication() {
@ -193,33 +195,19 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
Cancellable? cancellable = null) {
Geary.AccountInformation? result = account_information;
do {
result = yield validate_async(result, cancellable);
result = yield validate_or_retry_async(result, cancellable);
} while (result != null);
if (login_dialog != null)
login_dialog.hide();
}
// Returns null if we are done validating, or the revised account information if we should retry.
private async Geary.AccountInformation? validate_async(Geary.AccountInformation account_information,
private async Geary.AccountInformation? validate_or_retry_async(Geary.AccountInformation account_information,
Cancellable? cancellable = null) {
bool success = false;
try {
success = yield account_information.validate_async(cancellable);
} catch (Geary.EngineError err) {
debug("Error validating account: %s", err.message);
success = false;
}
if (yield validate_async(account_information, cancellable))
return null;
if (success) {
account_information.store_async.begin(cancellable);
try {
set_account(account_information.get_account());
debug("Successfully validated account information");
return null;
} catch (Geary.EngineError err) {
debug("Unable to retrieve email account: %s", err.message);
}
}
debug("Validation failed. Prompting user for revised account information");
Geary.AccountInformation? new_account_information =
request_account_information(account_information);
@ -238,6 +226,34 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
return new_account_information;
}
// Attempts to validate and add an account. Returns true on success, else false.
public async bool validate_async(Geary.AccountInformation account_information,
Cancellable? cancellable = null) {
bool success = false;
try {
success = yield account_information.validate_async(cancellable);
} catch (Geary.EngineError err) {
debug("Error validating account: %s", err.message);
return false;
}
if (success) {
account_information.store_async.begin(cancellable);
try {
set_account(account_information.get_account());
debug("Successfully validated account information");
return true;
} catch (Geary.EngineError err) {
debug("Unable to retrieve email account: %s", err.message);
}
}
return false;
}
private void open_account(string email, string? old_imap_password, string? old_smtp_password,
PasswordTypeFlag password_flags, Cancellable? cancellable) {
Geary.AccountInformation account_information;
@ -368,17 +384,25 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
// Prompt the user for a service, real name, username, and password, and try to start Geary.
private Geary.AccountInformation? request_account_information(Geary.AccountInformation? old_info) {
Geary.AccountInformation? new_info = old_info;
if (login_dialog == null)
login_dialog = new LoginDialog(); // Create here so we know GTK is initialized.
if (new_info == null)
login_dialog.set_real_name(get_default_real_name());
else
login_dialog.set_account_information(new_info);
login_dialog.present();
for (;;) {
LoginDialog login_dialog = (new_info == null) ? new LoginDialog(get_default_real_name())
: new LoginDialog.from_account_information(new_info);
if (!login_dialog.show()) {
login_dialog.show_spinner(false);
if (login_dialog.run() != Gtk.ResponseType.OK) {
debug("User refused to enter account information. Exiting...");
exit(1);
return null;
}
new_info = login_dialog.account_information;
login_dialog.show_spinner(true);
new_info = login_dialog.get_account_information();
if ((!new_info.default_imap_server_ssl && !new_info.default_imap_server_starttls)
|| (!new_info.default_smtp_server_ssl && !new_info.default_smtp_server_starttls)) {
@ -392,7 +416,7 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
break;
}
if (new_info.imap_remember_password)
keyring_save_password(new_info.imap_credentials, PasswordType.IMAP);
else

View file

@ -18,6 +18,7 @@ public class GearyController {
public const string ACTION_ZOOM_IN = "GearyZoomIn";
public const string ACTION_ZOOM_OUT = "GearyZoomOut";
public const string ACTION_ZOOM_NORMAL = "GearyZoomNormal";
public const string ACTION_ACCOUNTS = "GearyAccounts";
public const string ACTION_PREFERENCES = "GearyPreferences";
public const string ACTION_MARK_AS_MENU = "GearyMarkAsMenuButton";
public const string ACTION_MARK_AS_READ = "GearyMarkAsRead";
@ -130,6 +131,11 @@ public class GearyController {
private Gtk.ActionEntry[] create_actions() {
Gtk.ActionEntry[] entries = new Gtk.ActionEntry[0];
Gtk.ActionEntry accounts = { ACTION_ACCOUNTS, null, TRANSLATABLE, null,
null, on_accounts };
accounts.label = _("A_ccounts");
entries += accounts;
Gtk.ActionEntry prefs = { ACTION_PREFERENCES, Gtk.Stock.PREFERENCES, TRANSLATABLE, null,
null, on_preferences };
prefs.label = _("_Preferences");
@ -700,6 +706,12 @@ public class GearyController {
clear_new_messages("on_has_toplevel_focus", null);
}
private void on_accounts() {
AccountDialog dialog = new AccountDialog();
dialog.run();
dialog.destroy();
}
private void on_preferences() {
PreferencesDialog dialog = new PreferencesDialog(GearyApplication.instance.config);
dialog.run();

109
ui/account_list.glade Normal file
View file

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkActionGroup" id="account list actions">
<child>
<object class="GtkAction" id="add_account">
<property name="icon_name">list-add-symbolic</property>
</object>
</child>
<child>
<object class="GtkAction" id="close">
<property name="stock_id">gtk-close</property>
</object>
</child>
</object>
<object class="GtkBox" id="container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="account_list">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">False</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="toolbar">
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">2</property>
<style>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToolButton" id="add_button">
<property name="related_action">add_account</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Add an account</property>
<property name="label" translatable="yes">toolbutton1</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</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="GtkButtonBox" id="buttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="spacing">5</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="close_button">
<property name="related_action">close</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
<property name="yalign">0.54000002145767212</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</interface>

64
ui/account_spinner.glade Normal file
View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkBox" id="container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">15</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinner" id="spinner">
<property name="width_request">45</property>
<property name="height_request">45</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please wait while Geary validates your account.</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</interface>

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@
If ToolbarMenu is changed, be sure to update ToolbarMenuProxy as well. See comments below.
-->
<popup name="ToolbarMenu">
<menuitem name="Accounts" action="GearyAccounts" />
<menuitem name="Preferences" action="GearyPreferences" />
<separator />
<menuitem name="Help" action="GearyHelp" />
@ -17,6 +18,7 @@
we keep a duplicate of ToolbarMenu in this .ui file to be used by the proxy.
-->
<popup name="ToolbarMenuProxy">
<menuitem name="Accounts" action="GearyAccounts" />
<menuitem name="Preferences" action="GearyPreferences" />
<separator />
<menuitem name="Help" action="GearyHelp" />