mirror of
https://github.com/M66B/FairEmail.git
synced 2025-03-15 08:29:24 +00:00
Added option to scroll to top on new messages
This commit is contained in:
parent
da87251d51
commit
7e36de7733
5 changed files with 103 additions and 71 deletions
3
FAQ.md
3
FAQ.md
|
@ -1220,7 +1220,8 @@ By selecting a zero snooze duration you can cancel snoozing.
|
|||
**(69) Can you add auto scroll up on new message?**
|
||||
|
||||
The message list is automatically scrolled up when navigating from a new message notification or after a manual refresh.
|
||||
Always automatically scrolling up on arrival of new messages would interfere with your own navigation and scrolling.
|
||||
Always automatically scrolling up on arrival of new messages would interfere with your own scrolling,
|
||||
but if you like you can enable this in the advanced options.
|
||||
|
||||
<br />
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@ public class FragmentMessages extends FragmentBase {
|
|||
private boolean date;
|
||||
private boolean threading;
|
||||
private boolean pull;
|
||||
private boolean autoscroll;
|
||||
private boolean actionbar;
|
||||
private boolean autoexpand;
|
||||
private boolean autoclose;
|
||||
|
@ -148,6 +149,8 @@ public class FragmentMessages extends FragmentBase {
|
|||
private String searching = null;
|
||||
private boolean refresh = false;
|
||||
private boolean manual = false;
|
||||
private Integer lastUnseen = null;
|
||||
|
||||
private AdapterMessage adapter;
|
||||
|
||||
private AdapterMessage.ViewType viewType;
|
||||
|
@ -233,6 +236,7 @@ public class FragmentMessages extends FragmentBase {
|
|||
else
|
||||
pull = false;
|
||||
|
||||
autoscroll = prefs.getBoolean("autoscroll", false);
|
||||
date = prefs.getBoolean("date", true);
|
||||
threading = prefs.getBoolean("threading", true);
|
||||
actionbar = prefs.getBoolean("actionbar", true);
|
||||
|
@ -1715,45 +1719,8 @@ public class FragmentMessages extends FragmentBase {
|
|||
public void onChanged(List<TupleFolderEx> folders) {
|
||||
if (folders == null)
|
||||
folders = new ArrayList<>();
|
||||
Log.i("Folder state updated count=" + folders.size());
|
||||
|
||||
int unseen = 0;
|
||||
boolean sync = false;
|
||||
boolean errors = false;
|
||||
for (TupleFolderEx folder : folders) {
|
||||
unseen += folder.unseen;
|
||||
if (folder.synchronize)
|
||||
sync = true;
|
||||
if (folder.error != null)
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (unseen > 0)
|
||||
setSubtitle(getString(R.string.title_name_count,
|
||||
getString(R.string.title_folder_unified),
|
||||
nf.format(unseen)));
|
||||
else
|
||||
setSubtitle(getString(R.string.title_folder_unified));
|
||||
|
||||
boolean refreshing = false;
|
||||
for (TupleFolderEx folder : folders)
|
||||
if (folder.sync_state != null &&
|
||||
(folder.account == null || "connected".equals(folder.accountState))) {
|
||||
refreshing = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!refreshing && manual) {
|
||||
manual = false;
|
||||
rvMessage.scrollToPosition(0);
|
||||
}
|
||||
|
||||
if (errors && !refreshing && swipeRefresh.isRefreshing())
|
||||
Snackbar.make(view, R.string.title_sync_errors, Snackbar.LENGTH_LONG).show();
|
||||
|
||||
refresh = sync;
|
||||
swipeRefresh.setEnabled(pull && refresh);
|
||||
swipeRefresh.setRefreshing(refreshing);
|
||||
updateState(folders);
|
||||
}
|
||||
});
|
||||
db.message().liveHidden(null).observe(getViewLifecycleOwner(), new Observer<List<Long>>() {
|
||||
|
@ -1770,37 +1737,17 @@ public class FragmentMessages extends FragmentBase {
|
|||
db.folder().liveFolderEx(folder).observe(getViewLifecycleOwner(), new Observer<TupleFolderEx>() {
|
||||
@Override
|
||||
public void onChanged(@Nullable TupleFolderEx folder) {
|
||||
Log.i("Folder state updated");
|
||||
if (folder == null)
|
||||
setSubtitle(null);
|
||||
else {
|
||||
if (folder.unseen > 0)
|
||||
setSubtitle(getString(R.string.title_name_count,
|
||||
folder.getDisplayName(getContext()),
|
||||
nf.format(folder.unseen)));
|
||||
else
|
||||
setSubtitle(folder.getDisplayName(getContext()));
|
||||
List<TupleFolderEx> folders = new ArrayList<>();
|
||||
if (folder != null)
|
||||
folders.add(folder);
|
||||
|
||||
boolean outbox = EntityFolder.OUTBOX.equals(folder.type);
|
||||
if (FragmentMessages.this.outbox != outbox) {
|
||||
FragmentMessages.this.outbox = outbox;
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
updateState(folders);
|
||||
|
||||
boolean outbox = EntityFolder.OUTBOX.equals(folder.type);
|
||||
if (FragmentMessages.this.outbox != outbox) {
|
||||
FragmentMessages.this.outbox = outbox;
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
boolean refreshing = (folder != null && folder.sync_state != null &&
|
||||
(folder.account == null || "connected".equals(folder.accountState)));
|
||||
if (!refreshing && manual) {
|
||||
manual = false;
|
||||
rvMessage.scrollToPosition(0);
|
||||
}
|
||||
|
||||
if (folder != null && folder.error != null && !refreshing && swipeRefresh.isRefreshing())
|
||||
Snackbar.make(view, folder.error, Snackbar.LENGTH_LONG).show();
|
||||
|
||||
refresh = (folder != null);
|
||||
swipeRefresh.setEnabled(pull && refresh);
|
||||
swipeRefresh.setRefreshing(refreshing);
|
||||
}
|
||||
});
|
||||
db.message().liveHidden(folder).observe(getViewLifecycleOwner(), new Observer<List<Long>>() {
|
||||
|
@ -2213,6 +2160,67 @@ public class FragmentMessages extends FragmentBase {
|
|||
}.execute(this, args, "messages:all");
|
||||
}
|
||||
|
||||
private void updateState(List<TupleFolderEx> folders) {
|
||||
Log.i("Folder state updated count=" + folders.size());
|
||||
|
||||
// Get state
|
||||
int unseen = 0;
|
||||
boolean sync = false;
|
||||
boolean errors = false;
|
||||
boolean refreshing = false;
|
||||
for (TupleFolderEx folder : folders) {
|
||||
unseen += folder.unseen;
|
||||
if (folder.synchronize)
|
||||
sync = true;
|
||||
if (folder.error != null)
|
||||
errors = true;
|
||||
if (folder.sync_state != null &&
|
||||
(folder.account == null || "connected".equals(folder.accountState))) {
|
||||
refreshing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get name
|
||||
String name;
|
||||
if (viewType == AdapterMessage.ViewType.UNIFIED)
|
||||
name = getString(R.string.title_folder_unified);
|
||||
else
|
||||
name = (folders.size() > 0 ? folders.get(0).getDisplayName(getContext()) : "");
|
||||
|
||||
// Show name/unread
|
||||
if (unseen == 0)
|
||||
setSubtitle(name);
|
||||
else
|
||||
setSubtitle(getString(R.string.title_name_count, name, nf.format(unseen)));
|
||||
|
||||
// Auto scroll
|
||||
if (lastUnseen == null || lastUnseen != unseen) {
|
||||
if ((!refreshing && manual) ||
|
||||
(autoscroll && lastUnseen != null && lastUnseen < unseen))
|
||||
// Delay to let list update
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
rvMessage.scrollToPosition(0);
|
||||
}
|
||||
}, 3000);
|
||||
manual = false;
|
||||
lastUnseen = unseen;
|
||||
}
|
||||
|
||||
// Show errors
|
||||
if (errors && !refreshing && swipeRefresh.isRefreshing())
|
||||
if (folders.size() == 1)
|
||||
Snackbar.make(view, folders.get(0).error, Snackbar.LENGTH_LONG).show();
|
||||
else
|
||||
Snackbar.make(view, R.string.title_sync_errors, Snackbar.LENGTH_LONG).show();
|
||||
|
||||
refresh = sync;
|
||||
swipeRefresh.setEnabled(pull && refresh);
|
||||
swipeRefresh.setRefreshing(refreshing);
|
||||
}
|
||||
|
||||
private void loadMessages() {
|
||||
if (viewType == AdapterMessage.ViewType.THREAD && autonext) {
|
||||
ViewModelMessages model = ViewModelProviders.of(getActivity()).get(ViewModelMessages.class);
|
||||
|
|
|
@ -91,6 +91,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
private SwitchCompat swActionbar;
|
||||
|
||||
private SwitchCompat swPull;
|
||||
private SwitchCompat swAutoScroll;
|
||||
private SwitchCompat swSwipeNav;
|
||||
private SwitchCompat swAutoExpand;
|
||||
private SwitchCompat swAutoClose;
|
||||
|
@ -125,7 +126,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
static String[] OPTIONS_RESTART = new String[]{
|
||||
"startup", "date", "threading", "avatars", "identicons", "circular", "name_email", "subject_italic", "flags", "preview",
|
||||
"addresses", "monospaced", "autohtml", "autoimages", "actionbar",
|
||||
"pull", "swipenav", "autoexpand", "autoclose", "autonext",
|
||||
"pull", "autoscroll", "swipenav", "autoexpand", "autoclose", "autonext",
|
||||
"subscriptions",
|
||||
"authentication", "debug"
|
||||
};
|
||||
|
@ -135,7 +136,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
"metered", "download", "roaming",
|
||||
"startup", "date", "threading", "avatars", "identicons", "circular", "name_email", "subject_italic", "flags", "preview",
|
||||
"addresses", "monospaced", "autohtml", "autoimages", "actionbar",
|
||||
"pull", "swipenav", "autoexpand", "autoclose", "autonext", "collapse", "autoread", "automove",
|
||||
"pull", "autoscroll", "swipenav", "autoexpand", "autoclose", "autonext", "collapse", "autoread", "automove",
|
||||
"autoresize", "resize", "prefix_once", "autosend",
|
||||
"badge", "subscriptions", "notify_preview", "search_local", "light", "sound",
|
||||
"authentication", "paranoid", "english", "updates", "debug",
|
||||
|
@ -181,6 +182,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
swActionbar = view.findViewById(R.id.swActionbar);
|
||||
|
||||
swPull = view.findViewById(R.id.swPull);
|
||||
swAutoScroll = view.findViewById(R.id.swAutoScroll);
|
||||
swSwipeNav = view.findViewById(R.id.swSwipeNav);
|
||||
swAutoExpand = view.findViewById(R.id.swAutoExpand);
|
||||
swAutoClose = view.findViewById(R.id.swAutoClose);
|
||||
|
@ -443,6 +445,13 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
}
|
||||
});
|
||||
|
||||
swAutoScroll.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
prefs.edit().putBoolean("autoscroll", checked).apply();
|
||||
}
|
||||
});
|
||||
|
||||
swSwipeNav.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
|
@ -753,6 +762,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
swActionbar.setChecked(prefs.getBoolean("actionbar", true));
|
||||
|
||||
swPull.setChecked(prefs.getBoolean("pull", true));
|
||||
swAutoScroll.setChecked(prefs.getBoolean("autoscroll", false));
|
||||
swSwipeNav.setChecked(prefs.getBoolean("swipenav", true));
|
||||
swAutoExpand.setChecked(prefs.getBoolean("autoexpand", true));
|
||||
swAutoClose.setChecked(prefs.getBoolean("autoclose", true));
|
||||
|
|
|
@ -577,6 +577,18 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/vSeparatorBehavior"
|
||||
app:switchPadding="12dp" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/swAutoScroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="@string/title_advanced_autoscroll"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/swPull"
|
||||
app:switchPadding="12dp" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/swSwipeNav"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -586,7 +598,7 @@
|
|||
android:layout_marginEnd="12dp"
|
||||
android:text="@string/title_advanced_swipenav"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/swPull"
|
||||
app:layout_constraintTop_toBottomOf="@id/swAutoScroll"
|
||||
app:switchPadding="12dp" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
|
|
|
@ -183,6 +183,7 @@
|
|||
<string name="title_advanced_actionbar">Conversation action bar</string>
|
||||
|
||||
<string name="title_advanced_pull_refresh">Pull down to refresh</string>
|
||||
<string name="title_advanced_autoscroll">Scroll to top on receiving new messages</string>
|
||||
<string name="title_advanced_swipenav">Swipe left/right to go to next/previous conversation</string>
|
||||
<string name="title_advanced_autoexpand">Automatically expand messages</string>
|
||||
<string name="title_advanced_collapse">Collapse messages in conversations on \'back\'</string>
|
||||
|
|
Loading…
Add table
Reference in a new issue