Add initial support for showing/hiding account status as it changes

Add infobars for offline, service problems, auth & cert problems. Show
offline and service problem infobars as needed.
This commit is contained in:
Michael Gratton 2018-12-30 22:40:04 +11:00 committed by Michael James Gratton
parent 62665bf782
commit e7c6da9496
3 changed files with 453 additions and 18 deletions

View file

@ -88,6 +88,29 @@ public class GearyController : Geary.BaseObject {
this.store = new Geary.App.EmailStore(account);
}
public Geary.Account.Status get_effective_status() {
Geary.Account.Status current = this.account.current_status;
Geary.Account.Status effective = 0;
if (current.is_online()) {
effective |= ONLINE;
}
if (current.has_service_problem()) {
// Only retain this flag if the problem isn't auth or
// cert related, that is handled elsewhere.
Geary.ClientService.Status incoming =
account.incoming.current_status;
Geary.ClientService.Status outgoing =
account.outgoing.current_status;
if (incoming != AUTHENTICATION_FAILED &&
incoming != TLS_VALIDATION_FAILED &&
outgoing != AUTHENTICATION_FAILED &&
outgoing != TLS_VALIDATION_FAILED) {
effective |= SERVICE_PROBLEM;
}
}
return effective;
}
}
@ -601,6 +624,9 @@ public class GearyController : Geary.BaseObject {
}
private void open_account(Geary.Account account) {
account.notify["current-status"].connect(
on_account_status_notify
);
account.report_problem.connect(on_report_problem);
connect_account_async.begin(account, cancellable_open_account);
@ -608,16 +634,18 @@ public class GearyController : Geary.BaseObject {
account.contacts_loaded.connect(list_store.set_sort_function);
}
private async void close_account(Geary.AccountInformation info) {
AccountContext? context = this.accounts.get(info);
private async void close_account(Geary.AccountInformation config) {
AccountContext? context = this.accounts.get(config);
if (context != null) {
Geary.ContactStore contact_store = context.account.get_contact_store();
ContactListStore list_store = this.contact_list_store_cache.get(contact_store);
Geary.Account account = context.account;
Geary.ContactStore contact_store = account.get_contact_store();
ContactListStore list_store =
this.contact_list_store_cache.get(contact_store);
context.account.contacts_loaded.disconnect(list_store.set_sort_function);
account.contacts_loaded.disconnect(list_store.set_sort_function);
this.contact_list_store_cache.unset(contact_store);
if (this.current_account == context.account) {
if (this.current_account == account) {
this.current_account = null;
previous_non_search_folder = null;
@ -626,9 +654,12 @@ public class GearyController : Geary.BaseObject {
cancel_folder();
}
// Stop showing errors when closing the account - the user
// doesn't care
context.account.report_problem.disconnect(on_report_problem);
// Stop updating status and showing errors when closing
// the account - the user doesn't care any more
account.report_problem.disconnect(on_report_problem);
account.notify["current-status"].disconnect(
on_account_status_notify
);
yield disconnect_account_async(context);
}
@ -858,6 +889,21 @@ public class GearyController : Geary.BaseObject {
}
}
private void update_account_status() {
Geary.Account.Status effective_status =
this.accounts.values.fold<Geary.Account.Status>(
(ctx, status) => ctx.get_effective_status() | status,
0
);
foreach (Gtk.Window window in this.application.get_windows()) {
MainWindow? main = window as MainWindow;
if (main != null) {
main.update_account_status(effective_status);
}
}
}
private void on_retry_problem(MainWindowInfoBar info_bar) {
Geary.ServiceProblemReport? service_report =
info_bar.report as Geary.ServiceProblemReport;
@ -952,6 +998,10 @@ public class GearyController : Geary.BaseObject {
report_problem(problem);
}
private void on_account_status_notify() {
update_account_status();
}
private void on_account_email_removed(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
if (folder.special_folder_type == Geary.SpecialFolderType.OUTBOX) {
main_window.status_bar.deactivate_message(StatusBar.Message.OUTBOX_SEND_FAILURE);

View file

@ -59,6 +59,19 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
[GtkChild]
private Gtk.Grid info_bar_container;
[GtkChild]
private Gtk.InfoBar offline_infobar;
[GtkChild]
private Gtk.InfoBar service_problem_infobar;
[GtkChild]
private Gtk.InfoBar auth_problem_infobar;
[GtkChild]
private Gtk.InfoBar cert_problem_infobar;
/** Fired when the shift key is pressed or released. */
public signal void on_shift_key(bool pressed);
@ -87,6 +100,23 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
base_unref();
}
/** Updates the window's account status info bars. */
public void update_account_status(Geary.Account.Status status) {
// Only ever show one at a time. Offline is primary since
// nothing else can happen when offline. Service problems are
// secondary since auth and cert problems can't be resolved
// when the service isn't talking to the server. Auth and cert
// problems are enabled elsewhere, since the controller might
// be already prompting the user about it.
this.offline_infobar.set_visible(!status.is_online());
this.service_problem_infobar.set_visible(
status.is_online() && status.has_service_problem()
);
this.auth_problem_infobar.hide();
this.cert_problem_infobar.hide();
update_infobar_frame();
}
public void show_infobar(MainWindowInfoBar info_bar) {
this.info_bar_container.add(info_bar);
this.info_bar_frame.show();
@ -443,6 +473,18 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
this.main_toolbar.folder = this.current_folder.get_display_name();
}
private void update_infobar_frame() {
// Ensure the info bar frame is shown only when it has visible
// children
bool show_frame = false;
info_bar_container.foreach((child) => {
if (child.visible) {
show_frame = true;
}
});
this.info_bar_frame.set_visible(show_frame);
}
private inline void check_shift_event(Gdk.EventKey event) {
// FIXME: it's possible the user will press two shift keys. We want
// the shift key to report as released when they release ALL of them.
@ -474,13 +516,15 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
return Gdk.EVENT_STOP;
}
[GtkCallback]
private void on_offline_infobar_response() {
this.offline_infobar.hide();
update_infobar_frame();
}
[GtkCallback]
private void on_info_bar_container_remove() {
// Ensure the info bar frame is hidden when the last info bar
// is removed from the container.
if (this.info_bar_container.get_children().length() == 0) {
this.info_bar_frame.hide();
}
update_infobar_frame();
}
}

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="MainWindow" parent="GtkApplicationWindow">
@ -9,6 +9,9 @@
<property name="show_menubar">False</property>
<signal name="delete-event" handler="on_delete_event" swapped="no"/>
<signal name="focus-in-event" handler="on_focus_event" swapped="no"/>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkOverlay" id="overlay">
<property name="visible">True</property>
@ -143,6 +146,347 @@
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<signal name="remove" handler="on_info_bar_container_remove" swapped="no"/>
<child>
<object class="GtkInfoBar" id="offline_infobar">
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_offline_infobar_response" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="offline_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Infobar title when one or more accounts are offline">Working offline</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="offline_description">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes" comments="Label and tooltip for offline infobar">Your computer does not appear to be connected to the Internet.
You will not be able to send or receive email until it is re-connected.</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Label and tooltip for offline infobar">You will not be able to send or receive email until re-connected.</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<style>
<class name="sigh"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="service_problem_infobar">
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="message_type">error</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="service_problem_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Infobar title when one or more accounts have encounted an error">Account problem</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="service_problem_description">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes" comments="Label and tooltip for account service problem infobar">Geary encountered a problem connecting to an account.
Please check your Internet connection, the server configuration and try again.</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Label and tooltip for account service problem infobar">Geary encountered a problem connecting to an account.</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<style>
<class name="sigh"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="auth_problem_infobar">
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="message_type">error</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="auth_problem_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Infobar title when one or more accounts have a login error">Login problem</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="auth_problem_description">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes" comments="Label and tooltip for authentication problem infobar">An account has reported an incorrect login or password.
Please check your login name and try again.</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Label and tooltip for authentication problem infobar">An account has reported an incorrect login or password.</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<style>
<class name="sigh"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="cert_problem_infobar">
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="message_type">warning</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="cert_problem_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Infobar title when one or more accounts have a TLS cert validation error">Security problem</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cert_problem_description">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes" comments="Label and tooltip for TLS cert validation error infobar">An account has reported an untrusted server.
Please check the server configuration and try again.</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Label and tooltip for TLS cert validation error infobar">An account has reported an untrusted server.</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<style>
<class name="sigh"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
</object>
</child>
<child type="label_item">
@ -165,8 +509,5 @@
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</template>
</interface>