diff --git a/app/src/main/java/eu/faircode/email/ActivityView.java b/app/src/main/java/eu/faircode/email/ActivityView.java index 57f99334c1..8df7ca9155 100644 --- a/app/src/main/java/eu/faircode/email/ActivityView.java +++ b/app/src/main/java/eu/faircode/email/ActivityView.java @@ -1006,7 +1006,7 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB DB db = DB.getInstance(this); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - db.account().liveAccountFolder().observe(owner, new Observer>() { + db.account().liveAccountFolder(false).observe(owner, new Observer>() { @Override public void onChanged(@Nullable List accounts) { if (accounts == null) diff --git a/app/src/main/java/eu/faircode/email/AdapterAccount.java b/app/src/main/java/eu/faircode/email/AdapterAccount.java index 238cadc461..e48af8eab7 100644 --- a/app/src/main/java/eu/faircode/email/AdapterAccount.java +++ b/app/src/main/java/eu/faircode/email/AdapterAccount.java @@ -91,7 +91,7 @@ public class AdapterAccount extends RecyclerView.Adapter items = new ArrayList<>(); + private List items = new ArrayList<>(); private NumberFormat NF = NumberFormat.getNumberInstance(); private DateFormat DTF; @@ -196,133 +196,191 @@ public class AdapterAccount extends RecyclerView.Adapter 0) + tvName.setText(context.getString(R.string.title_name_count, account.name, NF.format(account.unseen))); + else + tvName.setText(account.name); - ivOAuth.setImageDrawable(ContextCompat.getDrawable(context, account.auth_type == AUTH_TYPE_GMAIL - ? R.drawable.twotone_android_24 : R.drawable.twotone_security_24)); - ivOAuth.setVisibility( - settings && account.auth_type != AUTH_TYPE_PASSWORD ? View.VISIBLE : View.GONE); - ivPrimary.setVisibility(account.primary ? View.VISIBLE : View.GONE); - ivNotify.setVisibility(account.notify ? View.VISIBLE : View.GONE); + tvName.setTypeface(account.unseen > 0 ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); + tvName.setTextColor(account.unseen > 0 ? colorUnread : textColorSecondary); + } - if (settings) { - tvName.setText(account.name); - tvName.setTextColor(account.protocol == EntityAccount.TYPE_IMAP - ? textColorSecondary : colorWarning); + StringBuilder user = new StringBuilder(account.user); + if (account.provider != null && (BuildConfig.DEBUG || debug)) + user.append(" (").append(account.provider).append(')'); + tvUser.setText(user); + tvUser.setVisibility(View.VISIBLE); + + if ("connected".equals(account.state)) { + ivState.setImageResource(R.drawable.twotone_cloud_done_24); + ivState.setContentDescription(context.getString(R.string.title_legend_connected)); + } else if ("connecting".equals(account.state)) { + ivState.setImageResource(R.drawable.twotone_cloud_queue_24); + ivState.setContentDescription(context.getString(R.string.title_legend_connecting)); + } else if ("closing".equals(account.state)) { + ivState.setImageResource(R.drawable.twotone_cancel_24); + ivState.setContentDescription(context.getString(R.string.title_legend_closing)); + } else { + if (account.backoff_until == null) { + ivState.setImageResource(R.drawable.twotone_cloud_off_24); + ivState.setContentDescription(context.getString(R.string.title_legend_disconnected)); + } else { + ivState.setImageResource(R.drawable.twotone_update_24); + ivState.setContentDescription(context.getString(R.string.title_legend_backoff)); + } + } + ivState.setVisibility(account.synchronize || account.state != null ? View.VISIBLE : View.INVISIBLE); + + tvHost.setText(String.format("%s:%d/%s", + account.host, + account.port, + EmailService.getEncryptionName(account.encryption))); + tvHost.setTextColor(account.insecure ? colorWarning : textColorTertiary); + tvHost.setVisibility(View.VISIBLE); + + tvCreated.setVisibility(debug ? View.VISIBLE : View.GONE); + tvCreated.setText(context.getString(R.string.title_created_at, + account.created == null ? null : DTF.format(account.created))); + tvLast.setVisibility(compact ? View.GONE : View.VISIBLE); + tvLast.setText(context.getString(R.string.title_last_connected, + (account.last_connected == null ? "-" : DTF.format(account.last_connected)) + + (BuildConfig.DEBUG ? + "/" + (account.last_modified == null ? "-" : DTF.format(account.last_modified)) + + " " + account.poll_interval + + "/" + account.keep_alive_ok + + "/" + account.keep_alive_failed + + "/" + account.keep_alive_succeeded : ""))); + + tvBackoff.setText(context.getString(R.string.title_backoff_until, + account.backoff_until == null ? "-" : DTF.format(account.backoff_until))); + tvBackoff.setVisibility(account.backoff_until == null || !settings ? View.GONE : View.VISIBLE); + + Integer percent = account.getQuotaPercentage(); + boolean warning = (percent != null && percent > EntityAccount.QUOTA_WARNING); + + tvUsage.setText(settings || percent == null ? null : NF.format(percent) + "%"); + tvUsage.setVisibility(settings || percent == null || (compact && !warning) ? View.GONE : View.VISIBLE); + tvQuota.setText(context.getString(R.string.title_storage_quota, + (account.quota_usage == null ? "-" : Helper.humanReadableByteCount(account.quota_usage)), + (account.quota_limit == null ? "-" : Helper.humanReadableByteCount(account.quota_limit)))); + tvQuota.setVisibility(settings && (account.quota_usage != null || account.quota_limit != null) ? View.VISIBLE : View.GONE); + + tvUsage.setTextColor(warning ? colorWarning : textColorSecondary); + tvUsage.setTypeface(warning ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); + + tvQuota.setTextColor(warning ? colorWarning : textColorSecondary); + tvQuota.setTypeface(warning ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); + + tvMaxSize.setText(account.max_size == null ? null : Helper.humanReadableByteCount(account.max_size)); + tvMaxSize.setVisibility(settings && account.max_size != null && BuildConfig.DEBUG ? View.VISIBLE : View.GONE); + if (tvMaxSize.getVisibility() == View.VISIBLE) + tvQuota.setVisibility(View.VISIBLE); + + tvId.setText(account.id + "/" + account.uuid); + tvId.setVisibility(settings && BuildConfig.DEBUG ? View.VISIBLE : View.GONE); + + tvCapabilities.setText(account.capabilities); + + tvCapabilities.setVisibility(settings && (debug || BuildConfig.DEBUG) && + !TextUtils.isEmpty(account.capabilities) ? View.VISIBLE : View.GONE); + + tvIdentity.setVisibility(account.identities > 0 || !settings ? View.GONE : View.VISIBLE); + tvDrafts.setVisibility(account.drafts != null || !settings ? View.GONE : View.VISIBLE); + tvSent.setVisibility(account.protocol != EntityAccount.TYPE_IMAP || + account.sent != null || !settings ? View.GONE : View.VISIBLE); + + tvWarning.setText(account.warning); + tvWarning.setVisibility(account.warning == null || !settings ? View.GONE : View.VISIBLE); + + tvError.setText(account.error); + tvError.setVisibility(account.error == null ? View.GONE : View.VISIBLE); + btnHelp.setVisibility(account.error == null ? View.GONE : View.VISIBLE); + + ibInbox.setVisibility(settings ? View.GONE : View.VISIBLE); + grpSettings.setVisibility(settings ? View.VISIBLE : View.GONE); } else { + view.setActivated(account.tbd != null); + view.setAlpha(account.synchronize ? 1.0f : Helper.LOW_LIGHT); + vwColor.setBackgroundColor(account.folderColor == null ? Color.TRANSPARENT : account.folderColor); + vwColor.setVisibility(ActivityBilling.isPro(context) ? View.VISIBLE : View.INVISIBLE); + + ivSync.setVisibility(View.GONE); + + ivOAuth.setVisibility(View.GONE); + ivPrimary.setVisibility(View.GONE); + ivNotify.setVisibility(View.GONE); + if (account.unseen > 0) - tvName.setText(context.getString(R.string.title_name_count, account.name, NF.format(account.unseen))); + tvName.setText(context.getString(R.string.title_name_count, + account.getName(context), NF.format(account.unseen))); else - tvName.setText(account.name); + tvName.setText(account.getName(context)); tvName.setTypeface(account.unseen > 0 ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); tvName.setTextColor(account.unseen > 0 ? colorUnread : textColorSecondary); - } - StringBuilder user = new StringBuilder(account.user); - if (account.provider != null && (BuildConfig.DEBUG || debug)) - user.append(" (").append(account.provider).append(')'); - tvUser.setText(user); - - if ("connected".equals(account.state)) { - ivState.setImageResource(R.drawable.twotone_cloud_done_24); - ivState.setContentDescription(context.getString(R.string.title_legend_connected)); - } else if ("connecting".equals(account.state)) { - ivState.setImageResource(R.drawable.twotone_cloud_queue_24); - ivState.setContentDescription(context.getString(R.string.title_legend_connecting)); - } else if ("closing".equals(account.state)) { - ivState.setImageResource(R.drawable.twotone_cancel_24); - ivState.setContentDescription(context.getString(R.string.title_legend_closing)); - } else { - if (account.backoff_until == null) { - ivState.setImageResource(R.drawable.twotone_cloud_off_24); - ivState.setContentDescription(context.getString(R.string.title_legend_disconnected)); - } else { - ivState.setImageResource(R.drawable.twotone_update_24); - ivState.setContentDescription(context.getString(R.string.title_legend_backoff)); - } + tvUser.setVisibility(View.GONE); + + ivState.setVisibility(View.GONE); + + tvHost.setVisibility(View.GONE); + + tvCreated.setVisibility(View.GONE); + tvLast.setVisibility(View.GONE); + + tvBackoff.setVisibility(View.GONE); + + tvUsage.setVisibility(View.GONE); + tvQuota.setVisibility(View.GONE); + + tvMaxSize.setVisibility(View.GONE); + + tvId.setVisibility(View.GONE); + + tvCapabilities.setVisibility(View.GONE); + + tvIdentity.setVisibility(View.GONE); + tvDrafts.setVisibility(View.GONE); + tvSent.setVisibility(View.GONE); + + tvWarning.setVisibility(View.GONE); + + tvError.setVisibility(View.GONE); + btnHelp.setVisibility(View.GONE); + + ibInbox.setVisibility(View.GONE); + grpSettings.setVisibility(View.GONE); } - ivState.setVisibility(account.synchronize || account.state != null ? View.VISIBLE : View.INVISIBLE); - - tvHost.setText(String.format("%s:%d/%s", - account.host, - account.port, - EmailService.getEncryptionName(account.encryption))); - tvHost.setTextColor(account.insecure ? colorWarning : textColorTertiary); - tvCreated.setVisibility(debug ? View.VISIBLE : View.GONE); - tvCreated.setText(context.getString(R.string.title_created_at, - account.created == null ? null : DTF.format(account.created))); - tvLast.setVisibility(compact ? View.GONE : View.VISIBLE); - tvLast.setText(context.getString(R.string.title_last_connected, - (account.last_connected == null ? "-" : DTF.format(account.last_connected)) + - (BuildConfig.DEBUG ? - "/" + (account.last_modified == null ? "-" : DTF.format(account.last_modified)) + - " " + account.poll_interval + - "/" + account.keep_alive_ok + - "/" + account.keep_alive_failed + - "/" + account.keep_alive_succeeded : ""))); - - tvBackoff.setText(context.getString(R.string.title_backoff_until, - account.backoff_until == null ? "-" : DTF.format(account.backoff_until))); - tvBackoff.setVisibility(account.backoff_until == null || !settings ? View.GONE : View.VISIBLE); - - Integer percent = account.getQuotaPercentage(); - boolean warning = (percent != null && percent > EntityAccount.QUOTA_WARNING); - - tvUsage.setText(settings || percent == null ? null : NF.format(percent) + "%"); - tvUsage.setVisibility(settings || percent == null || (compact && !warning) ? View.GONE : View.VISIBLE); - tvQuota.setText(context.getString(R.string.title_storage_quota, - (account.quota_usage == null ? "-" : Helper.humanReadableByteCount(account.quota_usage)), - (account.quota_limit == null ? "-" : Helper.humanReadableByteCount(account.quota_limit)))); - tvQuota.setVisibility(settings && (account.quota_usage != null || account.quota_limit != null) ? View.VISIBLE : View.GONE); - - tvUsage.setTextColor(warning ? colorWarning : textColorSecondary); - tvUsage.setTypeface(warning ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); - - tvQuota.setTextColor(warning ? colorWarning : textColorSecondary); - tvQuota.setTypeface(warning ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT); - - tvMaxSize.setText(account.max_size == null ? null : Helper.humanReadableByteCount(account.max_size)); - tvMaxSize.setVisibility(settings && account.max_size != null && BuildConfig.DEBUG ? View.VISIBLE : View.GONE); - if (tvMaxSize.getVisibility() == View.VISIBLE) - tvQuota.setVisibility(View.VISIBLE); - - tvId.setText(account.id + "/" + account.uuid); - tvId.setVisibility(settings && BuildConfig.DEBUG ? View.VISIBLE : View.GONE); - - tvCapabilities.setText(account.capabilities); - - tvCapabilities.setVisibility(settings && (debug || BuildConfig.DEBUG) && - !TextUtils.isEmpty(account.capabilities) ? View.VISIBLE : View.GONE); - - tvIdentity.setVisibility(account.identities > 0 || !settings ? View.GONE : View.VISIBLE); - tvDrafts.setVisibility(account.drafts != null || !settings ? View.GONE : View.VISIBLE); - tvSent.setVisibility(account.protocol != EntityAccount.TYPE_IMAP || - account.sent != null || !settings ? View.GONE : View.VISIBLE); - - tvWarning.setText(account.warning); - tvWarning.setVisibility(account.warning == null || !settings ? View.GONE : View.VISIBLE); - - tvError.setText(account.error); - tvError.setVisibility(account.error == null ? View.GONE : View.VISIBLE); - btnHelp.setVisibility(account.error == null ? View.GONE : View.VISIBLE); - - ibInbox.setVisibility(settings ? View.GONE : View.VISIBLE); - grpSettings.setVisibility(settings ? View.VISIBLE : View.GONE); } @Override public void onClick(View view) { if (view.getId() == R.id.btnHelp) { int pos = getAdapterPosition(); - TupleAccountEx account = (pos == RecyclerView.NO_POSITION ? null : items.get(pos)); + TupleAccountFolder account = (pos == RecyclerView.NO_POSITION ? null : items.get(pos)); if (account == null) Helper.viewFAQ(context, 22); else { @@ -345,7 +403,7 @@ public class AdapterAccount extends RecyclerView.Adapter accounts) { + public void set(@NonNull List accounts) { Log.i("Set accounts=" + accounts.size()); + if (accounts.size() > 0) + TupleAccountFolder.sort(accounts, true, context); + DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new DiffCallback(items, accounts), false); items = accounts; @@ -865,10 +933,10 @@ public class AdapterAccount extends RecyclerView.Adapter prev = new ArrayList<>(); - private List next = new ArrayList<>(); + private List prev = new ArrayList<>(); + private List next = new ArrayList<>(); - DiffCallback(List prev, List next) { + DiffCallback(List prev, List next) { this.prev.addAll(prev); this.next.addAll(next); } @@ -885,15 +953,15 @@ public class AdapterAccount extends RecyclerView.Adapter= 0 && pos < items.size()) return items.get(pos); else @@ -923,7 +991,7 @@ public class AdapterAccount extends RecyclerView.Adapter accounts, boolean expanded, boolean folders) { Log.i("Set nav accounts=" + accounts.size()); - if (accounts.size() > 0) { - final Collator collator = Collator.getInstance(Locale.getDefault()); - collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc - - Collections.sort(accounts, new Comparator() { - @Override - public int compare(TupleAccountFolder a1, TupleAccountFolder a2) { - // Account - - if (nav_categories) { - int c = collator.compare( - a1.category == null ? "" : a1.category, - a2.category == null ? "" : a2.category); - if (c != 0) - return c; - } - - int a = Integer.compare( - a1.order == null ? -1 : a1.order, - a2.order == null ? -1 : a2.order); - if (a != 0) - return a; - - int p = -Boolean.compare(a1.primary, a2.primary); - if (p != 0) - return p; - - int n = collator.compare(a1.name, a2.name); - if (n != 0) - return n; - - // Folder - - int o = Integer.compare( - a1.folderOrder == null ? -1 : a1.folderOrder, - a2.folderOrder == null ? -1 : a2.folderOrder); - if (o != 0) - return o; - - int t1 = EntityFolder.FOLDER_SORT_ORDER.indexOf(a1.folderType); - int t2 = EntityFolder.FOLDER_SORT_ORDER.indexOf(a2.folderType); - int t = Integer.compare(t1, t2); - if (t != 0) - return t; - - int s = -Boolean.compare(a1.folderSync, a2.folderSync); - if (s != 0) - return s; - - if (a1.folderName == null && a2.folderName == null) - return 0; - else if (a1.folderName == null) - return -1; - else if (a2.folderName == null) - return 1; - - return collator.compare(a1.getName(context), a2.getName(context)); - } - }); - } + if (accounts.size() > 0) + TupleAccountFolder.sort(accounts, nav_categories, context); all = accounts; if (!folders) { diff --git a/app/src/main/java/eu/faircode/email/DaoAccount.java b/app/src/main/java/eu/faircode/email/DaoAccount.java index d32421619c..1c5634a30c 100644 --- a/app/src/main/java/eu/faircode/email/DaoAccount.java +++ b/app/src/main/java/eu/faircode/email/DaoAccount.java @@ -50,34 +50,11 @@ public interface DaoAccount { LiveData> liveSynchronizingAccounts(); @Query("SELECT account.*" + - ", (SELECT COUNT(DISTINCT" + - " CASE WHEN NOT message.hash IS NULL THEN message.hash" + - " WHEN NOT message.msgid IS NULL THEN message.msgid" + - " ELSE message.id END)" + - " FROM message" + - " JOIN folder ON folder.id = message.folder" + - " WHERE message.account = account.id" + - " AND folder.type <> '" + EntityFolder.OUTBOX + "'" + - " AND folder.count_unread" + - " AND NOT ui_seen" + - " AND NOT ui_hide) AS unseen" + ", (SELECT COUNT(identity.id)" + " FROM identity" + " WHERE identity.account = account.id" + " AND identity.synchronize) AS identities" + ", drafts.id AS drafts, sent.id AS sent" + - " FROM account" + - " LEFT JOIN folder AS drafts ON drafts.account = account.id AND drafts.type = '" + EntityFolder.DRAFTS + "'" + - " LEFT JOIN folder AS sent ON sent.account = account.id AND sent.type = '" + EntityFolder.SENT + "'" + - " WHERE :all OR account.synchronize" + - " GROUP BY account.id" + - " ORDER BY account.category COLLATE NOCASE" + - ", account.`order`" + - ", account.`primary` DESC" + - ", account.name COLLATE NOCASE") - LiveData> liveAccountsEx(boolean all); - - @Query("SELECT account.*" + ", NULL AS folderId, NULL AS folderSeparator" + ", NULL AS folderType, -1 AS folderOrder" + ", NULL AS folderName, NULL AS folderDisplay, NULL AS folderColor" + @@ -96,11 +73,14 @@ public interface DaoAccount { " AND NOT ui_seen" + " AND NOT ui_hide) AS unseen" + " FROM account" + - " WHERE account.synchronize" + + " LEFT JOIN folder AS drafts ON drafts.account = account.id AND drafts.type = '" + EntityFolder.DRAFTS + "'" + + " LEFT JOIN folder AS sent ON sent.account = account.id AND sent.type = '" + EntityFolder.SENT + "'" + + " WHERE (:settings OR account.synchronize)" + " UNION " + " SELECT account.*" + + ", 0 AS identities, 0 AS drafts, 0 AS sent" + ", folder.id AS folderId, folder.separator AS folderSeparator" + ", folder.type AS folderType, folder.`order` AS folderOrder" + ", folder.name AS folderName, folder.display AS folderDisplay, folder.color AS folderColor" + @@ -120,10 +100,10 @@ public interface DaoAccount { " FROM account" + " JOIN folder ON folder.account = account.id" + " LEFT JOIN operation ON operation.folder = folder.id AND operation.state = 'executing'" + - " WHERE account.synchronize" + - " AND folder.navigation" + + " WHERE (:settings OR account.synchronize)" + + " AND NOT :settings AND folder.navigation" + " GROUP BY folder.id") - LiveData> liveAccountFolder(); + LiveData> liveAccountFolder(boolean settings); @Query("SELECT account.*" + ", SUM(folder.synchronize) AS folders" + diff --git a/app/src/main/java/eu/faircode/email/FragmentAccounts.java b/app/src/main/java/eu/faircode/email/FragmentAccounts.java index ecb5bc731c..60964e39db 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAccounts.java +++ b/app/src/main/java/eu/faircode/email/FragmentAccounts.java @@ -58,9 +58,12 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; +import java.text.Collator; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Locale; import java.util.Objects; public class FragmentAccounts extends FragmentBase { @@ -183,8 +186,8 @@ public class FragmentAccounts extends FragmentBase { if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) return null; - TupleAccountEx prev = adapter.getItemAtPosition(pos - 1); - TupleAccountEx account = adapter.getItemAtPosition(pos); + TupleAccountFolder prev = adapter.getItemAtPosition(pos - 1); + TupleAccountFolder account = adapter.getItemAtPosition(pos); if (pos > 0 && prev == null) return null; if (account == null) @@ -309,15 +312,15 @@ public class FragmentAccounts extends FragmentBase { final DB db = DB.getInstance(context); // Observe accounts - db.account().liveAccountsEx(settings) - .observe(getViewLifecycleOwner(), new Observer>() { + db.account().liveAccountFolder(settings) + .observe(getViewLifecycleOwner(), new Observer>() { @Override - public void onChanged(@Nullable List accounts) { + public void onChanged(@Nullable List accounts) { if (accounts == null) accounts = new ArrayList<>(); boolean authorized = true; - for (TupleAccountEx account : accounts) + for (TupleAccountFolder account : accounts) if (account.auth_type != AUTH_TYPE_PASSWORD && !Helper.hasPermissions(getContext(), Helper.getOAuthPermissions())) { authorized = false; diff --git a/app/src/main/java/eu/faircode/email/TupleAccountEx.java b/app/src/main/java/eu/faircode/email/TupleAccountEx.java deleted file mode 100644 index 7d283b2cdd..0000000000 --- a/app/src/main/java/eu/faircode/email/TupleAccountEx.java +++ /dev/null @@ -1,42 +0,0 @@ -package eu.faircode.email; - -/* - This file is part of FairEmail. - - FairEmail is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - FairEmail is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with FairEmail. If not, see . - - Copyright 2018-2024 by Marcel Bokhorst (M66B) -*/ - -import java.util.Objects; - -public class TupleAccountEx extends EntityAccount { - public int unseen; - public int identities; // synchronizing - public Long drafts; - public Long sent; - - @Override - public boolean equals(Object obj) { - if (obj instanceof TupleAccountEx) { - TupleAccountEx other = (TupleAccountEx) obj; - return (super.equals(obj) && - this.unseen == other.unseen && - this.identities == other.identities && - Objects.equals(this.drafts, other.drafts) && - Objects.equals(this.sent, other.sent)); - } else - return false; - } -} diff --git a/app/src/main/java/eu/faircode/email/TupleAccountFolder.java b/app/src/main/java/eu/faircode/email/TupleAccountFolder.java index 86bda37512..27a99907df 100644 --- a/app/src/main/java/eu/faircode/email/TupleAccountFolder.java +++ b/app/src/main/java/eu/faircode/email/TupleAccountFolder.java @@ -21,9 +21,18 @@ package eu.faircode.email; import android.content.Context; +import java.text.Collator; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; import java.util.Objects; public class TupleAccountFolder extends EntityAccount { + public int identities; // synchronizing + public Long drafts; + public Long sent; + public Long folderId; public Character folderSeparator; public String folderType; @@ -58,11 +67,76 @@ public class TupleAccountFolder extends EntityAccount { return folderName.substring(s + 1); } + static void sort(List accounts, boolean nav_categories, Context context) { + final Collator collator = Collator.getInstance(Locale.getDefault()); + collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc + + Collections.sort(accounts, new Comparator() { + @Override + public int compare(TupleAccountFolder a1, TupleAccountFolder a2) { + // Account + + if (nav_categories) { + int c = collator.compare( + a1.category == null ? "" : a1.category, + a2.category == null ? "" : a2.category); + if (c != 0) + return c; + } + + int a = Integer.compare( + a1.order == null ? -1 : a1.order, + a2.order == null ? -1 : a2.order); + if (a != 0) + return a; + + int p = -Boolean.compare(a1.primary, a2.primary); + if (p != 0) + return p; + + int n = collator.compare(a1.name, a2.name); + if (n != 0) + return n; + + // Folder + + int o = Integer.compare( + a1.folderOrder == null ? -1 : a1.folderOrder, + a2.folderOrder == null ? -1 : a2.folderOrder); + if (o != 0) + return o; + + int t1 = EntityFolder.FOLDER_SORT_ORDER.indexOf(a1.folderType); + int t2 = EntityFolder.FOLDER_SORT_ORDER.indexOf(a2.folderType); + int t = Integer.compare(t1, t2); + if (t != 0) + return t; + + int s = -Boolean.compare(a1.folderSync, a2.folderSync); + if (s != 0) + return s; + + if (a1.folderName == null && a2.folderName == null) + return 0; + else if (a1.folderName == null) + return -1; + else if (a2.folderName == null) + return 1; + + return collator.compare(a1.getName(context), a2.getName(context)); + } + }); + } + @Override public boolean equals(Object obj) { if (obj instanceof TupleAccountFolder) { TupleAccountFolder other = (TupleAccountFolder) obj; return (super.equals(obj) && + this.identities == other.identities && + Objects.equals(this.drafts, other.drafts) && + Objects.equals(this.sent, other.sent) && + Objects.equals(this.folderId, other.folderId) && Objects.equals(this.folderSeparator, other.folderSeparator) && Objects.equals(this.folderType, other.folderType) &&