Load more messages when scrolled to bottom. #3857

This commit is contained in:
Eric Gregory 2011-11-11 13:36:25 -08:00
parent 3f2a5960c7
commit d8fe58bf46
7 changed files with 93 additions and 12 deletions

View file

@ -31,6 +31,7 @@ public class MainWindow : Gtk.Window {
message_list_view = new MessageListView(message_list_store);
message_list_view.conversation_selected.connect(on_conversation_selected);
message_list_view.load_more.connect(on_load_more);
folder_list_view = new FolderListView(folder_list_store);
folder_list_view.folder_selected.connect(on_folder_selected);
@ -202,8 +203,10 @@ public class MainWindow : Gtk.Window {
current_conversations.lazy_load(-1, -1, Geary.Folder.ListFlags.FAST, cancellable_folder);
}
public void on_scan_started() {
debug("on scan started");
public void on_scan_started(Geary.EmailIdentifier? id, int low, int count) {
debug("on scan started. id = %s low = %d count = %d", id != null ? id.to_string() : "(null)",
low, count);
message_list_view.enable_load_more = false;
}
public void on_scan_error(Error err) {
@ -214,6 +217,7 @@ public class MainWindow : Gtk.Window {
debug("on scan completed");
do_fetch_previews.begin(cancellable_message);
message_list_view.enable_load_more = true;
}
public void on_conversations_added(Gee.Collection<Geary.Conversation> conversations) {
@ -242,6 +246,25 @@ public class MainWindow : Gtk.Window {
message_list_store.update_conversation(conversation);
}
private void on_load_more() {
debug("on_load_more");
message_list_view.enable_load_more = false;
Geary.EmailIdentifier? low_id = message_list_store.get_email_id_lowest();
current_conversations.load_by_id_async.begin(low_id, - FETCH_EMAIL_CHUNK_COUNT,
Geary.Folder.ListFlags.NONE, cancellable_folder, on_load_more_completed);
}
private void on_load_more_completed(Object? source, AsyncResult result) {
debug("on load more completed");
try {
current_conversations.load_by_id_async.end(result);
} catch (Error err) {
debug("Error, unable to load conversations: %s", err.message);
}
}
private async void do_fetch_previews(Cancellable? cancellable) throws Error {
int count = message_list_store.get_count();
for (int ctr = 0; ctr < count; ctr++) {

View file

@ -157,6 +157,23 @@ public class MessageListStore : Gtk.TreeStore {
return conversation;
}
public Geary.EmailIdentifier? get_email_id_lowest() {
Geary.EmailIdentifier? low = null;
int count = get_count();
for (int ctr = 0; ctr < count; ctr++) {
Geary.Conversation c = get_conversation_at_index(ctr);
Gee.SortedSet<Geary.Email>? mail = c.get_pool_sorted(compare_email_id_desc);
if (mail == null)
continue;
Geary.EmailIdentifier pos = mail.first().id;
if (low == null || pos.ordering < low.ordering)
low = pos;
}
return low;
}
private bool find_conversation(Geary.Conversation conversation, out Gtk.TreeIter iter) {
iter = Gtk.TreeIter();
int count = get_count();

View file

@ -5,7 +5,16 @@
*/
public class MessageListView : Gtk.TreeView {
const int LOAD_MORE_HEIGHT = 100;
public bool enable_load_more { get; set; default = true; }
// Used to avoid repeated calls to load_more(). Contains the last "upper" bound of the
// scroll adjustment seen at the call to load_more().
double last_upper = -1.0;
public signal void conversation_selected(Geary.Conversation? conversation);
public signal void load_more();
public MessageListView(MessageListStore store) {
set_model(store);
@ -18,7 +27,8 @@ public class MessageListView : Gtk.TreeView {
MessageListStore.Column.MESSAGE_DATA.to_string(), 0));
get_selection().changed.connect(on_selection_changed);
this.style_set.connect(on_style_changed);
style_set.connect(on_style_changed);
show.connect(on_show);
}
private void on_style_changed() {
@ -26,6 +36,25 @@ public class MessageListView : Gtk.TreeView {
MessageListCellRenderer.style_changed(this);
}
private void on_show() {
// Wait until we're visible to set this signal up.
get_vadjustment().value_changed.connect(on_value_changed);
}
private void on_value_changed() {
if (!enable_load_more)
return;
// Check if we're at the very bottom of the list. If we are, it's time to
// issue a load_more signal.
if (get_vadjustment().get_value() >= get_vadjustment().get_upper() -
get_vadjustment().page_size - LOAD_MORE_HEIGHT && get_vadjustment().get_upper()
> last_upper) {
load_more();
last_upper = get_vadjustment().get_upper();
}
}
private static Gtk.TreeViewColumn create_column(MessageListStore.Column column,
Gtk.CellRenderer renderer, string attr, int width = 0) {
Gtk.TreeViewColumn view_column = new Gtk.TreeViewColumn.with_attributes(column.to_string(),

View file

@ -70,6 +70,7 @@ public class MessageViewer : Gtk.Viewport {
public void add_message(Geary.Email email) {
messages.add(email);
Gtk.Builder builder = GearyApplication.instance.create_builder("message.glade");
debug("Message id: %s", email.id.to_string());
string username;
try {

View file

@ -10,3 +10,7 @@ public int compare_email(Geary.Email aenvelope, Geary.Email benvelope) {
// stabilize sort by using the mail's ordering, which is always unique in a folder
return (diff != 0) ? diff : aenvelope.id.compare(benvelope.id);
}
public int compare_email_id_desc(Geary.Email aenvelope, Geary.Email benvelope) {
return (int) (aenvelope.id.ordering - benvelope.id.ordering);
}

View file

@ -374,6 +374,7 @@ public class Geary.Conversations : Object {
on_email_listed(null, null);
} catch (Error err) {
on_email_listed(null, err);
throw err;
}
}

View file

@ -387,7 +387,7 @@ private class Geary.EngineFolder : Geary.AbstractFolder {
// because the local store caches messages starting from the newest (at the end of the list)
// to the earliest fetched by the user, need to adjust the low value to match its offset
// and range
local_low = (low - (remote_count - local_count)).clamp(1, local_count);
local_low = low - (remote_count - local_count);
} else {
normalize_span_specifiers(ref low, ref count, local_count);
local_low = low.clamp(1, local_count);
@ -397,14 +397,16 @@ private class Geary.EngineFolder : Geary.AbstractFolder {
low, count, local_count, remote_count, local_low);
Gee.List<Geary.Email>? local_list = null;
try {
local_list = yield local_folder.list_email_async(local_low, count, required_fields,
Geary.Folder.ListFlags.NONE, cancellable);
} catch (Error local_err) {
if (cb != null)
cb (null, local_err);
throw local_err;
if (local_low > 0) {
try {
local_list = yield local_folder.list_email_async(local_low, count, required_fields,
Geary.Folder.ListFlags.NONE, cancellable);
} catch (Error local_err) {
if (cb != null)
cb (null, local_err);
throw local_err;
}
}
int local_list_size = (local_list != null) ? local_list.size : 0;
@ -684,6 +686,10 @@ private class Geary.EngineFolder : Geary.AbstractFolder {
initial_id.to_string(), to_string());
}
// normalize the initial position to the remote folder's addressing
initial_position = remote_count - (local_count - initial_position);
assert(initial_position > 0);
// since count can also indicate "to earliest" or "to latest", normalize
// (count is exclusive of initial_id, hence adding/substracting one, meaning that a count
// of zero or one are accepted)