Load more messages when scrolled to bottom. #3857
This commit is contained in:
parent
3f2a5960c7
commit
d8fe58bf46
7 changed files with 93 additions and 12 deletions
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ public class Geary.Conversations : Object {
|
|||
on_email_listed(null, null);
|
||||
} catch (Error err) {
|
||||
on_email_listed(null, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue