diff --git a/app/src/main/java/eu/faircode/email/DaoMessage.java b/app/src/main/java/eu/faircode/email/DaoMessage.java index ba2121bb4a..37f9e00c0d 100644 --- a/app/src/main/java/eu/faircode/email/DaoMessage.java +++ b/app/src/main/java/eu/faircode/email/DaoMessage.java @@ -91,6 +91,8 @@ public interface DaoMessage { " AND (NOT (:filter_seen AND NOT :filter_unflagged) OR SUM(1 - message.ui_seen) > 0)" + " AND (NOT (:filter_unflagged AND NOT :filter_seen) OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0)" + " AND (NOT (:filter_seen AND :filter_unflagged) OR SUM(1 - message.ui_seen) > 0 OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0)" + + " AND (NOT :filter_unseen OR SUM(1 - message.ui_seen) = 0)" + + " AND (NOT :filter_flagged OR COUNT(message.id) - SUM(1 - message.ui_flagged) = 0)" + " AND (NOT :filter_unknown OR SUM(message.avatar IS NOT NULL AND message.sender <> identity.email) > 0)" + " AND (NOT :filter_snoozed OR message.ui_snoozed IS NULL OR " + is_drafts + ")" + " AND (NOT :filter_deleted OR NOT message.ui_deleted)" + @@ -119,7 +121,7 @@ public interface DaoMessage { String type, String category, boolean threading, boolean group_category, String sort1, String sort2, boolean ascending, - boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, + boolean filter_seen, boolean filter_unseen, boolean filter_flagged, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, boolean found, boolean debug); @@ -169,6 +171,8 @@ public interface DaoMessage { " AND (NOT (:filter_seen AND NOT :filter_unflagged) OR SUM(1 - message.ui_seen) > 0 OR " + is_outbox + ")" + " AND (NOT (:filter_unflagged AND NOT :filter_seen) OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0 OR " + is_outbox + ")" + " AND (NOT (:filter_seen AND :filter_unflagged) OR SUM(1 - message.ui_seen) > 0 OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0 OR " + is_outbox + ")" + + " AND (NOT :filter_unseen OR SUM(1 - message.ui_seen) = 0 OR " + is_outbox + ")" + + " AND (NOT :filter_flagged OR COUNT(message.id) - SUM(1 - message.ui_flagged) = 0 OR " + is_outbox + ")" + " AND (NOT :filter_unknown OR SUM(message.avatar IS NOT NULL AND message.sender <> identity.email) > 0" + " OR " + is_outbox + " OR " + is_drafts + " OR " + is_sent + ")" + " AND (NOT :filter_snoozed OR message.ui_snoozed IS NULL OR " + is_outbox + " OR " + is_drafts + ")" + @@ -196,7 +200,7 @@ public interface DaoMessage { DataSource.Factory pagedFolder( long folder, boolean threading, String sort1, String sort2, boolean ascending, - boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, + boolean filter_seen, boolean filter_unseen, boolean filter_flagged, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, boolean found, boolean debug); @@ -1149,6 +1153,8 @@ public interface DaoMessage { " AND (NOT (:filter_seen AND NOT :filter_unflagged) OR SUM(1 - message.ui_seen) > 0)" + " AND (NOT (:filter_unflagged AND NOT :filter_seen) OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0)" + " AND (NOT (:filter_seen AND :filter_unflagged) OR SUM(1 - message.ui_seen) > 0 OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0)" + + " AND (NOT :filter_unseen OR SUM(1 - message.ui_seen) = 0)" + + " AND (NOT :filter_flagged OR COUNT(message.id) - SUM(1 - message.ui_flagged) = 0)" + " AND (NOT :filter_unknown OR SUM(message.avatar IS NOT NULL AND message.sender <> identity.email) > 0)" + " AND (NOT :filter_snoozed OR message.ui_snoozed IS NULL OR " + is_drafts + ")" + " AND (NOT :filter_deleted OR NOT message.ui_deleted)" + @@ -1178,7 +1184,7 @@ public interface DaoMessage { String type, String category, boolean threading, boolean group_category, String sort1, String sort2, boolean ascending, - boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, + boolean filter_seen, boolean filter_unseen, boolean filter_flagged, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, boolean found, boolean debug); @@ -1228,6 +1234,8 @@ public interface DaoMessage { " AND (NOT (:filter_seen AND NOT :filter_unflagged) OR SUM(1 - message.ui_seen) > 0 OR " + is_outbox + ")" + " AND (NOT (:filter_unflagged AND NOT :filter_seen) OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0 OR " + is_outbox + ")" + " AND (NOT (:filter_seen AND :filter_unflagged) OR SUM(1 - message.ui_seen) > 0 OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0 OR " + is_outbox + ")" + + " AND (NOT :filter_unseen OR SUM(1 - message.ui_seen) = 0 OR " + is_outbox + ")" + + " AND (NOT :filter_flagged OR COUNT(message.id) - SUM(1 - message.ui_flagged) = 0 OR " + is_outbox + ")" + " AND (NOT :filter_unknown OR SUM(message.avatar IS NOT NULL AND message.sender <> identity.email) > 0" + " OR " + is_outbox + " OR " + is_drafts + " OR " + is_sent + ")" + " AND (NOT :filter_snoozed OR message.ui_snoozed IS NULL OR " + is_outbox + " OR " + is_drafts + ")" + @@ -1256,7 +1264,7 @@ public interface DaoMessage { DataSource.Factory pagedFolderJson( long folder, boolean threading, String sort1, String sort2, boolean ascending, - boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, + boolean filter_seen, boolean filter_unseen, boolean filter_flagged, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, boolean found, boolean debug); } \ No newline at end of file diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index 8bcaef84c7..d3276e6918 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -1396,7 +1396,7 @@ public class FragmentMessages extends FragmentBase public void onClick(View v) { String name = getFilter(v.getContext(), "seen", viewType, type); boolean filter = prefs.getBoolean(name, true); - onMenuFilter(name, !filter); + onMenuFilter("seen", viewType, type, !filter); } }); @@ -1405,7 +1405,7 @@ public class FragmentMessages extends FragmentBase public void onClick(View v) { String name = getFilter(v.getContext(), "unflagged", viewType, type); boolean filter = prefs.getBoolean(name, true); - onMenuFilter(name, !filter); + onMenuFilter("unflagged", viewType, type, !filter); } }); @@ -1414,7 +1414,7 @@ public class FragmentMessages extends FragmentBase public void onClick(View v) { String name = getFilter(v.getContext(), "snoozed", viewType, type); boolean filter = prefs.getBoolean(name, true); - onMenuFilter(name, !filter); + onMenuFilter("snoozed", viewType, type, !filter); } }); @@ -6401,6 +6401,8 @@ public class FragmentMessages extends FragmentBase String sort = prefs.getString(getSort(context, viewType, type), "time"); boolean ascending = prefs.getBoolean(getSortOrder(context, viewType, type), outbox); boolean filter_seen = prefs.getBoolean(getFilter(context, "seen", viewType, type), false); + boolean filter_unseen = prefs.getBoolean(getFilter(context, "unseen", viewType, type), false); + boolean filter_flagged = prefs.getBoolean(getFilter(context, "flagged", viewType, type), false); boolean filter_unflagged = prefs.getBoolean(getFilter(context, "unflagged", viewType, type), false); boolean filter_unknown = prefs.getBoolean(getFilter(context, "unknown", viewType, type), false); boolean filter_snoozed = prefs.getBoolean(getFilter(context, "snoozed", viewType, type), true); @@ -6423,7 +6425,9 @@ public class FragmentMessages extends FragmentBase (viewType == AdapterMessage.ViewType.UNIFIED || (viewType == AdapterMessage.ViewType.FOLDER && !outbox)); - boolean filter_active = (filter_seen || filter_unflagged || filter_unknown || + boolean filter_active = (filter_seen || filter_unseen || + filter_flagged || filter_unflagged || + filter_unknown || (language_detection && !TextUtils.isEmpty(filter_language))); int filterColor = Helper.resolveColor(context, androidx.appcompat.R.attr.colorAccent); float filterLighten = 0.7f - (float) ColorUtils.calculateLuminance(filterColor); @@ -6506,6 +6510,8 @@ public class FragmentMessages extends FragmentBase menu.findItem(R.id.menu_filter).setVisible(viewType != AdapterMessage.ViewType.SEARCH && !outbox); menu.findItem(R.id.menu_filter_seen).setVisible(folder); + menu.findItem(R.id.menu_filter_unseen).setVisible(folder); + menu.findItem(R.id.menu_filter_flagged).setVisible(folder); menu.findItem(R.id.menu_filter_unflagged).setVisible(folder); menu.findItem(R.id.menu_filter_unknown).setVisible(folder && !drafts && !sent); menu.findItem(R.id.menu_filter_snoozed).setVisible(folder && !drafts); @@ -6515,6 +6521,8 @@ public class FragmentMessages extends FragmentBase menu.findItem(R.id.menu_filter_trash).setVisible(viewType == AdapterMessage.ViewType.THREAD); menu.findItem(R.id.menu_filter_seen).setChecked(filter_seen); + menu.findItem(R.id.menu_filter_unseen).setChecked(filter_unseen); + menu.findItem(R.id.menu_filter_flagged).setChecked(filter_flagged); menu.findItem(R.id.menu_filter_unflagged).setChecked(filter_unflagged); menu.findItem(R.id.menu_filter_unknown).setChecked(filter_unknown); menu.findItem(R.id.menu_filter_snoozed).setChecked(filter_snoozed); @@ -6594,8 +6602,8 @@ public class FragmentMessages extends FragmentBase ibUnflagged.setImageResource(filter_unflagged ? R.drawable.twotone_star_border_24 : R.drawable.baseline_star_24); ibSnoozed.setImageResource(filter_snoozed ? R.drawable.twotone_visibility_off_24 : R.drawable.twotone_visibility_24); - ibSeen.setImageTintList(ColorStateList.valueOf(filter_seen ? colorAccent : colorControlNormal)); - ibUnflagged.setImageTintList(ColorStateList.valueOf(filter_unflagged ? colorAccent : colorControlNormal)); + ibSeen.setImageTintList(ColorStateList.valueOf(filter_seen || filter_unseen ? colorAccent : colorControlNormal)); + ibUnflagged.setImageTintList(ColorStateList.valueOf(filter_flagged || filter_unflagged ? colorAccent : colorControlNormal)); ibSnoozed.setImageTintList(ColorStateList.valueOf(filter_snoozed ? colorControlNormal : colorAccent)); ibSeen.setVisibility(quick_filter && folder ? View.VISIBLE : View.GONE); @@ -6678,19 +6686,25 @@ public class FragmentMessages extends FragmentBase onMenuAscending(!item.isChecked()); return true; } else if (itemId == R.id.menu_filter_seen) { - onMenuFilter(getFilter(getContext(), "seen", viewType, type), !item.isChecked()); + onMenuFilter("seen", viewType, type, !item.isChecked()); + return true; + } else if (itemId == R.id.menu_filter_unseen) { + onMenuFilter("unseen", viewType, type, !item.isChecked()); + return true; + } else if (itemId == R.id.menu_filter_flagged) { + onMenuFilter("flagged", viewType, type, !item.isChecked()); return true; } else if (itemId == R.id.menu_filter_unflagged) { - onMenuFilter(getFilter(getContext(), "unflagged", viewType, type), !item.isChecked()); + onMenuFilter("unflagged", viewType, type, !item.isChecked()); return true; } else if (itemId == R.id.menu_filter_unknown) { - onMenuFilter(getFilter(getContext(), "unknown", viewType, type), !item.isChecked()); + onMenuFilter("unknown", viewType, type, !item.isChecked()); return true; } else if (itemId == R.id.menu_filter_snoozed) { - onMenuFilter(getFilter(getContext(), "snoozed", viewType, type), !item.isChecked()); + onMenuFilter("snoozed", viewType, type, !item.isChecked()); return true; } else if (itemId == R.id.menu_filter_deleted) { - onMenuFilter(getFilter(getContext(), "deleted", viewType, type), !item.isChecked()); + onMenuFilter("deleted", viewType, type, !item.isChecked()); return true; } else if (itemId == R.id.menu_filter_language) { onMenuFilterLanguage(); @@ -6880,9 +6894,25 @@ public class FragmentMessages extends FragmentBase loadMessages(true); } - private void onMenuFilter(String name, boolean filter) { + private void onMenuFilter(String name, AdapterMessage.ViewType viewType, String type, boolean filter) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); - prefs.edit().putBoolean(name, filter).apply(); + prefs.edit().putBoolean(getFilter(getContext(), name, viewType, type), filter).apply(); + if ("seen".equals(name)) { + String altName = getFilter(getContext(), "unseen", viewType, type); + prefs.edit().putBoolean(altName, false).apply(); + } + if ("unseen".equals(name)) { + String altName = getFilter(getContext(), "seen", viewType, type); + prefs.edit().putBoolean(altName, false).apply(); + } + if ("flagged".equals(name)) { + String altName = getFilter(getContext(), "unflagged", viewType, type); + prefs.edit().putBoolean(altName, false).apply(); + } + if ("unflagged".equals(name)) { + String altName = getFilter(getContext(), "flagged", viewType, type); + prefs.edit().putBoolean(altName, false).apply(); + } invalidateOptionsMenu(); if (selectionTracker != null) selectionTracker.clearSelection(); diff --git a/app/src/main/java/eu/faircode/email/ViewModelMessages.java b/app/src/main/java/eu/faircode/email/ViewModelMessages.java index d09c3e04da..0b3dccacd3 100644 --- a/app/src/main/java/eu/faircode/email/ViewModelMessages.java +++ b/app/src/main/java/eu/faircode/email/ViewModelMessages.java @@ -132,6 +132,8 @@ public class ViewModelMessages extends ViewModel { args.group_category, args.sort1, args.sort2, args.ascending, args.filter_seen, + args.filter_unseen, + args.filter_flagged, args.filter_unflagged, args.filter_unknown, args.filter_snoozed, @@ -147,6 +149,8 @@ public class ViewModelMessages extends ViewModel { args.group_category, args.sort1, args.sort2, args.ascending, args.filter_seen, + args.filter_unseen, + args.filter_flagged, args.filter_unflagged, args.filter_unknown, args.filter_snoozed, @@ -169,6 +173,8 @@ public class ViewModelMessages extends ViewModel { args.folder, args.threading, args.sort1, args.sort2, args.ascending, args.filter_seen, + args.filter_unseen, + args.filter_flagged, args.filter_unflagged, args.filter_unknown, args.filter_snoozed, @@ -181,6 +187,8 @@ public class ViewModelMessages extends ViewModel { args.folder, args.threading, args.sort1, args.sort2, args.ascending, args.filter_seen, + args.filter_unseen, + args.filter_flagged, args.filter_unflagged, args.filter_unknown, args.filter_snoozed, @@ -218,7 +226,7 @@ public class ViewModelMessages extends ViewModel { null, null, args.threading, false, criteria == null || criteria.touched == null ? "time" : "touched", "", false, - false, false, false, false, false, + false, false, false, false, false, false, false, null, true, args.debug); @@ -227,7 +235,7 @@ public class ViewModelMessages extends ViewModel { null, null, args.threading, false, criteria == null || criteria.touched == null ? "time" : "touched", "", false, - false, false, false, false, false, + false, false, false, false, false, false, false, null, true, args.debug); @@ -237,7 +245,7 @@ public class ViewModelMessages extends ViewModel { pager = db.message().pagedFolderJson( args.folder, args.threading, criteria == null || criteria.touched == null ? "time" : "touched", "", false, - false, false, false, false, false, + false, false, false, false, false, false, false, null, true, args.debug); @@ -245,7 +253,7 @@ public class ViewModelMessages extends ViewModel { pager = db.message().pagedFolder( args.folder, args.threading, criteria == null || criteria.touched == null ? "time" : "touched", "", false, - false, false, false, false, false, + false, false, false, false, false, false, false, null, true, args.debug); @@ -576,6 +584,8 @@ public class ViewModelMessages extends ViewModel { private String sort2; private boolean ascending; private boolean filter_seen; + private boolean filter_unseen; + private boolean filter_flagged; private boolean filter_unflagged; private boolean filter_unknown; private boolean filter_snoozed; @@ -617,6 +627,8 @@ public class ViewModelMessages extends ViewModel { this.sort1 = "sender"; this.filter_seen = prefs.getBoolean(FragmentMessages.getFilter(context, "seen", viewType, type), false); + this.filter_unseen = prefs.getBoolean(FragmentMessages.getFilter(context, "unseen", viewType, type), false); + this.filter_flagged = prefs.getBoolean(FragmentMessages.getFilter(context, "flagged", viewType, type), false); this.filter_unflagged = prefs.getBoolean(FragmentMessages.getFilter(context, "unflagged", viewType, type), false); this.filter_unknown = prefs.getBoolean(FragmentMessages.getFilter(context, "unknown", viewType, type), false); this.filter_snoozed = prefs.getBoolean(FragmentMessages.getFilter(context, "snoozed", viewType, type), true); @@ -648,6 +660,8 @@ public class ViewModelMessages extends ViewModel { Objects.equals(this.sort2, other.sort2) && this.ascending == other.ascending && this.filter_seen == other.filter_seen && + this.filter_unseen == other.filter_unseen && + this.filter_flagged == other.filter_flagged && this.filter_unflagged == other.filter_unflagged && this.filter_unknown == other.filter_unknown && this.filter_snoozed == other.filter_snoozed && @@ -668,8 +682,8 @@ public class ViewModelMessages extends ViewModel { " threading=" + threading + " category=" + group_category + " sort=" + sort1 + "/" + sort2 + ":" + ascending + - " filter seen=" + filter_seen + - " unflagged=" + filter_unflagged + + " filter seen=" + filter_seen + "/" + filter_unseen + + " flagged=" + filter_flagged + "/" + filter_unflagged + " unknown=" + filter_unknown + " snoozed=" + filter_snoozed + " archive=" + filter_archive + diff --git a/app/src/main/res/menu/menu_messages.xml b/app/src/main/res/menu/menu_messages.xml index 28fc87f9f0..0d2e59cd0e 100644 --- a/app/src/main/res/menu/menu_messages.xml +++ b/app/src/main/res/menu/menu_messages.xml @@ -104,6 +104,16 @@ android:checkable="true" android:title="@string/title_filter_seen" /> + + + + Filter out Read + Unread + Starred Unstarred Unknown senders Hidden