From 655e25258f8031e239ac0f7259b5f65b528598cd Mon Sep 17 00:00:00 2001 From: M66B Date: Wed, 17 Oct 2018 16:37:59 +0000 Subject: [PATCH] Previous/next navigation --- FAQ.md | 2 - .../java/eu/faircode/email/ActivityView.java | 27 +++++++ .../eu/faircode/email/FragmentMessages.java | 77 ++++++++++++++----- .../res/drawable/baseline_skip_next_24.xml | 10 +++ .../drawable/baseline_skip_previous_24.xml | 10 +++ app/src/main/res/layout/fragment_messages.xml | 26 +++++++ 6 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_skip_next_24.xml create mode 100644 app/src/main/res/drawable/baseline_skip_previous_24.xml diff --git a/FAQ.md b/FAQ.md index f8e67657..4ed8cdec 100644 --- a/FAQ.md +++ b/FAQ.md @@ -130,8 +130,6 @@ See [here](https://support.microsoft.com/en-us/help/12409/microsoft-account-app- * More themes: the goal is to keep the app as simple as possible, so this will not be added. * Encryption: there is too little interest in sending/receiving encrypted messages to justify putting effort into this. * Multiple select: swiping is easier and doesn't have the risk of accidental touches, so multiple select would not add anything. -* Swipe left/right for previous/next message: this would be confusing since sometimes a message and sometimes a conversation would be shown. -* Open message from notification: this would be confusing since sometimes a message and sometimes a conversation would be opened. * Preview message text: this is not always possible because the message text is initially not downloaded for large messages and besides that the subject is supposed to tell what the message is about. * Filter rules: filter rules should be executed on the server because a battery powered device with possibly an unstable internet connection is not suitable for executing filter rules. * Widget: FairEmail can be started from a shortcut and new messages are reported as status bar notifications, so I don't see what a widget would add. diff --git a/app/src/main/java/eu/faircode/email/ActivityView.java b/app/src/main/java/eu/faircode/email/ActivityView.java index 4ee0e219..49cf5c96 100644 --- a/app/src/main/java/eu/faircode/email/ActivityView.java +++ b/app/src/main/java/eu/faircode/email/ActivityView.java @@ -75,6 +75,7 @@ import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Observer; import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.paging.PagedList; public class ActivityView extends ActivityBilling implements FragmentManager.OnBackStackChangedListener { private View view; @@ -83,6 +84,7 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB private ActionBarDrawerToggle drawerToggle; private long attachment = -1; + private PagedList messages = null; private static final int ATTACHMENT_BUFFER_SIZE = 8192; // bytes @@ -883,4 +885,29 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB }.load(this, args); } } + + void setMessages(PagedList messages) { + this.messages = messages; + } + + public String[] getPrevNext(String thread) { + boolean found = false; + TupleMessageEx prev = null; + TupleMessageEx next = null; + for (int i = 0; i < messages.size(); i++) { + TupleMessageEx item = messages.get(i); + if (item == null) + continue; + if (found) { + next = item; + messages.loadAround(i); + break; + } + if (thread.equals(item.thread)) + found = true; + else + prev = item; + } + return new String[]{prev == null ? null : prev.thread, next == null ? null : next.thread}; + } } diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index dd254ffb..11987aa1 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -52,10 +52,12 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.SearchView; import androidx.constraintlayout.widget.Group; +import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.paging.LivePagedListBuilder; import androidx.paging.PagedList; import androidx.recyclerview.widget.ItemTouchHelper; @@ -75,6 +77,8 @@ public class FragmentMessages extends FragmentEx { private Group grpHintActions; private Group grpReady; private FloatingActionButton fab; + private FloatingActionButton fabPrev; + private FloatingActionButton fabNext; private long folder = -1; private long account = -1; @@ -107,12 +111,21 @@ public class FragmentMessages extends FragmentEx { // Get arguments Bundle args = getArguments(); - if (args != null) { - account = args.getLong("account", -1); - folder = args.getLong("folder", -1); - thread = args.getString("thread"); - search = args.getString("search"); - } + account = args.getLong("account", -1); + folder = args.getLong("folder", -1); + thread = args.getString("thread"); + search = args.getString("search"); + + if (TextUtils.isEmpty(search)) + if (thread == null) + if (folder < 0) + viewType = AdapterMessage.ViewType.UNIFIED; + else + viewType = AdapterMessage.ViewType.FOLDER; + else + viewType = AdapterMessage.ViewType.THREAD; + else + viewType = AdapterMessage.ViewType.SEARCH; } @Override @@ -134,6 +147,8 @@ public class FragmentMessages extends FragmentEx { grpHintActions = view.findViewById(R.id.grpHintActions); grpReady = view.findViewById(R.id.grpReady); fab = view.findViewById(R.id.fab); + fabPrev = view.findViewById(R.id.fabPrev); + fabNext = view.findViewById(R.id.fabNext); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); @@ -168,17 +183,6 @@ public class FragmentMessages extends FragmentEx { LinearLayoutManager llm = new LinearLayoutManager(getContext()); rvMessage.setLayoutManager(llm); - if (TextUtils.isEmpty(search)) - if (thread == null) - if (folder < 0) - viewType = AdapterMessage.ViewType.UNIFIED; - else - viewType = AdapterMessage.ViewType.FOLDER; - else - viewType = AdapterMessage.ViewType.THREAD; - else - viewType = AdapterMessage.ViewType.SEARCH; - adapter = new AdapterMessage(getContext(), getViewLifecycleOwner(), viewType, new AdapterMessage.IProperties() { @Override public void setExpanded(long id, boolean expand) { @@ -467,11 +471,30 @@ public class FragmentMessages extends FragmentEx { } }); + View.OnClickListener navigate = new View.OnClickListener() { + @Override + public void onClick(View v) { + getFragmentManager().popBackStack("thread", FragmentManager.POP_BACK_STACK_INCLUSIVE); + + LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext()); + lbm.sendBroadcast( + new Intent(ActivityView.ACTION_VIEW_THREAD) + .putExtra("account", account) + .putExtra("thread", (String) v.getTag())); + } + }; + + fabPrev.setOnClickListener(navigate); + fabNext.setOnClickListener(navigate); + // Initialize tvNoEmail.setVisibility(View.GONE); grpReady.setVisibility(View.GONE); pbWait.setVisibility(View.VISIBLE); + fab.hide(); + fabPrev.hide(); + fabNext.hide(); return view; } @@ -561,7 +584,22 @@ public class FragmentMessages extends FragmentEx { loadMessages(); // Compose FAB - if (viewType != AdapterMessage.ViewType.THREAD) { + if (viewType == AdapterMessage.ViewType.THREAD) { + String[] pn = ((ActivityView) getActivity()).getPrevNext(thread); + + fabPrev.setTag(pn[0]); + fabNext.setTag(pn[1]); + + if (pn[0] == null) + fabPrev.hide(); + else + fabPrev.show(); + + if (pn[1] == null) + fabNext.hide(); + else + fabNext.show(); + } else { Bundle args = new Bundle(); args.putLong("account", account); @@ -816,6 +854,9 @@ public class FragmentMessages extends FragmentEx { return; } + if (viewType != AdapterMessage.ViewType.THREAD) + ((ActivityView) getActivity()).setMessages(messages); + if (viewType == AdapterMessage.ViewType.THREAD && autoExpand) { autoExpand = false; diff --git a/app/src/main/res/drawable/baseline_skip_next_24.xml b/app/src/main/res/drawable/baseline_skip_next_24.xml new file mode 100644 index 00000000..4f860dba --- /dev/null +++ b/app/src/main/res/drawable/baseline_skip_next_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_skip_previous_24.xml b/app/src/main/res/drawable/baseline_skip_previous_24.xml new file mode 100644 index 00000000..24e5c0e2 --- /dev/null +++ b/app/src/main/res/drawable/baseline_skip_previous_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_messages.xml b/app/src/main/res/layout/fragment_messages.xml index 4378c0b5..0157c60c 100644 --- a/app/src/main/res/layout/fragment_messages.xml +++ b/app/src/main/res/layout/fragment_messages.xml @@ -162,4 +162,30 @@ app:backgroundTint="?attr/colorAccent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> + + + +