diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index b4c5d920..f714afc9 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -39,6 +39,15 @@ public class Preferences { _prefs.edit().putInt("pref_tap_to_reveal_time", number).apply(); } + public void setCurrentSortCategory(SortCategory category) { + _prefs.edit().putInt("pref_current_sort_category", category.ordinal()).apply(); + } + + public int getCurrentSortCategory() { + return _prefs.getInt("pref_current_sort_category", 0); + } + + public int getTapToRevealTime() { return _prefs.getInt("pref_tap_to_reveal_time", 30); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/SortCategory.java b/app/src/main/java/com/beemdevelopment/aegis/SortCategory.java new file mode 100644 index 00000000..7e6e6bbf --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/SortCategory.java @@ -0,0 +1,73 @@ +package com.beemdevelopment.aegis; + +import com.beemdevelopment.aegis.helpers.comparators.AccountNameComparator; +import com.beemdevelopment.aegis.helpers.comparators.IssuerNameComparator; + +import java.util.Comparator; + +public enum SortCategory { + CUSTOM, + ACCOUNT, + ACCOUNTREVERSED, + ISSUER, + ISSUERREVERSED; + + public static SortCategory fromInteger(int x) { + switch(x) { + case 0: + return CUSTOM; + case 1: + return ACCOUNT; + case 2: + return ACCOUNTREVERSED; + case 3: + return ISSUER; + case 4: + return ISSUERREVERSED; + } + return null; + } + + public static Comparator getComparator(SortCategory sortCategory) { + switch(sortCategory) { + case ACCOUNT: + case ACCOUNTREVERSED: + return new AccountNameComparator(); + case ISSUER: + case ISSUERREVERSED: + return new IssuerNameComparator(); + case CUSTOM: + return new IssuerNameComparator(); + } + return null; + } + + public static boolean isReversed(SortCategory sortCategory) { + switch(sortCategory) { + case ACCOUNTREVERSED: + case ISSUERREVERSED: + return true; + + default: + return false; + } + } + + public static int getMenuItem(SortCategory sortCategory) { + switch (sortCategory) { + case CUSTOM: + return R.id.menu_sort_custom; + case ACCOUNT: + return R.id.menu_sort_alphabetically_name; + case ACCOUNTREVERSED: + return R.id.menu_sort_alphabetically_name_reverse; + case ISSUER: + return R.id.menu_sort_alphabetically; + case ISSUERREVERSED: + return R.id.menu_sort_alphabetically_reverse; + + default: + return R.id.menu_sort_custom; + } + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/AccountNameComparator.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/AccountNameComparator.java new file mode 100644 index 00000000..07143749 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/AccountNameComparator.java @@ -0,0 +1,12 @@ +package com.beemdevelopment.aegis.helpers.comparators; + +import com.beemdevelopment.aegis.db.DatabaseEntry; + +import java.util.Comparator; + +public class AccountNameComparator implements Comparator { + @Override + public int compare(DatabaseEntry a, DatabaseEntry b) { + return a.getName().compareToIgnoreCase(b.getName()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/IssuerNameComparator.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/IssuerNameComparator.java new file mode 100644 index 00000000..283c97fa --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/IssuerNameComparator.java @@ -0,0 +1,13 @@ +package com.beemdevelopment.aegis.helpers.comparators; + +import com.beemdevelopment.aegis.db.DatabaseEntry; +import com.beemdevelopment.aegis.ui.views.EntryHolder; + +import java.util.Comparator; + +public class IssuerNameComparator implements Comparator { + @Override + public int compare(DatabaseEntry a, DatabaseEntry b) { + return a.getIssuer().compareToIgnoreCase(b.getIssuer()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java index 4943ba20..029faa11 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -8,6 +8,9 @@ import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.graphics.Rect; + +import com.beemdevelopment.aegis.SortCategory; +import com.beemdevelopment.aegis.helpers.comparators.IssuerNameComparator; import com.google.android.material.bottomsheet.BottomSheetDialog; import android.os.Bundle; import android.view.Menu; @@ -27,6 +30,8 @@ import com.beemdevelopment.aegis.ui.views.EntryListView; import java.lang.reflect.UndeclaredThrowableException; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.TreeSet; import com.beemdevelopment.aegis.AegisApplication; @@ -55,6 +60,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private DatabaseManager _db; private boolean _loaded; private String _checkedGroup; + private SortCategory _sortCategory; private Menu _menu; private FloatingActionsMenu _fabMenu; @@ -257,6 +263,22 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _entryListView.setGroupFilter(group); } + private void setSortCategory(SortCategory sortCategory) { + _sortCategory = sortCategory; + + if(sortCategory == SortCategory.CUSTOM) + { + _entryListView.clearEntries(); + loadEntries(); + } + + _entryListView.setSortCategory(sortCategory); + } + + private void updateSortCategoryMenu(SortCategory sortCategory) { + _menu.findItem(SortCategory.getMenuItem(sortCategory)).setChecked(true); + } + private void addEntry(DatabaseEntry entry) { _db.addEntry(entry); _entryListView.addEntry(entry); @@ -398,6 +420,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene updateLockIcon(); if (_loaded) { updateGroupFilterMenu(); + updateSortCategoryMenu(SortCategory.fromInteger(getPreferences().getCurrentSortCategory())); } return true; } @@ -422,6 +445,37 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } setGroupFilter(group); } + + if (item.getGroupId() == R.id.action_sort_category) { + item.setChecked(true); + + SortCategory sortCategory; + switch (item.getItemId()) { + case R.id.menu_sort_alphabetically: + sortCategory = SortCategory.ISSUER; + break; + + case R.id.menu_sort_alphabetically_reverse: + sortCategory = SortCategory.ISSUERREVERSED; + break; + + case R.id.menu_sort_alphabetically_name: + sortCategory = SortCategory.ACCOUNT; + break; + + case R.id.menu_sort_alphabetically_name_reverse: + sortCategory = SortCategory.ACCOUNTREVERSED; + break; + + case R.id.menu_sort_custom: + default: + sortCategory = SortCategory.CUSTOM; + break; + } + + setSortCategory(sortCategory); + getPreferences().setCurrentSortCategory(sortCategory); + } return super.onOptionsItemSelected(item); } } @@ -459,11 +513,14 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } loadEntries(); + SortCategory currentSortCategory = SortCategory.fromInteger(getPreferences().getCurrentSortCategory()); + setSortCategory(currentSortCategory); } private void loadEntries() { // load all entries - _entryListView.addEntries(_db.getEntries()); + List entries = new ArrayList(_db.getEntries()); + _entryListView.addEntries(entries); _loaded = true; } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java index b6185731..9f7fa08a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java @@ -5,7 +5,9 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import com.beemdevelopment.aegis.SortCategory; import com.beemdevelopment.aegis.helpers.ItemTouchHelperAdapter; +import com.beemdevelopment.aegis.helpers.comparators.IssuerNameComparator; import com.beemdevelopment.aegis.otp.HotpInfo; import com.beemdevelopment.aegis.otp.OtpInfo; import com.beemdevelopment.aegis.otp.OtpInfoException; @@ -27,6 +29,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I private boolean _tapToReveal; private int _tapToRevealTime; private String _groupFilter; + private SortCategory _sortCategory; // keeps track of the viewholders that are currently bound private List _holders; @@ -151,6 +154,21 @@ public class EntryAdapter extends RecyclerView.Adapter implements I notifyDataSetChanged(); } + public void setSortCategory(SortCategory sortCategory) { + if (_sortCategory != sortCategory && sortCategory != SortCategory.CUSTOM) { + Collections.sort(_shownEntries, SortCategory.getComparator(sortCategory)); + + if(SortCategory.isReversed(sortCategory)) + { + Collections.reverse(_shownEntries); + } + + notifyDataSetChanged(); + } + + _sortCategory = sortCategory; + } + @Override public void onItemDismiss(int position) { diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java index d059f015..99f7c4e6 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java @@ -14,6 +14,7 @@ import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.view.animation.LayoutAnimationController; +import com.beemdevelopment.aegis.SortCategory; import com.beemdevelopment.aegis.helpers.SimpleItemTouchHelperCallback; import com.beemdevelopment.aegis.helpers.UiRefresher; import com.beemdevelopment.aegis.otp.TotpInfo; @@ -93,6 +94,13 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { runLayoutAnimation(_rvKeyProfiles); } + public void setSortCategory(SortCategory sortCategory) { + _touchCallback.setIsLongPressDragEnabled(sortCategory == SortCategory.CUSTOM); + + _adapter.setSortCategory(sortCategory); + runLayoutAnimation(_rvKeyProfiles); + } + public void refresh(boolean hard) { if (_showProgress) { _progressBar.refresh(); diff --git a/app/src/main/res/drawable-anydpi/ic_action_sort.xml b/app/src/main/res/drawable-anydpi/ic_action_sort.xml new file mode 100644 index 00000000..ef66d1c4 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_action_sort.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_action_sort.png b/app/src/main/res/drawable-hdpi/ic_action_sort.png new file mode 100644 index 00000000..fe9573f4 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_sort.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_sort.png b/app/src/main/res/drawable-mdpi/ic_action_sort.png new file mode 100644 index 00000000..a9588ed3 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_sort.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_sort.png b/app/src/main/res/drawable-xhdpi/ic_action_sort.png new file mode 100644 index 00000000..2184723d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_sort.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_sort.png b/app/src/main/res/drawable-xxhdpi/ic_action_sort.png new file mode 100644 index 00000000..ca1da315 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_sort.png differ diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 87fdf361..4d9644d5 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -21,6 +21,35 @@ android:title="@string/all" android:checked="true" /> + + + + + + + + + + + + All Name No group + Issuer (A to Z) + Issuer (Z to A) + Account (A to Z) + Account (Z to A) + Custom New group... Enter a group name Group name