diff --git a/app/src/main/java/eu/faircode/email/DaoMessage.java b/app/src/main/java/eu/faircode/email/DaoMessage.java index fe610473cb..c81e836930 100644 --- a/app/src/main/java/eu/faircode/email/DaoMessage.java +++ b/app/src/main/java/eu/faircode/email/DaoMessage.java @@ -80,6 +80,7 @@ public interface DaoMessage { " AND (NOT :filter_unflagged 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 (:filter_language IS NULL OR message.language = :filter_language)" + " ORDER BY -IFNULL(MAX(message.importance), 1)" + ", CASE" + " WHEN 'unread' = :sort THEN SUM(1 - message.ui_seen) = 0" + @@ -98,7 +99,7 @@ public interface DaoMessage { String type, boolean threading, String sort, boolean ascending, - boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, + boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, String filter_language, boolean found, boolean debug); @@ -135,6 +136,7 @@ public interface DaoMessage { " 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 + ")" + + " AND (:filter_language IS NULL OR message.language = :filter_language)" + " ORDER BY -IFNULL(MAX(message.importance), 1)" + ", CASE" + " WHEN 'unread' = :sort THEN SUM(1 - message.ui_seen) = 0" + @@ -152,7 +154,7 @@ public interface DaoMessage { DataSource.Factory pagedFolder( long folder, boolean threading, String sort, boolean ascending, - boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, + boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, String filter_language, boolean found, boolean debug); @@ -463,6 +465,14 @@ public interface DaoMessage { " ORDER BY sender, subject") Cursor getSuggestions(String query); + @Query("SELECT language FROM message" + + " WHERE (:account IS NULL OR message.account = :account)" + + " AND (:folder IS NULL OR message.folder = :folder)" + + " AND NOT message.language IS NULL" + + " GROUP BY language" + + " ORDER BY COUNT(*) DESC") + List getLanguages(Long account, Long folder); + @Insert long insertMessage(EntityMessage message); diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index 942b01ad52..837f43d43b 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -3426,15 +3426,13 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. menu.findItem(R.id.menu_compact).setChecked(compact); - menu.findItem(R.id.menu_select_all).setVisible(!outbox && - (viewType == AdapterMessage.ViewType.UNIFIED || viewType == AdapterMessage.ViewType.FOLDER)); + boolean list = (viewType == AdapterMessage.ViewType.UNIFIED || viewType == AdapterMessage.ViewType.FOLDER); + + menu.findItem(R.id.menu_select_language).setVisible(list && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q); + menu.findItem(R.id.menu_select_all).setVisible(!outbox && list); menu.findItem(R.id.menu_select_found).setVisible(viewType == AdapterMessage.ViewType.SEARCH); - menu.findItem(R.id.menu_empty_trash).setVisible(EntityFolder.TRASH.equals(type) && - (viewType == AdapterMessage.ViewType.UNIFIED || - viewType == AdapterMessage.ViewType.FOLDER)); - menu.findItem(R.id.menu_empty_spam).setVisible(EntityFolder.JUNK.equals(type) && - (viewType == AdapterMessage.ViewType.UNIFIED || - viewType == AdapterMessage.ViewType.FOLDER)); + menu.findItem(R.id.menu_empty_trash).setVisible(EntityFolder.TRASH.equals(type) && list); + menu.findItem(R.id.menu_empty_spam).setVisible(EntityFolder.JUNK.equals(type) && list); menu.findItem(R.id.menu_force_sync).setVisible(viewType == AdapterMessage.ViewType.UNIFIED); @@ -3534,6 +3532,10 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. onMenuCompact(); return true; + case R.id.menu_select_language: + onMenuSelectLanguage(); + return true; + case R.id.menu_select_all: case R.id.menu_select_found: onMenuSelectAll(); @@ -3625,6 +3627,63 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. getActivity().invalidateOptionsMenu(); } + private void onMenuSelectLanguage() { + Bundle args = new Bundle(); + args.putLong("account", account); + args.putLong("folder", folder); + + new SimpleTask>() { + @Override + protected List onExecute(Context context, Bundle args) { + long account = args.getLong("account"); + long folder = args.getLong("folder"); + + DB db = DB.getInstance(context); + return db.message().getLanguages(account < 0 ? null : account, folder < 0 ? null : folder); + } + + @Override + protected void onExecuted(Bundle args, List languages) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + String current = prefs.getString("filter_language", null); + + PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(getContext(), getViewLifecycleOwner(), vwAnchor); + popupMenu.getMenu().add(Menu.NONE, 0, 0, R.string.title_language_all); + + for (int i = 0; i < languages.size(); i++) { + String language = languages.get(i); + Locale locale = new Locale(language); + String title = locale.getDisplayLanguage() + (language.equals(current) ? " ★" : ""); + popupMenu.getMenu() + .add(Menu.NONE, i + 1, i + 1, title) + .setIntent(new Intent().putExtra("locale", locale)); + } + + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + if (item.getItemId() == 0) // all + prefs.edit().remove("filter_language").apply(); + else { + Locale locale = (Locale) item.getIntent().getSerializableExtra("locale"); + prefs.edit().putString("filter_language", locale.getLanguage()).apply(); + } + + loadMessages(true); + + return true; + } + }); + popupMenu.show(); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Log.unexpectedError(getParentFragmentManager(), ex); + } + }.execute(this, args, "menu:language"); + } + private void onMenuSelectAll() { ViewModelMessages model = new ViewModelProvider(getActivity()).get(ViewModelMessages.class); model.getIds(getContext(), getViewLifecycleOwner(), new Observer>() { @@ -3871,7 +3930,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. boolean filter_seen = prefs.getBoolean("filter_seen", false); boolean filter_unflagged = prefs.getBoolean("filter_unflagged", false); boolean filter_unknown = prefs.getBoolean("filter_unknown", false); - boolean filter_active = (filter_seen || filter_unflagged || filter_unknown); + String filter_language = prefs.getString("filter_language", null); + boolean filter_active = (filter_seen || filter_unflagged || filter_unknown || !TextUtils.isEmpty(filter_language)); boolean none = (items == 0 && !loading && tasks == 0 && initialized); boolean filtered = (filter_active && viewType != AdapterMessage.ViewType.SEARCH); diff --git a/app/src/main/java/eu/faircode/email/ViewModelMessages.java b/app/src/main/java/eu/faircode/email/ViewModelMessages.java index 5443dc41fb..fc3361a1cd 100644 --- a/app/src/main/java/eu/faircode/email/ViewModelMessages.java +++ b/app/src/main/java/eu/faircode/email/ViewModelMessages.java @@ -21,6 +21,7 @@ package eu.faircode.email; import android.content.Context; import android.content.SharedPreferences; +import android.os.Build; import android.os.Bundle; import android.text.TextUtils; @@ -97,6 +98,7 @@ public class ViewModelMessages extends ViewModel { args.filter_unflagged, args.filter_unknown, args.filter_snoozed, + args.filter_language, false, args.debug), LOCAL_PAGE_SIZE); @@ -116,6 +118,7 @@ public class ViewModelMessages extends ViewModel { args.filter_unflagged, args.filter_unknown, args.filter_snoozed, + args.filter_language, false, args.debug), configFolder); @@ -144,6 +147,7 @@ public class ViewModelMessages extends ViewModel { args.threading, "time", false, false, false, false, false, + null, true, args.debug), configSearch); @@ -153,6 +157,7 @@ public class ViewModelMessages extends ViewModel { args.folder, args.threading, "time", false, false, false, false, false, + null, true, args.debug), configSearch); @@ -330,6 +335,7 @@ public class ViewModelMessages extends ViewModel { private boolean filter_unknown; private boolean filter_snoozed; private boolean filter_archive; + private String filter_language; private boolean debug; Args(Context context, @@ -356,6 +362,10 @@ public class ViewModelMessages extends ViewModel { this.filter_unflagged = prefs.getBoolean("filter_unflagged", false); this.filter_unknown = prefs.getBoolean("filter_unknown", false); this.filter_snoozed = prefs.getBoolean("filter_snoozed", true); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) + this.filter_language = null; + else + this.filter_language = prefs.getString("filter_language", null); this.debug = prefs.getBoolean("debug", false); } @@ -379,6 +389,7 @@ public class ViewModelMessages extends ViewModel { this.filter_unknown == other.filter_unknown && this.filter_snoozed == other.filter_snoozed && this.filter_archive == other.filter_archive && + Objects.equals(this.filter_language, other.filter_language) && this.debug == other.debug); } else return false; @@ -397,6 +408,7 @@ public class ViewModelMessages extends ViewModel { " unknown=" + filter_unknown + " snoozed=" + filter_snoozed + " archive=" + filter_archive + + " language=" + filter_language + " debug=" + debug; } } diff --git a/app/src/main/res/menu/menu_messages.xml b/app/src/main/res/menu/menu_messages.xml index 901b9da112..768e49140c 100644 --- a/app/src/main/res/menu/menu_messages.xml +++ b/app/src/main/res/menu/menu_messages.xml @@ -102,6 +102,11 @@ android:title="@string/title_compact" app:showAsAction="never" /> + + Compact view Text size + Select language Select all Select found Force sync + All + Previous Next