From 9b148eefb94633832e56d9865a9265dbc7a5fe0f Mon Sep 17 00:00:00 2001 From: M66B Date: Tue, 7 Aug 2018 06:38:00 +0000 Subject: [PATCH] Added message list paging --- .idea/caches/build_file_checksums.ser | Bin 535 -> 535 bytes app/build.gradle | 5 + .../eu/faircode/email/AdapterMessage.java | 205 ++++++------------ .../java/eu/faircode/email/DaoMessage.java | 20 +- .../eu/faircode/email/FragmentMessages.java | 53 ++--- app/src/main/res/layout/item_message.xml | 12 + 6 files changed, 130 insertions(+), 165 deletions(-) diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index bd541ede8dbabcdfc426a4127f8042ba0a439150..e3fc4a70b6031e3a61a19b6caa6c03dd100a51c5 100644 GIT binary patch delta 32 qcmV+*0N?+Y1eXMmnFHuvnz5W}0TI%)>z8|8xi??Ep8&Gp2(x(eF%Mk; delta 32 ocmbQvGM#0@Oy;}X85`$hF$!j$Um)zu()cG$U;EFqS<_Q00Mj%L { +public class AdapterMessage extends PagedListAdapter { private Context context; private ViewType viewType; private boolean debug; private ExecutorService executor = Executors.newCachedThreadPool(); - private List all = new ArrayList<>(); - private List filtered = new ArrayList<>(); - enum ViewType {FOLDER, THREAD} public class ViewHolder extends RecyclerView.ViewHolder @@ -62,6 +56,7 @@ public class AdapterMessage extends RecyclerView.Adapter 1 ? View.VISIBLE : View.GONE); + } else + tvCount.setText(Helper.localizeFolderName(context, message.folderName)); + + ivAttachments.setVisibility(message.attachments > 0 ? View.VISIBLE : View.GONE); + + boolean unseen = (message.thread == null && !outbox ? message.unseen > 0 : !message.seen); + + int typeface = (unseen ? Typeface.BOLD : Typeface.NORMAL); + tvFrom.setTypeface(null, typeface); + tvTime.setTypeface(null, typeface); + tvSubject.setTypeface(null, typeface); + tvCount.setTypeface(null, typeface); + + tvFrom.setTextColor(Helper.resolveColor(context, unseen ? R.attr.colorUnread : android.R.attr.textColorSecondary)); + tvTime.setTextColor(Helper.resolveColor(context, unseen ? R.attr.colorUnread : android.R.attr.textColorSecondary)); + } + @Override public void onClick(View view) { int pos = getAdapterPosition(); if (pos == RecyclerView.NO_POSITION) return; - final TupleMessageEx message = filtered.get(pos); + final TupleMessageEx message = getItem(pos); executor.submit(new Runnable() { @Override @@ -120,102 +162,26 @@ public class AdapterMessage extends RecyclerView.Adapter messages) { - Log.i(Helper.TAG, "Set messages=" + messages.size()); - - Collections.sort(messages, new Comparator() { - @Override - public int compare(TupleMessageEx m1, TupleMessageEx m2) { - if (EntityFolder.isOutgoing(m1.folderType)) - return -Long.compare(m1.received, m2.received); - else - return -Long.compare( - m1.sent == null ? 0 : m1.sent, - m2.sent == null ? 0 : m2.sent); - } - }); - - all.clear(); - all.addAll(messages); - - DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new MessageDiffCallback(filtered, all)); - - filtered.clear(); - filtered.addAll(all); - - diff.dispatchUpdatesTo(new ListUpdateCallback() { - @Override - public void onInserted(int position, int count) { - Log.i(Helper.TAG, "Inserted @" + position + " #" + count); - } - - @Override - public void onRemoved(int position, int count) { - Log.i(Helper.TAG, "Removed @" + position + " #" + count); - } - - @Override - public void onMoved(int fromPosition, int toPosition) { - Log.i(Helper.TAG, "Moved " + fromPosition + ">" + toPosition); - } - - @Override - public void onChanged(int position, int count, Object payload) { - Log.i(Helper.TAG, "Changed @" + position + " #" + count); - } - }); - diff.dispatchUpdatesTo(AdapterMessage.this); } - private class MessageDiffCallback extends DiffUtil.Callback { - private List prev; - private List next; - - MessageDiffCallback(List prev, List next) { - this.prev = prev; - this.next = next; - } - - @Override - public int getOldListSize() { - return prev.size(); - } - - @Override - public int getNewListSize() { - return next.size(); - } - - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - TupleMessageEx m1 = prev.get(oldItemPosition); - TupleMessageEx m2 = next.get(newItemPosition); - return m1.id.equals(m2.id); - } - - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - TupleMessageEx m1 = prev.get(oldItemPosition); - TupleMessageEx m2 = next.get(newItemPosition); - return m1.equals(m2); - } - } - - @Override - public long getItemId(int position) { - return filtered.get(position).id; - } + public static final DiffUtil.ItemCallback DIFF_CALLBACK = + new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame( + @NonNull TupleMessageEx prev, @NonNull TupleMessageEx next) { + return prev.id.equals(next.id); + } - @Override - public int getItemCount() { - return filtered.size(); - } + @Override + public boolean areContentsTheSame( + @NonNull TupleMessageEx prev, @NonNull TupleMessageEx next) { + return prev.equals(next); + } + }; @Override @NonNull @@ -227,39 +193,12 @@ public class AdapterMessage extends RecyclerView.Adapter 1 ? View.VISIBLE : View.GONE); - } else - holder.tvCount.setText(Helper.localizeFolderName(context, message.folderName)); - - holder.ivAttachments.setVisibility(message.attachments > 0 ? View.VISIBLE : View.GONE); - - boolean unseen = (message.thread == null && !outbox ? message.unseen > 0 : !message.seen); - - int visibility = (unseen ? Typeface.BOLD : Typeface.NORMAL); - holder.tvFrom.setTypeface(null, visibility); - holder.tvTime.setTypeface(null, visibility); - holder.tvSubject.setTypeface(null, visibility); - holder.tvCount.setTypeface(null, visibility); - - holder.tvFrom.setTextColor(Helper.resolveColor(context, unseen ? R.attr.colorUnread : android.R.attr.textColorSecondary)); - holder.tvTime.setTextColor(Helper.resolveColor(context, unseen ? R.attr.colorUnread : android.R.attr.textColorSecondary)); - - holder.wire(); } } diff --git a/app/src/main/java/eu/faircode/email/DaoMessage.java b/app/src/main/java/eu/faircode/email/DaoMessage.java index 8bf28534..8be1ee23 100644 --- a/app/src/main/java/eu/faircode/email/DaoMessage.java +++ b/app/src/main/java/eu/faircode/email/DaoMessage.java @@ -20,6 +20,7 @@ package eu.faircode.email; */ import android.arch.lifecycle.LiveData; +import android.arch.paging.DataSource; import android.arch.persistence.room.Dao; import android.arch.persistence.room.Insert; import android.arch.persistence.room.OnConflictStrategy; @@ -39,9 +40,10 @@ public interface DaoMessage { " WHERE folder.type = '" + EntityFolder.TYPE_INBOX + "'" + " AND (NOT ui_hide OR :debug)" + " AND received IN (SELECT MAX(m.received) FROM message m WHERE m.folder = message.folder" + - " GROUP BY CASE WHEN m.thread IS NULL THEN m.id ELSE m.thread END)") + " GROUP BY CASE WHEN m.thread IS NULL THEN m.id ELSE m.thread END)" + + " ORDER BY received DESC") // in theory the message id and thread could be the same - LiveData> liveUnifiedInbox(boolean debug); + DataSource.Factory pagedUnifiedInbox(boolean debug); @Query("SELECT message.*, folder.name as folderName, folder.type as folderType" + ", (SELECT COUNT(m.id) FROM message m WHERE m.account = message.account AND m.thread = message.thread) AS count" + @@ -52,8 +54,13 @@ public interface DaoMessage { " WHERE folder.id = :folder" + " AND (NOT ui_hide OR :debug)" + " AND received IN (SELECT MAX(m.received) FROM message m WHERE m.folder = message.folder" + - " GROUP BY CASE WHEN m.thread IS NULL THEN m.id ELSE m.thread END)") - LiveData> liveMessages(long folder, boolean debug); + " GROUP BY CASE WHEN m.thread IS NULL THEN m.id ELSE m.thread END)" + + " ORDER BY CASE WHEN folder.type IN " + + "('" + EntityFolder.TYPE_OUTBOX + "'" + + ", '" + EntityFolder.TYPE_DRAFTS + "'" + + ", '" + EntityFolder.TYPE_SENT + "')" + + " THEN sent ELSE received END DESC") + DataSource.Factory pagedFolder(long folder, boolean debug); @Query("SELECT message.*, folder.name as folderName, folder.type as folderType" + ", (SELECT COUNT(m.id) FROM message m WHERE m.account = message.account AND m.thread = message.thread) AS count" + @@ -62,8 +69,9 @@ public interface DaoMessage { " FROM message" + " JOIN folder ON folder.id = message.folder" + " JOIN message m1 ON m1.id = :msgid AND m1.account = message.account AND m1.thread = message.thread" + - " WHERE NOT message.ui_hide OR :debug") - LiveData> liveThread(long msgid, boolean debug); + " WHERE NOT message.ui_hide OR :debug" + + " ORDER BY received DESC") + DataSource.Factory pagedThread(long msgid, boolean debug); @Query("SELECT * FROM message WHERE id = :id") EntityMessage getMessage(long id); diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index cfb391c1..3e7314df 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -19,7 +19,10 @@ package eu.faircode.email; Copyright 2018 by Marcel Bokhorst (M66B) */ +import android.arch.lifecycle.LiveData; import android.arch.lifecycle.Observer; +import android.arch.paging.LivePagedListBuilder; +import android.arch.paging.PagedList; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -40,8 +43,6 @@ import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; -import java.util.List; - public class FragmentMessages extends FragmentEx { private RecyclerView rvMessage; private TextView tvNoEmail; @@ -93,51 +94,51 @@ public class FragmentMessages extends FragmentEx { pbWait.setVisibility(View.VISIBLE); fab.setVisibility(View.GONE); - DB db = DB.getInstance(getContext()); - // Observe folder/messages + DB db = DB.getInstance(getContext()); + LiveData> messages; boolean debug = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("debug", false); if (thread < 0) if (folder < 0) { setSubtitle(R.string.title_folder_unified); - db.message().liveUnifiedInbox(debug).observe(this, messagesObserver); + messages = new LivePagedListBuilder<>(db.message().pagedUnifiedInbox(debug), 20).build(); } else { - DB.getInstance(getContext()).folder().liveFolderEx(folder).observe(this, new Observer() { + db.folder().liveFolderEx(folder).observe(this, new Observer() { @Override public void onChanged(@Nullable TupleFolderEx folder) { setSubtitle(folder == null ? null : Helper.localizeFolderName(getContext(), folder.name)); } }); - db.message().liveMessages(folder, debug).observe(this, messagesObserver); + messages = new LivePagedListBuilder<>(db.message().pagedFolder(folder, debug), 20).build(); } else { setSubtitle(R.string.title_folder_thread); - db.message().liveThread(thread, debug).observe(this, messagesObserver); + messages = new LivePagedListBuilder<>(db.message().pagedThread(thread, debug), 20).build(); } + messages.observe(this, new Observer>() { + @Override + public void onChanged(@Nullable PagedList messages) { + adapter.submitList(messages); + + pbWait.setVisibility(View.GONE); + grpReady.setVisibility(View.VISIBLE); + + if (messages.size() == 0) { + tvNoEmail.setVisibility(View.VISIBLE); + rvMessage.setVisibility(View.GONE); + } else { + tvNoEmail.setVisibility(View.GONE); + rvMessage.setVisibility(View.VISIBLE); + } + } + }); + getLoaderManager().restartLoader(ActivityView.LOADER_MESSAGES_INIT, new Bundle(), initLoaderCallbacks).forceLoad(); return view; } - Observer> messagesObserver = new Observer>() { - @Override - public void onChanged(@Nullable List messages) { - adapter.set(messages); - - pbWait.setVisibility(View.GONE); - grpReady.setVisibility(View.VISIBLE); - - if (messages.size() == 0) { - tvNoEmail.setVisibility(View.VISIBLE); - rvMessage.setVisibility(View.GONE); - } else { - tvNoEmail.setVisibility(View.GONE); - rvMessage.setVisibility(View.VISIBLE); - } - } - }; - private static class InitLoader extends AsyncTaskLoader { InitLoader(@NonNull Context context) { super(context); diff --git a/app/src/main/res/layout/item_message.xml b/app/src/main/res/layout/item_message.xml index 1a0f2667..e90506d7 100644 --- a/app/src/main/res/layout/item_message.xml +++ b/app/src/main/res/layout/item_message.xml @@ -65,6 +65,18 @@ app:layout_constraintBottom_toBottomOf="@id/tvSubject" app:layout_constraintEnd_toEndOf="parent" /> + +