mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-04 20:30:36 +00:00
Fix the last couple of sorting bugs (#77)
This fixes the following bugs: - Sort category is forgotten after lock/unlock - The sort mode is not respected for new entries I got a little carried away while working on this patch and also included the following other enhancements: - Simplify the SortCategory, Theme and ViewMode enums - Simplify usage of string resources - Don't call notifyDataSetChanged and runLayoutAnimation unnecessarily
This commit is contained in:
parent
0a8dd56306
commit
6d26d1beb0
12 changed files with 264 additions and 309 deletions
|
@ -43,24 +43,24 @@ public class Preferences {
|
||||||
_prefs.edit().putInt("pref_current_sort_category", category.ordinal()).apply();
|
_prefs.edit().putInt("pref_current_sort_category", category.ordinal()).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentSortCategory() {
|
public SortCategory getCurrentSortCategory() {
|
||||||
return _prefs.getInt("pref_current_sort_category", 0);
|
return SortCategory.fromInteger(_prefs.getInt("pref_current_sort_category", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTapToRevealTime() {
|
public int getTapToRevealTime() {
|
||||||
return _prefs.getInt("pref_tap_to_reveal_time", 30);
|
return _prefs.getInt("pref_tap_to_reveal_time", 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentTheme() {
|
public Theme getCurrentTheme() {
|
||||||
return _prefs.getInt("pref_current_theme", 0);
|
return Theme.fromInteger(_prefs.getInt("pref_current_theme", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentTheme(Theme theme) {
|
public void setCurrentTheme(Theme theme) {
|
||||||
_prefs.edit().putInt("pref_current_theme", theme.ordinal()).apply();
|
_prefs.edit().putInt("pref_current_theme", theme.ordinal()).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentViewMode() {
|
public ViewMode getCurrentViewMode() {
|
||||||
return _prefs.getInt("pref_current_view_mode", 0);
|
return ViewMode.fromInteger(_prefs.getInt("pref_current_view_mode", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentViewMode(ViewMode viewMode) {
|
public void setCurrentViewMode(ViewMode viewMode) {
|
||||||
|
|
|
@ -1,69 +1,61 @@
|
||||||
package com.beemdevelopment.aegis;
|
package com.beemdevelopment.aegis;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.db.DatabaseEntry;
|
||||||
import com.beemdevelopment.aegis.helpers.comparators.AccountNameComparator;
|
import com.beemdevelopment.aegis.helpers.comparators.AccountNameComparator;
|
||||||
import com.beemdevelopment.aegis.helpers.comparators.IssuerNameComparator;
|
import com.beemdevelopment.aegis.helpers.comparators.IssuerNameComparator;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public enum SortCategory {
|
public enum SortCategory {
|
||||||
CUSTOM,
|
CUSTOM,
|
||||||
ACCOUNT,
|
ACCOUNT,
|
||||||
ACCOUNTREVERSED,
|
ACCOUNT_REVERSED,
|
||||||
ISSUER,
|
ISSUER,
|
||||||
ISSUERREVERSED;
|
ISSUER_REVERSED;
|
||||||
|
|
||||||
|
private static SortCategory[] _values;
|
||||||
|
|
||||||
|
static {
|
||||||
|
_values = values();
|
||||||
|
}
|
||||||
|
|
||||||
public static SortCategory fromInteger(int x) {
|
public static SortCategory fromInteger(int x) {
|
||||||
switch (x) {
|
return _values[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) {
|
public Comparator<DatabaseEntry> getComparator() {
|
||||||
switch (sortCategory) {
|
Comparator<DatabaseEntry> comparator = null;
|
||||||
|
|
||||||
|
switch (this) {
|
||||||
case ACCOUNT:
|
case ACCOUNT:
|
||||||
case ACCOUNTREVERSED:
|
comparator = new AccountNameComparator();
|
||||||
return new AccountNameComparator();
|
break;
|
||||||
|
case ACCOUNT_REVERSED:
|
||||||
|
comparator = Collections.reverseOrder(new AccountNameComparator());
|
||||||
|
break;
|
||||||
case ISSUER:
|
case ISSUER:
|
||||||
case ISSUERREVERSED:
|
comparator = new IssuerNameComparator();
|
||||||
return new IssuerNameComparator();
|
break;
|
||||||
case CUSTOM:
|
case ISSUER_REVERSED:
|
||||||
return new IssuerNameComparator();
|
comparator = Collections.reverseOrder(new IssuerNameComparator());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return comparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isReversed(SortCategory sortCategory) {
|
public int getMenuItem() {
|
||||||
switch (sortCategory) {
|
switch (this) {
|
||||||
case ACCOUNTREVERSED:
|
|
||||||
case ISSUERREVERSED:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getMenuItem(SortCategory sortCategory) {
|
|
||||||
switch (sortCategory) {
|
|
||||||
case CUSTOM:
|
case CUSTOM:
|
||||||
return R.id.menu_sort_custom;
|
return R.id.menu_sort_custom;
|
||||||
case ACCOUNT:
|
case ACCOUNT:
|
||||||
return R.id.menu_sort_alphabetically_name;
|
return R.id.menu_sort_alphabetically_name;
|
||||||
case ACCOUNTREVERSED:
|
case ACCOUNT_REVERSED:
|
||||||
return R.id.menu_sort_alphabetically_name_reverse;
|
return R.id.menu_sort_alphabetically_name_reverse;
|
||||||
case ISSUER:
|
case ISSUER:
|
||||||
return R.id.menu_sort_alphabetically;
|
return R.id.menu_sort_alphabetically;
|
||||||
case ISSUERREVERSED:
|
case ISSUER_REVERSED:
|
||||||
return R.id.menu_sort_alphabetically_reverse;
|
return R.id.menu_sort_alphabetically_reverse;
|
||||||
default:
|
default:
|
||||||
return R.id.menu_sort_custom;
|
return R.id.menu_sort_custom;
|
||||||
|
|
|
@ -5,43 +5,13 @@ public enum Theme {
|
||||||
DARK,
|
DARK,
|
||||||
AMOLED;
|
AMOLED;
|
||||||
|
|
||||||
|
private static Theme[] _values;
|
||||||
|
|
||||||
|
static {
|
||||||
|
_values = values();
|
||||||
|
}
|
||||||
|
|
||||||
public static Theme fromInteger(int x) {
|
public static Theme fromInteger(int x) {
|
||||||
switch (x) {
|
return _values[x];
|
||||||
case 0:
|
|
||||||
return LIGHT;
|
|
||||||
case 1:
|
|
||||||
return DARK;
|
|
||||||
case 2:
|
|
||||||
return AMOLED;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getThemeNameResource(int x) {
|
|
||||||
switch (x) {
|
|
||||||
case 0:
|
|
||||||
return R.string.light_theme_title;
|
|
||||||
case 1:
|
|
||||||
return R.string.dark_theme_title;
|
|
||||||
case 2:
|
|
||||||
return R.string.amoled_theme_title;
|
|
||||||
}
|
|
||||||
return R.string.light_theme_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getThemeNames() {
|
|
||||||
return new String[]{
|
|
||||||
"Light theme",
|
|
||||||
"Dark theme",
|
|
||||||
"Amoled theme"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int[] getThemeNameResources() {
|
|
||||||
return new int[] {
|
|
||||||
R.string.light_theme_title,
|
|
||||||
R.string.dark_theme_title,
|
|
||||||
R.string.amoled_theme_title
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,33 @@
|
||||||
package com.beemdevelopment.aegis;
|
package com.beemdevelopment.aegis;
|
||||||
|
|
||||||
|
import androidx.annotation.LayoutRes;
|
||||||
|
|
||||||
public enum ViewMode {
|
public enum ViewMode {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
COMPACT,
|
COMPACT,
|
||||||
SMALL;
|
SMALL;
|
||||||
|
|
||||||
|
private static ViewMode[] _values;
|
||||||
|
|
||||||
|
static {
|
||||||
|
_values = values();
|
||||||
|
}
|
||||||
|
|
||||||
public static ViewMode fromInteger(int x) {
|
public static ViewMode fromInteger(int x) {
|
||||||
switch (x) {
|
return _values[x];
|
||||||
case 0:
|
}
|
||||||
return NORMAL;
|
|
||||||
case 1:
|
@LayoutRes
|
||||||
return COMPACT;
|
public int getLayoutId() {
|
||||||
case 2:
|
switch (this) {
|
||||||
return SMALL;
|
case NORMAL:
|
||||||
|
return R.layout.card_entry;
|
||||||
|
case COMPACT:
|
||||||
|
return R.layout.card_entry_compact;
|
||||||
|
case SMALL:
|
||||||
|
return R.layout.card_entry_small;
|
||||||
|
default:
|
||||||
|
return R.layout.card_entry;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getViewModeNameResource(int x) {
|
|
||||||
switch (x) {
|
|
||||||
case 0:
|
|
||||||
return R.string.normal_viewmode_title;
|
|
||||||
case 1:
|
|
||||||
return R.string.compact_mode_title;
|
|
||||||
case 2:
|
|
||||||
return R.string.small_mode_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
return R.string.normal_viewmode_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getViewModeNames() {
|
|
||||||
return new String[]{
|
|
||||||
"Normal",
|
|
||||||
"Compact",
|
|
||||||
"Small"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int[] getViewModeNameResources() {
|
|
||||||
return new int[] {
|
|
||||||
R.string.normal_viewmode_title,
|
|
||||||
R.string.compact_mode_title,
|
|
||||||
R.string.small_mode_title
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public abstract class AegisActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the theme
|
// set the theme
|
||||||
setPreferredTheme(Theme.fromInteger(getPreferences().getCurrentTheme()));
|
setPreferredTheme(getPreferences().getCurrentTheme());
|
||||||
|
|
||||||
// apply a dirty hack to make progress bars work even if animations are disabled
|
// apply a dirty hack to make progress bars work even if animations are disabled
|
||||||
setGlobalAnimationDurationScale();
|
setGlobalAnimationDurationScale();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package com.beemdevelopment.aegis.ui;
|
package com.beemdevelopment.aegis.ui;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -16,9 +14,6 @@ import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SubMenu;
|
import android.view.SubMenu;
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.AccelerateInterpolator;
|
|
||||||
import android.view.animation.DecelerateInterpolator;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
@ -48,15 +43,12 @@ import com.google.zxing.Reader;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
||||||
|
|
||||||
public class MainActivity extends AegisActivity implements EntryListView.Listener {
|
public class MainActivity extends AegisActivity implements EntryListView.Listener {
|
||||||
// activity request codes
|
// activity request codes
|
||||||
private static final int CODE_SCAN = 0;
|
private static final int CODE_SCAN = 0;
|
||||||
|
@ -98,7 +90,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
_entryListView.setShowAccountName(getPreferences().isAccountNameVisible());
|
_entryListView.setShowAccountName(getPreferences().isAccountNameVisible());
|
||||||
_entryListView.setTapToReveal(getPreferences().isTapToRevealEnabled());
|
_entryListView.setTapToReveal(getPreferences().isTapToRevealEnabled());
|
||||||
_entryListView.setTapToRevealTime(getPreferences().getTapToRevealTime());
|
_entryListView.setTapToRevealTime(getPreferences().getTapToRevealTime());
|
||||||
_entryListView.setViewMode(ViewMode.fromInteger(getPreferences().getCurrentViewMode()));
|
_entryListView.setSortCategory(getPreferences().getCurrentSortCategory(), false);
|
||||||
|
_entryListView.setViewMode(getPreferences().getCurrentViewMode());
|
||||||
|
|
||||||
// set up the floating action button
|
// set up the floating action button
|
||||||
_fabMenu = findViewById(R.id.fab);
|
_fabMenu = findViewById(R.id.fab);
|
||||||
|
@ -203,9 +196,11 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
boolean showAccountName = getPreferences().isAccountNameVisible();
|
boolean showAccountName = getPreferences().isAccountNameVisible();
|
||||||
boolean tapToReveal = getPreferences().isTapToRevealEnabled();
|
boolean tapToReveal = getPreferences().isTapToRevealEnabled();
|
||||||
int tapToRevealTime = getPreferences().getTapToRevealTime();
|
int tapToRevealTime = getPreferences().getTapToRevealTime();
|
||||||
|
ViewMode viewMode = getPreferences().getCurrentViewMode();
|
||||||
_entryListView.setShowAccountName(showAccountName);
|
_entryListView.setShowAccountName(showAccountName);
|
||||||
_entryListView.setTapToReveal(tapToReveal);
|
_entryListView.setTapToReveal(tapToReveal);
|
||||||
_entryListView.setTapToRevealTime(tapToRevealTime);
|
_entryListView.setTapToRevealTime(tapToRevealTime);
|
||||||
|
_entryListView.setViewMode(viewMode);
|
||||||
_entryListView.refresh(true);
|
_entryListView.refresh(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,23 +312,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
menu.setGroupCheckable(R.id.action_filter_group, true, true);
|
menu.setGroupCheckable(R.id.action_filter_group, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSortCategoryMenu() {
|
||||||
|
SortCategory category = getPreferences().getCurrentSortCategory();
|
||||||
|
_menu.findItem(category.getMenuItem()).setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
private void setGroupFilter(String group) {
|
private void setGroupFilter(String group) {
|
||||||
getSupportActionBar().setSubtitle(group);
|
getSupportActionBar().setSubtitle(group);
|
||||||
_checkedGroup = group;
|
_checkedGroup = group;
|
||||||
_entryListView.setGroupFilter(group);
|
_entryListView.setGroupFilter(group, true);
|
||||||
}
|
|
||||||
|
|
||||||
private void setSortCategory(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) {
|
private void addEntry(DatabaseEntry entry) {
|
||||||
|
@ -412,7 +399,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
}
|
}
|
||||||
|
|
||||||
// refresh all codes to prevent showing old ones
|
// refresh all codes to prevent showing old ones
|
||||||
_entryListView.refresh(true);
|
_entryListView.refresh(false);
|
||||||
} else {
|
} else {
|
||||||
loadEntries();
|
loadEntries();
|
||||||
}
|
}
|
||||||
|
@ -481,7 +468,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
updateLockIcon();
|
updateLockIcon();
|
||||||
if (_loaded) {
|
if (_loaded) {
|
||||||
updateGroupFilterMenu();
|
updateGroupFilterMenu();
|
||||||
updateSortCategoryMenu(SortCategory.fromInteger(getPreferences().getCurrentSortCategory()));
|
updateSortCategoryMenu();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -517,13 +504,13 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
sortCategory = SortCategory.ISSUER;
|
sortCategory = SortCategory.ISSUER;
|
||||||
break;
|
break;
|
||||||
case R.id.menu_sort_alphabetically_reverse:
|
case R.id.menu_sort_alphabetically_reverse:
|
||||||
sortCategory = SortCategory.ISSUERREVERSED;
|
sortCategory = SortCategory.ISSUER_REVERSED;
|
||||||
break;
|
break;
|
||||||
case R.id.menu_sort_alphabetically_name:
|
case R.id.menu_sort_alphabetically_name:
|
||||||
sortCategory = SortCategory.ACCOUNT;
|
sortCategory = SortCategory.ACCOUNT;
|
||||||
break;
|
break;
|
||||||
case R.id.menu_sort_alphabetically_name_reverse:
|
case R.id.menu_sort_alphabetically_name_reverse:
|
||||||
sortCategory = SortCategory.ACCOUNTREVERSED;
|
sortCategory = SortCategory.ACCOUNT_REVERSED;
|
||||||
break;
|
break;
|
||||||
case R.id.menu_sort_custom:
|
case R.id.menu_sort_custom:
|
||||||
default:
|
default:
|
||||||
|
@ -531,7 +518,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSortCategory(sortCategory);
|
_entryListView.setSortCategory(sortCategory, true);
|
||||||
getPreferences().setCurrentSortCategory(sortCategory);
|
getPreferences().setCurrentSortCategory(sortCategory);
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
@ -570,14 +557,13 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
}
|
}
|
||||||
|
|
||||||
loadEntries();
|
loadEntries();
|
||||||
SortCategory currentSortCategory = SortCategory.fromInteger(getPreferences().getCurrentSortCategory());
|
|
||||||
setSortCategory(currentSortCategory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadEntries() {
|
private void loadEntries() {
|
||||||
// load all entries
|
// load all entries
|
||||||
List<DatabaseEntry> entries = new ArrayList<DatabaseEntry>(_db.getEntries());
|
List<DatabaseEntry> entries = new ArrayList<DatabaseEntry>(_db.getEntries());
|
||||||
_entryListView.addEntries(entries);
|
_entryListView.addEntries(entries);
|
||||||
|
_entryListView.runEntriesAnimation();
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,18 +89,17 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
// set the result intent in advance
|
// set the result intent in advance
|
||||||
setResult(new Intent());
|
setResult(new Intent());
|
||||||
|
|
||||||
int currentTheme = app.getPreferences().getCurrentTheme();
|
int currentTheme = app.getPreferences().getCurrentTheme().ordinal();
|
||||||
Preference darkModePreference = findPreference("pref_dark_mode");
|
Preference darkModePreference = findPreference("pref_dark_mode");
|
||||||
darkModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getString(Theme.getThemeNameResource(currentTheme))));
|
darkModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.theme_titles)[currentTheme]));
|
||||||
darkModePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
darkModePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
String[] themeNames = getStringsFromResourceIds(Theme.getThemeNameResources());
|
int currentTheme = app.getPreferences().getCurrentTheme().ordinal();
|
||||||
int checkedTheme = app.getPreferences().getCurrentTheme();
|
|
||||||
|
|
||||||
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
||||||
.setTitle(getString(R.string.choose_theme))
|
.setTitle(R.string.choose_theme)
|
||||||
.setSingleChoiceItems(themeNames, checkedTheme, (dialog, which) -> {
|
.setSingleChoiceItems(R.array.theme_titles, currentTheme, (dialog, which) -> {
|
||||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||||
app.getPreferences().setCurrentTheme(Theme.fromInteger(i));
|
app.getPreferences().setCurrentTheme(Theme.fromInteger(i));
|
||||||
|
|
||||||
|
@ -116,34 +115,22 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
darkModePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
int currentViewMode = app.getPreferences().getCurrentViewMode().ordinal();
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
_result.putExtra("needsRecreate", true);
|
|
||||||
getActivity().recreate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
int currentViewMode = app.getPreferences().getCurrentViewMode();
|
|
||||||
Preference viewModePreference = findPreference("pref_view_mode");
|
Preference viewModePreference = findPreference("pref_view_mode");
|
||||||
viewModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getString(ViewMode.getViewModeNameResource(currentViewMode))));
|
viewModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.view_mode_titles)[currentViewMode]));
|
||||||
viewModePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
viewModePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
String[] viewModes = getStringsFromResourceIds(ViewMode.getViewModeNameResources());
|
int currentViewMode = app.getPreferences().getCurrentViewMode().ordinal();
|
||||||
int checkedMode = app.getPreferences().getCurrentViewMode();
|
|
||||||
|
|
||||||
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
||||||
.setTitle(getString(R.string.choose_view_mode))
|
.setTitle(R.string.choose_view_mode)
|
||||||
.setSingleChoiceItems(viewModes, checkedMode, (dialog, which) -> {
|
.setSingleChoiceItems(R.array.view_mode_titles, currentViewMode, (dialog, which) -> {
|
||||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||||
app.getPreferences().setCurrentViewMode(ViewMode.fromInteger(i));
|
app.getPreferences().setCurrentViewMode(ViewMode.fromInteger(i));
|
||||||
|
viewModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.view_mode_titles)[i]));
|
||||||
|
_result.putExtra("needsRefresh", true);
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
|
|
||||||
viewModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getString(ViewMode.getViewModeNameResource(i))));
|
|
||||||
_result.putExtra("needsRecreate", true);
|
|
||||||
})
|
})
|
||||||
.setPositiveButton(android.R.string.ok, null)
|
.setPositiveButton(android.R.string.ok, null)
|
||||||
.create());
|
.create());
|
||||||
|
@ -245,14 +232,14 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
Dialogs.showSetPasswordDialog(getActivity(), new EnableEncryptionListener());
|
Dialogs.showSetPasswordDialog(getActivity(), new EnableEncryptionListener());
|
||||||
} else {
|
} else {
|
||||||
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
||||||
.setTitle(getString(R.string.disable_encryption))
|
.setTitle(R.string.disable_encryption)
|
||||||
.setMessage(getString(R.string.disable_encryption_description))
|
.setMessage(getString(R.string.disable_encryption_description))
|
||||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
try {
|
try {
|
||||||
_db.disableEncryption();
|
_db.disableEncryption();
|
||||||
} catch (DatabaseManagerException e) {
|
} catch (DatabaseManagerException e) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.disable_encryption_error), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.disable_encryption_error, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +330,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||||
if (!PermissionHelper.checkResults(grantResults)) {
|
if (!PermissionHelper.checkResults(grantResults)) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.permission_denied), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.permission_denied, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +387,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
String[] names = importers.keySet().toArray(new String[0]);
|
String[] names = importers.keySet().toArray(new String[0]);
|
||||||
|
|
||||||
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
||||||
.setTitle(getString(R.string.choose_application))
|
.setTitle(R.string.choose_application)
|
||||||
.setSingleChoiceItems(names, 0, null)
|
.setSingleChoiceItems(names, 0, null)
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
@ -420,7 +407,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
String[] names = importers.keySet().toArray(new String[0]);
|
String[] names = importers.keySet().toArray(new String[0]);
|
||||||
|
|
||||||
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
||||||
.setTitle(getString(R.string.choose_application))
|
.setTitle(R.string.choose_application)
|
||||||
.setSingleChoiceItems(names, 0, null)
|
.setSingleChoiceItems(names, 0, null)
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||||
|
@ -449,7 +436,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
Toast.makeText(getActivity(), R.string.app_lookup_error, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.app_lookup_error, Toast.LENGTH_SHORT).show();
|
||||||
} catch (IOException | DatabaseImporterException e) {
|
} catch (IOException | DatabaseImporterException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Toast.makeText(getActivity(), getString(R.string.reading_file_error), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.reading_file_error, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,10 +504,10 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
DatabaseImporter importer = DatabaseImporter.create(getContext(), _importerType);
|
DatabaseImporter importer = DatabaseImporter.create(getContext(), _importerType);
|
||||||
importDatabase(importer, reader);
|
importDatabase(importer, reader);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.file_not_found), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.file_not_found, Toast.LENGTH_SHORT).show();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Toast.makeText(getActivity(), getString(R.string.reading_file_error), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.reading_file_error, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +545,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
try {
|
try {
|
||||||
filename = _db.export(checked.get());
|
filename = _db.export(checked.get());
|
||||||
} catch (DatabaseManagerException e) {
|
} catch (DatabaseManagerException e) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.exporting_database_error), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.exporting_database_error, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,7 +565,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
builder.setMessage(getString(R.string.export_warning));
|
builder.setMessage(R.string.export_warning);
|
||||||
}
|
}
|
||||||
Dialogs.showSecureDialog(builder.create());
|
Dialogs.showSecureDialog(builder.create());
|
||||||
}
|
}
|
||||||
|
@ -637,7 +624,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
try {
|
try {
|
||||||
_db.save();
|
_db.save();
|
||||||
} catch (DatabaseManagerException e) {
|
} catch (DatabaseManagerException e) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.saving_error), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), R.string.saving_error, Toast.LENGTH_LONG).show();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,15 +655,6 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] getStringsFromResourceIds(int[] resourceIds) {
|
|
||||||
String[] strings = new String[resourceIds.length];
|
|
||||||
for(int i = 0; i < resourceIds.length; i++) {
|
|
||||||
strings[i] = getString(resourceIds[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SetPasswordListener implements Dialogs.SlotListener {
|
private class SetPasswordListener implements Dialogs.SlotListener {
|
||||||
@Override
|
@Override
|
||||||
public void onSlotResult(Slot slot, Cipher cipher) {
|
public void onSlotResult(Slot slot, Cipher cipher) {
|
||||||
|
|
|
@ -97,7 +97,7 @@ public class SelectEntriesActivity extends AegisActivity {
|
||||||
ClipboardManager clipboard = (ClipboardManager) this.getSystemService(Context.CLIPBOARD_SERVICE);
|
ClipboardManager clipboard = (ClipboardManager) this.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
ClipData clip = ClipData.newPlainText("text/plain", message);
|
ClipData clip = ClipData.newPlainText("text/plain", message);
|
||||||
clipboard.setPrimaryClip(clip);
|
clipboard.setPrimaryClip(clip);
|
||||||
Toast.makeText(this, getString(R.string.errors_copied), Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.errors_copied, Toast.LENGTH_SHORT).show();
|
||||||
})
|
})
|
||||||
.create());
|
.create());
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.beemdevelopment.aegis.R;
|
|
||||||
import com.beemdevelopment.aegis.SortCategory;
|
import com.beemdevelopment.aegis.SortCategory;
|
||||||
import com.beemdevelopment.aegis.ViewMode;
|
import com.beemdevelopment.aegis.ViewMode;
|
||||||
import com.beemdevelopment.aegis.db.DatabaseEntry;
|
import com.beemdevelopment.aegis.db.DatabaseEntry;
|
||||||
|
@ -16,6 +15,7 @@ import com.beemdevelopment.aegis.otp.TotpInfo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
private int _tapToRevealTime;
|
private int _tapToRevealTime;
|
||||||
private String _groupFilter;
|
private String _groupFilter;
|
||||||
private SortCategory _sortCategory;
|
private SortCategory _sortCategory;
|
||||||
|
|
||||||
private ViewMode _viewMode;
|
private ViewMode _viewMode;
|
||||||
|
private boolean _isPeriodUniform = true;
|
||||||
|
|
||||||
// keeps track of the viewholders that are currently bound
|
// keeps track of the viewholders that are currently bound
|
||||||
private List<EntryHolder> _holders;
|
private List<EntryHolder> _holders;
|
||||||
|
@ -57,26 +57,43 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
|
|
||||||
public void addEntry(DatabaseEntry entry) {
|
public void addEntry(DatabaseEntry entry) {
|
||||||
_entries.add(entry);
|
_entries.add(entry);
|
||||||
if (!isEntryFiltered(entry)) {
|
if (isEntryFiltered(entry)) {
|
||||||
_shownEntries.add(entry);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int position = getItemCount() - 1;
|
boolean added = false;
|
||||||
if (position == 0) {
|
Comparator<DatabaseEntry> comparator = _sortCategory.getComparator();
|
||||||
notifyDataSetChanged();
|
if (comparator != null) {
|
||||||
} else {
|
// insert the entry in the correct order
|
||||||
notifyItemInserted(position);
|
// note: this assumes that _shownEntries has already been sorted
|
||||||
|
for (int i = 0; i < _shownEntries.size(); i++) {
|
||||||
|
if (comparator.compare(_shownEntries.get(i), entry) > 0) {
|
||||||
|
_shownEntries.add(i, entry);
|
||||||
|
notifyItemInserted(i);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!added){
|
||||||
|
_shownEntries.add(entry);
|
||||||
|
|
||||||
|
int position = getItemCount() - 1;
|
||||||
|
if (position == 0) {
|
||||||
|
notifyDataSetChanged();
|
||||||
|
} else {
|
||||||
|
notifyItemInserted(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPeriodUniformity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntries(List<DatabaseEntry> entries) {
|
public void addEntries(List<DatabaseEntry> entries) {
|
||||||
_entries.addAll(entries);
|
_entries.addAll(entries);
|
||||||
for (DatabaseEntry entry : entries) {
|
updateShownEntries();
|
||||||
if (!isEntryFiltered(entry)) {
|
checkPeriodUniformity();
|
||||||
_shownEntries.add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEntry(DatabaseEntry entry) {
|
public void removeEntry(DatabaseEntry entry) {
|
||||||
|
@ -88,6 +105,8 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
_shownEntries.remove(position);
|
_shownEntries.remove(position);
|
||||||
notifyItemRemoved(position);
|
notifyItemRemoved(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkPeriodUniformity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearEntries() {
|
public void clearEntries() {
|
||||||
|
@ -116,6 +135,8 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
int position = getItemCount() - 1;
|
int position = getItemCount() - 1;
|
||||||
notifyItemInserted(position);
|
notifyItemInserted(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkPeriodUniformity();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEntryFiltered(DatabaseEntry entry) {
|
private boolean isEntryFiltered(DatabaseEntry entry) {
|
||||||
|
@ -145,36 +166,47 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroupFilter(String group) {
|
public void setGroupFilter(String group, boolean apply) {
|
||||||
|
if (_groupFilter != null && _groupFilter.equals(group)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
_groupFilter = group;
|
_groupFilter = group;
|
||||||
|
if (apply) {
|
||||||
|
updateShownEntries();
|
||||||
|
checkPeriodUniformity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortCategory(SortCategory category, boolean apply) {
|
||||||
|
if (_sortCategory == category) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_sortCategory = category;
|
||||||
|
if (apply) {
|
||||||
|
updateShownEntries();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateShownEntries() {
|
||||||
|
// clear the list of shown entries first
|
||||||
_shownEntries.clear();
|
_shownEntries.clear();
|
||||||
|
|
||||||
|
// add entries back that are not filtered out
|
||||||
for (DatabaseEntry entry : _entries) {
|
for (DatabaseEntry entry : _entries) {
|
||||||
if (!isEntryFiltered(entry)) {
|
if (!isEntryFiltered(entry)) {
|
||||||
_shownEntries.add(entry);
|
_shownEntries.add(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortList(_sortCategory);
|
// sort the remaining list of entries
|
||||||
|
Comparator<DatabaseEntry> comparator = _sortCategory.getComparator();
|
||||||
|
if (comparator != null) {
|
||||||
|
Collections.sort(_shownEntries, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSortCategory(SortCategory sortCategory) {
|
|
||||||
if (_sortCategory != sortCategory && sortCategory != SortCategory.CUSTOM) {
|
|
||||||
sortList(sortCategory);
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
_sortCategory = sortCategory;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sortList(SortCategory sortCategory) {
|
|
||||||
Collections.sort(_shownEntries, SortCategory.getComparator(sortCategory));
|
|
||||||
|
|
||||||
if (SortCategory.isReversed(sortCategory)) {
|
|
||||||
Collections.reverse(_shownEntries);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setViewMode(ViewMode viewMode) {
|
public void setViewMode(ViewMode viewMode) {
|
||||||
_viewMode = viewMode;
|
_viewMode = viewMode;
|
||||||
}
|
}
|
||||||
|
@ -211,16 +243,14 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public int getItemViewType(int position) {
|
||||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_entry, parent, false);
|
return _viewMode.getLayoutId();
|
||||||
if (_viewMode == ViewMode.NORMAL) {
|
}
|
||||||
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_entry, parent, false);
|
|
||||||
} else if (_viewMode == ViewMode.COMPACT) {
|
|
||||||
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_entry_compact, parent, false);
|
|
||||||
} else if (_viewMode == ViewMode.SMALL) {
|
|
||||||
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_entry_small, parent, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||||
|
View view = inflater.inflate(_viewMode.getLayoutId(), parent, false);
|
||||||
return new EntryHolder(view);
|
return new EntryHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,9 +266,6 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
boolean showProgress = !isPeriodUniform() && entry.getInfo() instanceof TotpInfo;
|
boolean showProgress = !isPeriodUniform() && entry.getInfo() instanceof TotpInfo;
|
||||||
holder.setData(entry, _showAccountName, showProgress, _tapToReveal);
|
holder.setData(entry, _showAccountName, showProgress, _tapToReveal);
|
||||||
holder.setTapToRevealTime(_tapToRevealTime);
|
holder.setTapToRevealTime(_tapToRevealTime);
|
||||||
if (showProgress) {
|
|
||||||
holder.startRefreshLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -280,6 +307,20 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
_holders.add(holder);
|
_holders.add(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkPeriodUniformity() {
|
||||||
|
boolean uniform = isPeriodUniform();
|
||||||
|
if (uniform == _isPeriodUniform) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isPeriodUniform = uniform;
|
||||||
|
|
||||||
|
for (EntryHolder holder : _holders) {
|
||||||
|
holder.setShowProgress(!_isPeriodUniform);
|
||||||
|
}
|
||||||
|
|
||||||
|
_listener.onPeriodUniformityChanged(_isPeriodUniform);
|
||||||
|
}
|
||||||
|
|
||||||
public int getUniformPeriod() {
|
public int getUniformPeriod() {
|
||||||
List<TotpInfo> infos = new ArrayList<>();
|
List<TotpInfo> infos = new ArrayList<>();
|
||||||
for (DatabaseEntry entry : _shownEntries) {
|
for (DatabaseEntry entry : _shownEntries) {
|
||||||
|
@ -318,5 +359,6 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
void onEntryMove(DatabaseEntry entry1, DatabaseEntry entry2);
|
void onEntryMove(DatabaseEntry entry1, DatabaseEntry entry2);
|
||||||
void onEntryDrop(DatabaseEntry entry);
|
void onEntryDrop(DatabaseEntry entry);
|
||||||
void onEntryChange(DatabaseEntry entry);
|
void onEntryChange(DatabaseEntry entry);
|
||||||
|
void onPeriodUniformityChanged(boolean uniform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,8 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
||||||
private ImageView _profileDrawable;
|
private ImageView _profileDrawable;
|
||||||
private DatabaseEntry _entry;
|
private DatabaseEntry _entry;
|
||||||
private ImageView _buttonRefresh;
|
private ImageView _buttonRefresh;
|
||||||
|
|
||||||
private View _entryDivider;
|
private View _entryDivider;
|
||||||
|
|
||||||
private View _currentView;
|
|
||||||
|
|
||||||
private boolean _hidden;
|
private boolean _hidden;
|
||||||
private int _tapToRevealTime;
|
private int _tapToRevealTime;
|
||||||
|
|
||||||
|
@ -42,7 +39,6 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
public EntryHolder(final View view) {
|
public EntryHolder(final View view) {
|
||||||
super(view);
|
super(view);
|
||||||
_currentView = view;
|
|
||||||
|
|
||||||
_profileName = view.findViewById(R.id.profile_account_name);
|
_profileName = view.findViewById(R.id.profile_account_name);
|
||||||
_profileCode = view.findViewById(R.id.profile_code);
|
_profileCode = view.findViewById(R.id.profile_code);
|
||||||
|
@ -80,14 +76,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
||||||
_hidden = hidden;
|
_hidden = hidden;
|
||||||
|
|
||||||
// only show the progress bar if there is no uniform period and the entry type is TotpInfo
|
// only show the progress bar if there is no uniform period and the entry type is TotpInfo
|
||||||
_progressBar.setVisibility(showProgress ? View.VISIBLE : View.GONE);
|
setShowProgress(showProgress);
|
||||||
if (showProgress) {
|
|
||||||
_progressBar.setPeriod(((TotpInfo)entry.getInfo()).getPeriod());
|
|
||||||
|
|
||||||
if (_entryDivider != null) {
|
|
||||||
_entryDivider.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only show the button if this entry is of type HotpInfo
|
// only show the button if this entry is of type HotpInfo
|
||||||
_buttonRefresh.setVisibility(entry.getInfo() instanceof HotpInfo ? View.VISIBLE : View.GONE);
|
_buttonRefresh.setVisibility(entry.getInfo() instanceof HotpInfo ? View.VISIBLE : View.GONE);
|
||||||
|
@ -125,6 +114,25 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
||||||
_buttonRefresh.setOnClickListener(listener);
|
_buttonRefresh.setOnClickListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setShowProgress(boolean showProgress) {
|
||||||
|
if (_entry.getInfo() instanceof HotpInfo) {
|
||||||
|
showProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_progressBar.setVisibility(showProgress ? View.VISIBLE : View.GONE);
|
||||||
|
if (showProgress) {
|
||||||
|
_progressBar.setPeriod(((TotpInfo) _entry.getInfo()).getPeriod());
|
||||||
|
|
||||||
|
if (_entryDivider != null) {
|
||||||
|
_entryDivider.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
startRefreshLoop();
|
||||||
|
} else {
|
||||||
|
stopRefreshLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void startRefreshLoop() {
|
public void startRefreshLoop() {
|
||||||
_refresher.start();
|
_refresher.start();
|
||||||
}
|
}
|
||||||
|
@ -162,7 +170,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideCode() {
|
private void hideCode() {
|
||||||
_profileCode.setText(_currentView.getContext().getResources().getString(R.string.tap_to_reveal));
|
_profileCode.setText(R.string.tap_to_reveal);
|
||||||
_hidden = true;
|
_hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
private Listener _listener;
|
private Listener _listener;
|
||||||
private SimpleItemTouchHelperCallback _touchCallback;
|
private SimpleItemTouchHelperCallback _touchCallback;
|
||||||
|
|
||||||
private RecyclerView _rvKeyProfiles;
|
private RecyclerView _recyclerView;
|
||||||
private PeriodProgressBar _progressBar;
|
private PeriodProgressBar _progressBar;
|
||||||
private boolean _showProgress;
|
private boolean _showProgress;
|
||||||
|
|
||||||
|
@ -44,12 +44,11 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_entry_list_view, container, false);
|
View view = inflater.inflate(R.layout.fragment_entry_list_view, container, false);
|
||||||
|
|
||||||
_progressBar = view.findViewById(R.id.progressBar);
|
_progressBar = view.findViewById(R.id.progressBar);
|
||||||
|
|
||||||
// set up the recycler view
|
// set up the recycler view
|
||||||
_rvKeyProfiles = view.findViewById(R.id.rvKeyProfiles);
|
_recyclerView = view.findViewById(R.id.rvKeyProfiles);
|
||||||
_rvKeyProfiles.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
_recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||||
super.onScrolled(recyclerView, dx, dy);
|
super.onScrolled(recyclerView, dx, dy);
|
||||||
|
@ -58,15 +57,15 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
});
|
});
|
||||||
|
|
||||||
LinearLayoutManager mLayoutManager = new LinearLayoutManager(view.getContext());
|
LinearLayoutManager mLayoutManager = new LinearLayoutManager(view.getContext());
|
||||||
_rvKeyProfiles.setLayoutManager(mLayoutManager);
|
_recyclerView.setLayoutManager(mLayoutManager);
|
||||||
_touchCallback = new SimpleItemTouchHelperCallback(_adapter);
|
_touchCallback = new SimpleItemTouchHelperCallback(_adapter);
|
||||||
ItemTouchHelper touchHelper = new ItemTouchHelper(_touchCallback);
|
ItemTouchHelper touchHelper = new ItemTouchHelper(_touchCallback);
|
||||||
touchHelper.attachToRecyclerView(_rvKeyProfiles);
|
touchHelper.attachToRecyclerView(_recyclerView);
|
||||||
_rvKeyProfiles.setAdapter(_adapter);
|
_recyclerView.setAdapter(_adapter);
|
||||||
|
|
||||||
int resId = R.anim.layout_animation_fall_down;
|
int resId = R.anim.layout_animation_fall_down;
|
||||||
LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(getContext(), resId);
|
LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(getContext(), resId);
|
||||||
_rvKeyProfiles.setLayoutAnimation(animation);
|
_recyclerView.setLayoutAnimation(animation);
|
||||||
|
|
||||||
_refresher = new UiRefresher(new UiRefresher.Listener() {
|
_refresher = new UiRefresher(new UiRefresher.Listener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,23 +82,26 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroupFilter(String group) {
|
public void setGroupFilter(String group, boolean apply) {
|
||||||
_adapter.setGroupFilter(group);
|
|
||||||
_touchCallback.setIsLongPressDragEnabled(group == null);
|
_touchCallback.setIsLongPressDragEnabled(group == null);
|
||||||
checkPeriodUniformity();
|
_adapter.setGroupFilter(group, apply);
|
||||||
|
|
||||||
runLayoutAnimation(_rvKeyProfiles);
|
if (apply) {
|
||||||
|
runEntriesAnimation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSortCategory(SortCategory sortCategory) {
|
public void setSortCategory(SortCategory sortCategory, boolean apply) {
|
||||||
_touchCallback.setIsLongPressDragEnabled(sortCategory == SortCategory.CUSTOM);
|
_touchCallback.setIsLongPressDragEnabled(sortCategory == SortCategory.CUSTOM);
|
||||||
|
_adapter.setSortCategory(sortCategory, apply);
|
||||||
|
|
||||||
_adapter.setSortCategory(sortCategory);
|
if (apply) {
|
||||||
runLayoutAnimation(_rvKeyProfiles);
|
runEntriesAnimation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setViewMode(ViewMode viewMode) {
|
public void setViewMode(ViewMode mode) {
|
||||||
_adapter.setViewMode(viewMode);
|
_adapter.setViewMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh(boolean hard) {
|
public void refresh(boolean hard) {
|
||||||
|
@ -109,33 +111,6 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
_adapter.refresh(hard);
|
_adapter.refresh(hard);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPeriodUniformity() {
|
|
||||||
boolean uniform = _adapter.isPeriodUniform();
|
|
||||||
if (uniform == _showProgress) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_showProgress = uniform;
|
|
||||||
|
|
||||||
if (_showProgress) {
|
|
||||||
_progressBar.setVisibility(View.VISIBLE);
|
|
||||||
_progressBar.setPeriod(_adapter.getUniformPeriod());
|
|
||||||
startRefreshLoop();
|
|
||||||
} else {
|
|
||||||
_progressBar.setVisibility(View.GONE);
|
|
||||||
stopRefreshLoop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startRefreshLoop() {
|
|
||||||
refresh(true);
|
|
||||||
_refresher.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopRefreshLoop() {
|
|
||||||
refresh(true);
|
|
||||||
_refresher.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setListener(Listener listener) {
|
public void setListener(Listener listener) {
|
||||||
_listener = listener;
|
_listener = listener;
|
||||||
}
|
}
|
||||||
|
@ -165,6 +140,19 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
_listener.onEntryChange(entry);
|
_listener.onEntryChange(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPeriodUniformityChanged(boolean isUniform) {
|
||||||
|
_showProgress = isUniform;
|
||||||
|
if (_showProgress) {
|
||||||
|
_progressBar.setVisibility(View.VISIBLE);
|
||||||
|
_progressBar.setPeriod(_adapter.getUniformPeriod());
|
||||||
|
_refresher.start();
|
||||||
|
} else {
|
||||||
|
_progressBar.setVisibility(View.GONE);
|
||||||
|
_refresher.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setShowAccountName(boolean showAccountName) {
|
public void setShowAccountName(boolean showAccountName) {
|
||||||
_adapter.setShowAccountName(showAccountName);
|
_adapter.setShowAccountName(showAccountName);
|
||||||
}
|
}
|
||||||
|
@ -179,37 +167,31 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
|
|
||||||
public void addEntry(DatabaseEntry entry) {
|
public void addEntry(DatabaseEntry entry) {
|
||||||
_adapter.addEntry(entry);
|
_adapter.addEntry(entry);
|
||||||
checkPeriodUniformity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntries(List<DatabaseEntry> entries) {
|
public void addEntries(List<DatabaseEntry> entries) {
|
||||||
_adapter.addEntries(entries);
|
_adapter.addEntries(entries);
|
||||||
checkPeriodUniformity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEntry(DatabaseEntry entry) {
|
public void removeEntry(DatabaseEntry entry) {
|
||||||
_adapter.removeEntry(entry);
|
_adapter.removeEntry(entry);
|
||||||
checkPeriodUniformity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearEntries() {
|
public void clearEntries() {
|
||||||
_adapter.clearEntries();
|
_adapter.clearEntries();
|
||||||
checkPeriodUniformity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceEntry(DatabaseEntry entry) {
|
public void replaceEntry(DatabaseEntry entry) {
|
||||||
_adapter.replaceEntry(entry);
|
_adapter.replaceEntry(entry);
|
||||||
checkPeriodUniformity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runLayoutAnimation(final RecyclerView recyclerView) {
|
public void runEntriesAnimation() {
|
||||||
final Context context = recyclerView.getContext();
|
final Context context = _recyclerView.getContext();
|
||||||
final LayoutAnimationController controller =
|
final LayoutAnimationController controller =
|
||||||
AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_fall_down);
|
AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_fall_down);
|
||||||
|
|
||||||
recyclerView.setLayoutAnimation(controller);
|
_recyclerView.setLayoutAnimation(controller);
|
||||||
recyclerView.getAdapter().notifyDataSetChanged();
|
_recyclerView.scheduleLayoutAnimation();
|
||||||
recyclerView.scheduleLayoutAnimation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
|
|
|
@ -17,4 +17,16 @@
|
||||||
<item>SHA256</item>
|
<item>SHA256</item>
|
||||||
<item>SHA512</item>
|
<item>SHA512</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="theme_titles">
|
||||||
|
<item>@string/light_theme_title</item>
|
||||||
|
<item>@string/dark_theme_title</item>
|
||||||
|
<item>@string/amoled_theme_title</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="view_mode_titles">
|
||||||
|
<item>@string/normal_viewmode_title</item>
|
||||||
|
<item>@string/compact_mode_title</item>
|
||||||
|
<item>@string/small_mode_title</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue