mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-20 22:09:12 +00:00
Merge pull request #760 from michaelschattgen/feature/usage-count
Add usage count to entries
This commit is contained in:
commit
c27c4f0ac5
16 changed files with 235 additions and 1 deletions
|
@ -12,9 +12,15 @@ import org.json.JSONException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class Preferences {
|
public class Preferences {
|
||||||
|
@ -147,6 +153,56 @@ public class Preferences {
|
||||||
_prefs.edit().putInt("pref_current_view_mode", viewMode.ordinal()).apply();
|
_prefs.edit().putInt("pref_current_view_mode", viewMode.ordinal()).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getUsageCount(UUID uuid) {
|
||||||
|
Integer usageCount = getUsageCounts().get(uuid);
|
||||||
|
|
||||||
|
return usageCount != null ? usageCount : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetUsageCount(UUID uuid) {
|
||||||
|
Map<UUID, Integer> usageCounts = getUsageCounts();
|
||||||
|
usageCounts.put(uuid, 0);
|
||||||
|
|
||||||
|
setUsageCount(usageCounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearUsageCount() {
|
||||||
|
_prefs.edit().remove("pref_usage_count").apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<UUID, Integer> getUsageCounts() {
|
||||||
|
Map<UUID, Integer> usageCounts = new HashMap<>();
|
||||||
|
String usageCount = _prefs.getString("pref_usage_count", "");
|
||||||
|
try {
|
||||||
|
JSONArray arr = new JSONArray(usageCount);
|
||||||
|
for(int i = 0; i < arr.length(); i++) {
|
||||||
|
JSONObject json = arr.getJSONObject(i);
|
||||||
|
usageCounts.put(UUID.fromString(json.getString("uuid")), json.getInt("count"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return usageCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsageCount(Map<UUID, Integer> usageCounts) {
|
||||||
|
JSONArray usageCountJson = new JSONArray();
|
||||||
|
for (Map.Entry<UUID, Integer> entry : usageCounts.entrySet()) {
|
||||||
|
JSONObject entryJson = new JSONObject();
|
||||||
|
try {
|
||||||
|
entryJson.put("uuid", entry.getKey());
|
||||||
|
entryJson.put("count", entry.getValue());
|
||||||
|
usageCountJson.put(entryJson);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_prefs.edit().putString("pref_usage_count", usageCountJson.toString()).apply();
|
||||||
|
}
|
||||||
|
|
||||||
public int getTimeout() {
|
public int getTimeout() {
|
||||||
return _prefs.getInt("pref_timeout", -1);
|
return _prefs.getInt("pref_timeout", -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.beemdevelopment.aegis;
|
package com.beemdevelopment.aegis;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.helpers.comparators.UsageCountComparator;
|
||||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||||
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;
|
||||||
|
@ -12,7 +13,8 @@ public enum SortCategory {
|
||||||
ACCOUNT,
|
ACCOUNT,
|
||||||
ACCOUNT_REVERSED,
|
ACCOUNT_REVERSED,
|
||||||
ISSUER,
|
ISSUER,
|
||||||
ISSUER_REVERSED;
|
ISSUER_REVERSED,
|
||||||
|
USAGE_COUNT;
|
||||||
|
|
||||||
private static SortCategory[] _values;
|
private static SortCategory[] _values;
|
||||||
|
|
||||||
|
@ -40,6 +42,9 @@ public enum SortCategory {
|
||||||
case ISSUER_REVERSED:
|
case ISSUER_REVERSED:
|
||||||
comparator = Collections.reverseOrder(new IssuerNameComparator());
|
comparator = Collections.reverseOrder(new IssuerNameComparator());
|
||||||
break;
|
break;
|
||||||
|
case USAGE_COUNT:
|
||||||
|
comparator = Collections.reverseOrder(new UsageCountComparator());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return comparator;
|
return comparator;
|
||||||
|
@ -57,6 +62,8 @@ public enum SortCategory {
|
||||||
return R.id.menu_sort_alphabetically;
|
return R.id.menu_sort_alphabetically;
|
||||||
case ISSUER_REVERSED:
|
case ISSUER_REVERSED:
|
||||||
return R.id.menu_sort_alphabetically_reverse;
|
return R.id.menu_sort_alphabetically_reverse;
|
||||||
|
case USAGE_COUNT:
|
||||||
|
return R.id.menu_sort_usage_count;
|
||||||
default:
|
default:
|
||||||
return R.id.menu_sort_custom;
|
return R.id.menu_sort_custom;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.beemdevelopment.aegis.helpers.comparators;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public class UsageCountComparator implements Comparator<VaultEntry> {
|
||||||
|
@Override
|
||||||
|
public int compare(VaultEntry a, VaultEntry b) {
|
||||||
|
return Integer.compare(a.getUsageCount(), b.getUsageCount());
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,8 @@ import android.widget.AutoCompleteTextView;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -100,6 +102,7 @@ public class EditEntryActivity extends AegisActivity {
|
||||||
private TextInputEditText _textDigits;
|
private TextInputEditText _textDigits;
|
||||||
private TextInputLayout _textDigitsLayout;
|
private TextInputLayout _textDigitsLayout;
|
||||||
private TextInputEditText _textSecret;
|
private TextInputEditText _textSecret;
|
||||||
|
private TextInputEditText _textUsageCount;
|
||||||
|
|
||||||
private AutoCompleteTextView _dropdownType;
|
private AutoCompleteTextView _dropdownType;
|
||||||
private AutoCompleteTextView _dropdownAlgo;
|
private AutoCompleteTextView _dropdownAlgo;
|
||||||
|
@ -150,6 +153,7 @@ public class EditEntryActivity extends AegisActivity {
|
||||||
_textDigits = findViewById(R.id.text_digits);
|
_textDigits = findViewById(R.id.text_digits);
|
||||||
_textDigitsLayout = findViewById(R.id.text_digits_layout);
|
_textDigitsLayout = findViewById(R.id.text_digits_layout);
|
||||||
_textSecret = findViewById(R.id.text_secret);
|
_textSecret = findViewById(R.id.text_secret);
|
||||||
|
_textUsageCount = findViewById(R.id.text_usage_count);
|
||||||
_dropdownType = findViewById(R.id.dropdown_type);
|
_dropdownType = findViewById(R.id.dropdown_type);
|
||||||
DropdownHelper.fillDropdown(this, _dropdownType, R.array.otp_types_array);
|
DropdownHelper.fillDropdown(this, _dropdownType, R.array.otp_types_array);
|
||||||
_dropdownAlgoLayout = findViewById(R.id.dropdown_algo_layout);
|
_dropdownAlgoLayout = findViewById(R.id.dropdown_algo_layout);
|
||||||
|
@ -279,6 +283,8 @@ public class EditEntryActivity extends AegisActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_textUsageCount.setText(getPreferences().getUsageCount(entryUUID).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAdvancedFieldStatus(String otpType) {
|
private void updateAdvancedFieldStatus(String otpType) {
|
||||||
|
@ -405,6 +411,14 @@ public class EditEntryActivity extends AegisActivity {
|
||||||
case R.id.action_edit_icon:
|
case R.id.action_edit_icon:
|
||||||
startIconSelection();
|
startIconSelection();
|
||||||
break;
|
break;
|
||||||
|
case R.id.action_reset_usage_count:
|
||||||
|
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.action_reset_usage_count)
|
||||||
|
.setMessage(R.string.action_reset_usage_count_dialog)
|
||||||
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> resetUsageCount())
|
||||||
|
.setNegativeButton(android.R.string.no, null)
|
||||||
|
.create());
|
||||||
|
break;
|
||||||
case R.id.action_default_icon:
|
case R.id.action_default_icon:
|
||||||
TextDrawable drawable = TextDrawableHelper.generate(_origEntry.getIssuer(), _origEntry.getName(), _iconView);
|
TextDrawable drawable = TextDrawableHelper.generate(_origEntry.getIssuer(), _origEntry.getName(), _iconView);
|
||||||
_iconView.setImageDrawable(drawable);
|
_iconView.setImageDrawable(drawable);
|
||||||
|
@ -431,6 +445,11 @@ public class EditEntryActivity extends AegisActivity {
|
||||||
AegisActivity.Helper.startExtActivityForResult(this, chooserIntent, PICK_IMAGE_REQUEST);
|
AegisActivity.Helper.startExtActivityForResult(this, chooserIntent, PICK_IMAGE_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetUsageCount() {
|
||||||
|
getPreferences().resetUsageCount(_origEntry.getUUID());
|
||||||
|
_textUsageCount.setText("0");
|
||||||
|
}
|
||||||
|
|
||||||
private void startIconSelection() {
|
private void startIconSelection() {
|
||||||
List<IconPack> iconPacks = getApp().getIconPackManager().getIconPacks().stream()
|
List<IconPack> iconPacks = getApp().getIconPackManager().getIconPacks().stream()
|
||||||
.sorted(Comparator.comparing(IconPack::getName))
|
.sorted(Comparator.comparing(IconPack::getName))
|
||||||
|
|
|
@ -57,6 +57,7 @@ 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.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -165,6 +166,17 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
Map<UUID, Integer> usageMap = _entryListView.getUsageCounts();
|
||||||
|
if (usageMap != null) {
|
||||||
|
getPreferences().setUsageCount(usageMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
_isAuthenticating = false;
|
_isAuthenticating = false;
|
||||||
|
@ -487,6 +499,9 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
// update the list of groups in the entry list view so that the chip gets updated
|
// update the list of groups in the entry list view so that the chip gets updated
|
||||||
_entryListView.setGroups(_vault.getGroups());
|
_entryListView.setGroups(_vault.getGroups());
|
||||||
|
|
||||||
|
// update the usage counts in case they are edited outside of the entrylistview
|
||||||
|
_entryListView.setUsageCounts(getPreferences().getUsageCounts());
|
||||||
|
|
||||||
// refresh all codes to prevent showing old ones
|
// refresh all codes to prevent showing old ones
|
||||||
_entryListView.refresh(false);
|
_entryListView.refresh(false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -605,6 +620,9 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
case R.id.menu_sort_alphabetically_name_reverse:
|
case R.id.menu_sort_alphabetically_name_reverse:
|
||||||
sortCategory = SortCategory.ACCOUNT_REVERSED;
|
sortCategory = SortCategory.ACCOUNT_REVERSED;
|
||||||
break;
|
break;
|
||||||
|
case R.id.menu_sort_usage_count:
|
||||||
|
sortCategory = SortCategory.USAGE_COUNT;
|
||||||
|
break;
|
||||||
case R.id.menu_sort_custom:
|
case R.id.menu_sort_custom:
|
||||||
default:
|
default:
|
||||||
sortCategory = SortCategory.CUSTOM;
|
sortCategory = SortCategory.CUSTOM;
|
||||||
|
@ -625,6 +643,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
|
|
||||||
private void loadEntries() {
|
private void loadEntries() {
|
||||||
if (!_loaded) {
|
if (!_loaded) {
|
||||||
|
_entryListView.setUsageCounts(getPreferences().getUsageCounts());
|
||||||
_entryListView.addEntries(_vault.getEntries());
|
_entryListView.addEntries(_vault.getEntries());
|
||||||
_entryListView.runEntriesAnimation();
|
_entryListView.runEntriesAnimation();
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
|
@ -741,6 +760,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
_entryListView.clearEntries();
|
_entryListView.clearEntries();
|
||||||
_loaded = false;
|
_loaded = false;
|
||||||
|
|
||||||
|
|
||||||
if (userInitiated) {
|
if (userInitiated) {
|
||||||
startAuthActivity(true);
|
startAuthActivity(true);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.HashSet;
|
||||||
|
|
||||||
public class AppearancePreferencesFragment extends PreferencesFragment {
|
public class AppearancePreferencesFragment extends PreferencesFragment {
|
||||||
private Preference _groupsPreference;
|
private Preference _groupsPreference;
|
||||||
|
private Preference _resetUsageCountPreference;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
@ -36,6 +37,17 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_resetUsageCountPreference = findPreference("pref_reset_usage_count");
|
||||||
|
_resetUsageCountPreference.setOnPreferenceClickListener(preference -> {
|
||||||
|
Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity())
|
||||||
|
.setTitle(R.string.preference_reset_usage_count)
|
||||||
|
.setMessage(R.string.preference_reset_usage_count_dialog)
|
||||||
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> getPreferences().clearUsageCount())
|
||||||
|
.setNegativeButton(android.R.string.no, null)
|
||||||
|
.create());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
int currentTheme = prefs.getCurrentTheme().ordinal();
|
int currentTheme = prefs.getCurrentTheme().ordinal();
|
||||||
Preference darkModePreference = findPreference("pref_dark_mode");
|
Preference darkModePreference = findPreference("pref_dark_mode");
|
||||||
darkModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.theme_titles)[currentTheme]));
|
darkModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.theme_titles)[currentTheme]));
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements ItemTouchHelperAdapter {
|
public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements ItemTouchHelperAdapter {
|
||||||
|
@ -32,6 +33,7 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
private List<VaultEntry> _entries;
|
private List<VaultEntry> _entries;
|
||||||
private List<VaultEntry> _shownEntries;
|
private List<VaultEntry> _shownEntries;
|
||||||
private List<VaultEntry> _selectedEntries;
|
private List<VaultEntry> _selectedEntries;
|
||||||
|
private Map<UUID, Integer> _usageCounts;
|
||||||
private VaultEntry _focusedEntry;
|
private VaultEntry _focusedEntry;
|
||||||
private int _codeGroupSize;
|
private int _codeGroupSize;
|
||||||
private boolean _showAccountName;
|
private boolean _showAccountName;
|
||||||
|
@ -139,6 +141,10 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntries(Collection<VaultEntry> entries) {
|
public void addEntries(Collection<VaultEntry> entries) {
|
||||||
|
for (VaultEntry entry: entries) {
|
||||||
|
entry.setUsageCount(_usageCounts.containsKey(entry.getUUID()) ? _usageCounts.get(entry.getUUID()) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
_entries.addAll(entries);
|
_entries.addAll(entries);
|
||||||
updateShownEntries();
|
updateShownEntries();
|
||||||
checkPeriodUniformity(true);
|
checkPeriodUniformity(true);
|
||||||
|
@ -282,6 +288,14 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
_viewMode = viewMode;
|
_viewMode = viewMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUsageCounts(Map<UUID, Integer> usageCounts) { _usageCounts = usageCounts; }
|
||||||
|
|
||||||
|
public Map<UUID, Integer> getUsageCounts() { return _usageCounts; }
|
||||||
|
|
||||||
|
public void setGroups(TreeSet<String> groups) {
|
||||||
|
_view.setGroups(groups);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemDismiss(int position) {
|
public void onItemDismiss(int position) {
|
||||||
|
|
||||||
|
@ -363,6 +377,8 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
focusEntry(entry, _tapToRevealTime);
|
focusEntry(entry, _tapToRevealTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incrementUsageCount(entry);
|
||||||
} else {
|
} else {
|
||||||
if (_selectedEntries.contains(entry)) {
|
if (_selectedEntries.contains(entry)) {
|
||||||
_view.onDeselect(entry);
|
_view.onDeselect(entry);
|
||||||
|
@ -586,6 +602,15 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
|
||||||
updateDraggableStatus();
|
updateDraggableStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void incrementUsageCount(VaultEntry entry) {
|
||||||
|
if (!_usageCounts.containsKey(entry.getUUID())) {
|
||||||
|
_usageCounts.put(entry.getUUID(), 1);
|
||||||
|
} else {
|
||||||
|
int usageCount = _usageCounts.get(entry.getUUID());
|
||||||
|
_usageCounts.put(entry.getUUID(), ++usageCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDragAndDropAllowed() {
|
public boolean isDragAndDropAllowed() {
|
||||||
return _sortCategory == SortCategory.CUSTOM && _groupFilter.isEmpty() && _searchFilter == null;
|
return _sortCategory == SortCategory.CUSTOM && _groupFilter.isEmpty() && _searchFilter == null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import com.google.android.material.chip.ChipGroup;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -184,6 +185,14 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUsageCounts(Map<UUID, Integer> usageCounts) {
|
||||||
|
_adapter.setUsageCounts(usageCounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<UUID, Integer> getUsageCounts() {
|
||||||
|
return _adapter.getUsageCounts();
|
||||||
|
}
|
||||||
|
|
||||||
public void setSearchFilter(String search) {
|
public void setSearchFilter(String search) {
|
||||||
_adapter.setSearchFilter(search);
|
_adapter.setSearchFilter(search);
|
||||||
_touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed());
|
_touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed());
|
||||||
|
|
|
@ -141,6 +141,7 @@ public class UUIDMap <T extends UUIDMap.Value> implements Iterable<T>, Serializa
|
||||||
this(UUID.randomUUID());
|
this(UUID.randomUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public final UUID getUUID() {
|
public final UUID getUUID() {
|
||||||
return _uuid;
|
return _uuid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public class VaultEntry extends UUIDMap.Value {
|
public class VaultEntry extends UUIDMap.Value {
|
||||||
private String _name = "";
|
private String _name = "";
|
||||||
private String _issuer = "";
|
private String _issuer = "";
|
||||||
|
@ -24,6 +26,7 @@ public class VaultEntry extends UUIDMap.Value {
|
||||||
private OtpInfo _info;
|
private OtpInfo _info;
|
||||||
private byte[] _icon;
|
private byte[] _icon;
|
||||||
private IconType _iconType = IconType.INVALID;
|
private IconType _iconType = IconType.INVALID;
|
||||||
|
private int _usageCount;
|
||||||
|
|
||||||
private VaultEntry(UUID uuid, OtpInfo info) {
|
private VaultEntry(UUID uuid, OtpInfo info) {
|
||||||
super(uuid);
|
super(uuid);
|
||||||
|
@ -130,6 +133,10 @@ public class VaultEntry extends UUIDMap.Value {
|
||||||
return _info;
|
return _info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getUsageCount() {
|
||||||
|
return _usageCount;
|
||||||
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
_name = name;
|
_name = name;
|
||||||
}
|
}
|
||||||
|
@ -155,6 +162,8 @@ public class VaultEntry extends UUIDMap.Value {
|
||||||
return _icon != null;
|
return _icon != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUsageCount(int usageCount) { _usageCount = usageCount; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof VaultEntry)) {
|
if (!(o instanceof VaultEntry)) {
|
||||||
|
|
7
app/src/main/res/drawable/ic_counter_black_24dp.xml
Normal file
7
app/src/main/res/drawable/ic_counter_black_24dp.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path android:fillColor="#000" android:pathData="M4,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M4,6V18H11V6H4M20,18V6H18.76C19,6.54 18.95,7.07 18.95,7.13C18.88,7.8 18.41,8.5 18.24,8.75L15.91,11.3L19.23,11.28L19.24,12.5L14.04,12.47L14,11.47C14,11.47 17.05,8.24 17.2,7.95C17.34,7.67 17.91,6 16.5,6C15.27,6.05 15.41,7.3 15.41,7.3L13.87,7.31C13.87,7.31 13.88,6.65 14.25,6H13V18H15.58L15.57,17.14L16.54,17.13C16.54,17.13 17.45,16.97 17.46,16.08C17.5,15.08 16.65,15.08 16.5,15.08C16.37,15.08 15.43,15.13 15.43,15.95H13.91C13.91,15.95 13.95,13.89 16.5,13.89C19.1,13.89 18.96,15.91 18.96,15.91C18.96,15.91 19,17.16 17.85,17.63L18.37,18H20M8.92,16H7.42V10.2L5.62,10.76V9.53L8.76,8.41H8.92V16Z" />
|
||||||
|
</vector>
|
|
@ -61,6 +61,7 @@
|
||||||
android:layout_margin="15dp"
|
android:layout_margin="15dp"
|
||||||
android:src="@drawable/ic_check_black_24dp"
|
android:src="@drawable/ic_check_black_24dp"
|
||||||
app:tint="?attr/iconColorPrimary" />
|
app:tint="?attr/iconColorPrimary" />
|
||||||
|
|
||||||
</com.avito.android.krop.KropView>
|
</com.avito.android.krop.KropView>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -285,6 +286,42 @@
|
||||||
android:inputType="text"/>
|
android:inputType="text"/>
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_usage_count"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:weightSum="2"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_counter_black_24dp"
|
||||||
|
app:tint="?attr/iconColorPrimary"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_gravity="center_vertical"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:hint="@string/usage_count"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="5dp">
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/text_usage_count"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:enabled="false"
|
||||||
|
android:inputType="number"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
android:id="@+id/action_edit_icon"
|
android:id="@+id/action_edit_icon"
|
||||||
android:title="@string/action_edit_icon"
|
android:title="@string/action_edit_icon"
|
||||||
app:showAsAction="never"/>
|
app:showAsAction="never"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_reset_usage_count"
|
||||||
|
android:title="@string/action_reset_usage_count"
|
||||||
|
app:showAsAction="never"/>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_default_icon"
|
android:id="@+id/action_default_icon"
|
||||||
android:title="@string/action_default_icon"
|
android:title="@string/action_default_icon"
|
||||||
|
|
|
@ -37,6 +37,9 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_sort_alphabetically_reverse"
|
android:id="@+id/menu_sort_alphabetically_reverse"
|
||||||
android:title="@string/sort_alphabetically_reverse"/>
|
android:title="@string/sort_alphabetically_reverse"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_sort_usage_count"
|
||||||
|
android:title="@string/sort_usage_count"/>
|
||||||
</group>
|
</group>
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -9,11 +9,14 @@
|
||||||
<string name="action_delete">Delete</string>
|
<string name="action_delete">Delete</string>
|
||||||
<string name="action_transfer">Transfer</string>
|
<string name="action_transfer">Transfer</string>
|
||||||
<string name="action_edit_icon">Edit icon</string>
|
<string name="action_edit_icon">Edit icon</string>
|
||||||
|
<string name="action_reset_usage_count">Reset usage count</string>
|
||||||
|
<string name="action_reset_usage_count_dialog">Are you sure you want to set the usage count of this entry to 0?</string>
|
||||||
<string name="action_default_icon">Restore default icon</string>
|
<string name="action_default_icon">Restore default icon</string>
|
||||||
<string name="discard">Discard</string>
|
<string name="discard">Discard</string>
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
<string name="issuer">Issuer</string>
|
<string name="issuer">Issuer</string>
|
||||||
<string name="suggested">Suggested</string>
|
<string name="suggested">Suggested</string>
|
||||||
|
<string name="usage_count">Usage count</string>
|
||||||
|
|
||||||
<string name="settings">Preferences</string>
|
<string name="settings">Preferences</string>
|
||||||
<string name="pref_cat_appearance_app">App</string>
|
<string name="pref_cat_appearance_app">App</string>
|
||||||
|
@ -245,6 +248,7 @@
|
||||||
<string name="sort_alphabetically_reverse">Issuer (Z to A)</string>
|
<string name="sort_alphabetically_reverse">Issuer (Z to A)</string>
|
||||||
<string name="sort_alphabetically_name">Account (A to Z)</string>
|
<string name="sort_alphabetically_name">Account (A to Z)</string>
|
||||||
<string name="sort_alphabetically_name_reverse">Account (Z to A)</string>
|
<string name="sort_alphabetically_name_reverse">Account (Z to A)</string>
|
||||||
|
<string name="sort_usage_count">Usage count</string>
|
||||||
<string name="sort_custom">Custom</string>
|
<string name="sort_custom">Custom</string>
|
||||||
<string name="new_group">New group…</string>
|
<string name="new_group">New group…</string>
|
||||||
<string name="enter_group_name">Enter a group name</string>
|
<string name="enter_group_name">Enter a group name</string>
|
||||||
|
@ -252,6 +256,9 @@
|
||||||
<string name="group_name_hint">Group name</string>
|
<string name="group_name_hint">Group name</string>
|
||||||
<string name="preference_manage_groups">Edit groups</string>
|
<string name="preference_manage_groups">Edit groups</string>
|
||||||
<string name="preference_manage_groups_summary">Manage and delete your groups here</string>
|
<string name="preference_manage_groups_summary">Manage and delete your groups here</string>
|
||||||
|
<string name="preference_reset_usage_count">Reset usage count</string>
|
||||||
|
<string name="preference_reset_usage_count_summary">Reset the usage count of every entry in your vault</string>
|
||||||
|
<string name="preference_reset_usage_count_dialog">Are you sure you want to set the usage count of every entry in your vault to 0?</string>
|
||||||
<string name="clear">Clear</string>
|
<string name="clear">Clear</string>
|
||||||
|
|
||||||
<string name="pref_highlight_entry_title">Highlight tokens when tapped</string>
|
<string name="pref_highlight_entry_title">Highlight tokens when tapped</string>
|
||||||
|
|
|
@ -49,5 +49,11 @@
|
||||||
android:title="@string/preference_manage_groups"
|
android:title="@string/preference_manage_groups"
|
||||||
android:summary="@string/preference_manage_groups_summary"
|
android:summary="@string/preference_manage_groups_summary"
|
||||||
app:iconSpaceReserved="false"/>
|
app:iconSpaceReserved="false"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="pref_reset_usage_count"
|
||||||
|
android:title="@string/preference_reset_usage_count"
|
||||||
|
android:summary="@string/preference_reset_usage_count_summary"
|
||||||
|
app:iconSpaceReserved="false"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
Loading…
Add table
Reference in a new issue