Improve UX when automating folder/conversation selection

Don't select the inbox of the first account by default in MainWindow,
and provide a means of inhibiting conversation autoselect when changing
folder. This allows selecting a conversation in a different folder and
opening new folders with a specific conversation selected without
jumping to the first conversation first when the autoselect pref is
enabled.
This commit is contained in:
Michael Gratton 2019-11-18 20:27:08 +11:00
parent 68aaec3245
commit a760e26560
4 changed files with 58 additions and 27 deletions

View file

@ -516,7 +516,7 @@ public class Application.Client : Gtk.Application {
*/
public MainWindow get_active_main_window() {
if (this.last_active_main_window == null) {
this.last_active_main_window = new_main_window();
this.last_active_main_window = new_main_window(true);
}
return last_active_main_window;
}
@ -619,10 +619,16 @@ public class Application.Client : Gtk.Application {
Gee.Collection<Geary.App.Conversation>? select_conversations) {
yield create_controller();
MainWindow main = new_main_window();
bool do_select = (
select_folder != null &&
select_conversations != null &&
!select_conversations.is_empty
);
MainWindow main = new_main_window(!do_select);
main.present();
if (select_folder != null) {
if (do_select) {
if (select_conversations == null || select_conversations.is_empty) {
main.select_folder.begin(select_folder, true);
} else {
@ -789,10 +795,26 @@ public class Application.Client : Gtk.Application {
return main;
}
private MainWindow new_main_window() {
private MainWindow new_main_window(bool select_first_inbox) {
MainWindow window = new MainWindow(this);
this.controller.register_window(window);
window.focus_in_event.connect(on_main_window_focus_in);
if (select_first_inbox) {
try {
var config = this.controller.get_first_account();
if (config != null) {
var first = this.engine.get_account_instance(config);
if (first != null) {
Geary.Folder? inbox = first.get_special_folder(INBOX);
if (inbox != null) {
window.select_folder.begin(inbox, true);
}
}
}
} catch (GLib.Error error) {
debug("Error getting Inbox for first account");
}
}
return window;
}

View file

@ -310,6 +310,7 @@ internal class Application.Controller : Geary.BaseObject {
window.select_folder.begin(
null,
false,
true,
(obj, res) => {
window.select_folder.end(res);
window.close();

View file

@ -215,8 +215,8 @@ public class Application.MainWindow :
private GLib.SimpleActionGroup edit_actions = new GLib.SimpleActionGroup();
// Determines if the conversation viewer should autoselect on next
// load
// Determines if the conversation viewer should auto-mark messages
// on next load
private bool previous_selection_was_interactive = false;
// Caches the last non-search folder so it can be re-selected on
@ -424,7 +424,8 @@ public class Application.MainWindow :
* the folder list), as opposed to some side effect.
*/
public async void select_folder(Geary.Folder? to_select,
bool is_interactive) {
bool is_interactive,
bool inhibit_autoselect = false) {
if (this.selected_folder != to_select) {
// Cancel any existing folder loading
this.folder_open.cancel();
@ -461,15 +462,21 @@ public class Application.MainWindow :
select_account(to_select != null ? to_select.account : null);
this.selected_folder = to_select;
// Ensure that the folder is selected in the UI if
// this was called by something other than the
// selection changed callback. That will check to
// ensure that we're not setting it again.
if (to_select != null) {
this.folder_list.select_folder(to_select);
// Prefer the inboxes branch if it exists
if (to_select.special_folder_type != INBOX ||
!this.folder_list.select_inbox(to_select.account)) {
this.folder_list.select_folder(to_select);
}
} else {
this.folder_list.deselect_folder();
}
if (!(to_select is Geary.SearchFolder)) {
this.previous_non_search_folder = to_select;
}
@ -508,6 +515,9 @@ public class Application.MainWindow :
);
this.progress_monitor.add(conversations_model.preview_monitor);
if (inhibit_autoselect) {
this.conversation_list_view.inhibit_next_autoselect();
}
this.conversation_list_view.set_model(conversations_model);
// disable copy/move to the new folder
@ -534,7 +544,8 @@ public class Application.MainWindow :
public async void show_conversations(Geary.Folder location,
Gee.Collection<Geary.App.Conversation> to_show,
bool is_interactive) {
yield select_folder(location, is_interactive);
bool inhibit_autoselect = (location != this.selected_folder);
yield select_folder(location, is_interactive, inhibit_autoselect);
// The folder may have changed again by the type the async
// call returns, so only continue if still current
if (this.selected_folder == location) {
@ -565,7 +576,8 @@ public class Application.MainWindow :
public async void show_email(Geary.Folder location,
Gee.Collection<Geary.EmailIdentifier> to_show,
bool is_interactive) {
yield select_folder(location, is_interactive);
bool inhibit_autoselect = (location != this.selected_folder);
yield select_folder(location, is_interactive, inhibit_autoselect);
// The folder may have changed again by the type the async
// call returns, so only continue if still current
if (this.selected_folder == location) {
@ -1284,23 +1296,6 @@ public class Application.MainWindow :
foreach (Geary.Folder folder in available) {
if (Controller.should_add_folder(available, folder)) {
add_folder(folder);
if (folder.special_folder_type == INBOX) {
// Select this inbox if there isn't an existing
// folder selected and it is the inbox for the
// first account
Geary.AccountInformation? first_account =
this.application.controller.get_first_account();
if (!this.folder_list.is_any_selected() &&
folder.account.information == first_account) {
// First we try to select the Inboxes branch
// inbox if it's there, falling back to the
// main folder list.
if (!this.folder_list.select_inbox(folder.account)) {
this.folder_list.select_folder(folder);
}
}
}
}
}
}
@ -1670,6 +1665,7 @@ public class Application.MainWindow :
this.select_folder.begin(
null,
false,
true,
(obj, res) => {
this.select_folder.end(res);
destroy();

View file

@ -18,6 +18,11 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
private Gee.Set<Geary.App.Conversation> selected = new Gee.HashSet<Geary.App.Conversation>();
private Geary.IdleManager selection_update;
// Determines if the next folder scan should avoid selecting a
// conversation when autoselect is enabled
private bool should_inhibit_autoselect = false;
public signal void conversations_selected(Gee.Set<Geary.App.Conversation> selected);
// Signal for when a conversation has been double-clicked, or selected and enter is pressed.
@ -131,6 +136,10 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
return this.selected.read_only_view;
}
public void inhibit_next_autoselect() {
this.should_inhibit_autoselect = true;
}
public void scroll(Gtk.ScrollType where) {
Gtk.TreeSelection selection = get_selection();
weak Gtk.TreeModel model;
@ -197,12 +206,15 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
// nothing has been selected yet and we're not showing a
// composer.
if (this.config.autoselect &&
!this.should_inhibit_autoselect &&
get_selection().count_selected_rows() == 0) {
var parent = get_toplevel() as Application.MainWindow;
if (parent != null && !parent.has_composer) {
set_cursor(new Gtk.TreePath.from_indices(0, -1), null, false);
}
}
this.should_inhibit_autoselect = false;
}
private void on_conversations_added(bool start) {