From 5ec1e33a31ab363066d386b2b59d69ad24165437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Wed, 26 Oct 2022 14:07:49 +0200 Subject: [PATCH] Add ability to favorite/pin entries --- .../beemdevelopment/aegis/OverallTest.java | 13 +++++- .../beemdevelopment/aegis/Preferences.java | 23 ++++++++++ .../SimpleItemTouchHelperCallback.java | 28 ++++++++---- .../comparators/FavoriteComparator.java | 12 +++++ .../aegis/ui/MainActivity.java | 41 ++++++++++++++++- .../aegis/ui/views/EntryAdapter.java | 45 +++++++++++++++++-- .../aegis/ui/views/EntryHolder.java | 4 ++ .../aegis/ui/views/EntryListView.java | 28 +++++++++++- .../aegis/vault/VaultEntry.java | 5 +++ .../res/drawable-anydpi/ic_set_favorite.xml | 15 +++++++ .../res/drawable-anydpi/ic_unset_favorite.xml | 15 +++++++ app/src/main/res/layout/card_entry.xml | 8 ++++ .../main/res/layout/card_entry_compact.xml | 11 ++++- app/src/main/res/layout/card_entry_small.xml | 8 ++++ app/src/main/res/menu/menu_action_mode.xml | 8 +++- app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 2 + 17 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/FavoriteComparator.java create mode 100644 app/src/main/res/drawable-anydpi/ic_set_favorite.xml create mode 100644 app/src/main/res/drawable-anydpi/ic_unset_favorite.xml diff --git a/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java b/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java index 451cc0c2..643adb49 100644 --- a/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java +++ b/app/src/androidTest/java/com/beemdevelopment/aegis/OverallTest.java @@ -1,6 +1,7 @@ package com.beemdevelopment.aegis; import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu; import static androidx.test.espresso.Espresso.openContextualActionModeOverflowMenu; import static androidx.test.espresso.action.ViewActions.clearText; import static androidx.test.espresso.action.ViewActions.click; @@ -9,20 +10,27 @@ import static androidx.test.espresso.action.ViewActions.longClick; import static androidx.test.espresso.action.ViewActions.pressBack; import static androidx.test.espresso.action.ViewActions.typeText; import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; +import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; import static androidx.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.matcher.ViewMatchers.withClassName; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertNull; import static junit.framework.TestCase.assertTrue; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; + import androidx.annotation.IdRes; +import androidx.test.core.app.ApplicationProvider; import androidx.test.espresso.ViewInteraction; import androidx.test.espresso.contrib.RecyclerViewActions; import androidx.test.espresso.matcher.RootMatchers; import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.beemdevelopment.aegis.encoding.Base32; import com.beemdevelopment.aegis.encoding.Hex; @@ -127,8 +135,9 @@ public class OverallTest extends AegisTest { onView(withId(R.id.action_share_qr)).perform(click()); onView(withId(R.id.btnNext)).perform(click()).perform(click()).perform(click()); - onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(2, longClick())); - onView(withId(R.id.action_delete)).perform(click()); + onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(0, longClick())); + onView(allOf(isDescendantOfA(withClassName(containsString("ActionBarContextView"))), withClassName(containsString("OverflowMenuButton")))).perform(click()); + onView(withText(R.string.action_delete)).perform(click()); onView(withId(android.R.id.button1)).perform(click()); openContextualActionModeOverflowMenu(); diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index 883973a3..9d7effbb 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -20,9 +20,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.UUID; public class Preferences { @@ -233,6 +235,27 @@ public class Preferences { _prefs.edit().putString("pref_usage_count", usageCountJson.toString()).apply(); } + public List getFavorites() { + List favorites = new ArrayList<>(); + Set favoritesStringSet = _prefs.getStringSet("pref_favorites", null); + if(favoritesStringSet != null) { + for (String favorite : favoritesStringSet) { + favorites.add(UUID.fromString(favorite)); + } + } + + return favorites; + } + + public void setFavorites(List favorites) { + Set favoritesHashSet = new HashSet(); + for (UUID favorite : favorites) { + favoritesHashSet.add(favorite.toString()); + } + + _prefs.edit().putStringSet("pref_favorites", favoritesHashSet).apply(); + } + public int getTimeout() { return _prefs.getInt("pref_timeout", -1); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/SimpleItemTouchHelperCallback.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/SimpleItemTouchHelperCallback.java index 1c4a5202..4ac8c79e 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/helpers/SimpleItemTouchHelperCallback.java +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/SimpleItemTouchHelperCallback.java @@ -10,11 +10,11 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { private VaultEntry _selectedEntry; - private final ItemTouchHelperAdapter _adapter; + private final EntryAdapter _adapter; private boolean _positionChanged = false; private boolean _isLongPressDragEnabled = true; - public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { + public SimpleItemTouchHelperCallback(EntryAdapter adapter) { _adapter = adapter; } @@ -28,7 +28,14 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { } public void setSelectedEntry(VaultEntry entry) { - _selectedEntry = entry; + if (entry == null) { + _selectedEntry = null; + return; + } + + if (!entry.getIsFavorited()) { + _selectedEntry = entry; + } } @Override @@ -41,13 +48,15 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = 0; - int position = viewHolder.getAdapterPosition(); - EntryAdapter adapter = (EntryAdapter)recyclerView.getAdapter(); - if (adapter.isPositionFooter(position) + if (viewHolder != null) { + int position = viewHolder.getAdapterPosition(); + EntryAdapter adapter = (EntryAdapter)recyclerView.getAdapter(); + if (adapter.isPositionFooter(position) || adapter.getEntryAt(position) != _selectedEntry || !isLongPressDragEnabled()) - { - dragFlags = 0; + { + dragFlags = 0; + } } return makeMovementFlags(dragFlags, swipeFlags); @@ -56,6 +65,9 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { + if(target.getAdapterPosition() < _adapter.getFavorites().size()){ + return false; + } _adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); _positionChanged = true; return true; diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/FavoriteComparator.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/FavoriteComparator.java new file mode 100644 index 00000000..095c4008 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/comparators/FavoriteComparator.java @@ -0,0 +1,12 @@ +package com.beemdevelopment.aegis.helpers.comparators; + +import com.beemdevelopment.aegis.vault.VaultEntry; + +import java.util.Comparator; + +public class FavoriteComparator implements Comparator { + @Override + public int compare(VaultEntry a, VaultEntry b) { + return -1 * Boolean.compare(a.getIsFavorited(), b.getIsFavorited()); + } +} \ 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 d354d14d..95a4419e 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -110,7 +110,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _isDPadPressed = false; _isDoingIntro = false; _isAuthenticating = false; - if (savedInstanceState != null) { _isRecreated = true; _pendingSearchQuery = savedInstanceState.getString("pendingSearchQuery"); @@ -177,10 +176,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene @Override protected void onPause() { Map usageMap = _entryListView.getUsageCounts(); + List favoritesList = _entryListView.getFavorites(); if (usageMap != null) { _prefs.setUsageCount(usageMap); } + if (favoritesList != null) { + _prefs.setFavorites(favoritesList); + } + super.onPause(); } @@ -645,6 +649,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene public boolean onCreateOptionsMenu(Menu menu) { _menu = menu; getMenuInflater().inflate(R.menu.menu_main, menu); + updateLockIcon(); if (_loaded) { _entryListView.setGroups(_vaultManager.getVault().getGroups()); @@ -774,6 +779,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void loadEntries() { if (!_loaded) { _entryListView.setUsageCounts(_prefs.getUsageCounts()); + _entryListView.setFavorites(_prefs.getFavorites()); _entryListView.addEntries(_vaultManager.getVault().getEntries()); _entryListView.runEntriesAnimation(); _loaded = true; @@ -859,6 +865,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene if (_selectedEntries.isEmpty()) { _actionMode.finish(); } else { + setFavoriteMenuItemVisiblity(); setIsMultipleSelected(_selectedEntries.size() > 1); } @@ -882,6 +889,27 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _actionMode.getMenu().findItem(R.id.action_copy).setVisible(!multipleSelected); } + private void setFavoriteMenuItemVisiblity() { + MenuItem toggleFavoriteMenuItem = _actionMode.getMenu().findItem(R.id.action_toggle_favorite); + + if (_selectedEntries.size() == 1){ + if (_selectedEntries.get(0).getIsFavorited()) { + toggleFavoriteMenuItem.setIcon(R.drawable.ic_set_favorite); + toggleFavoriteMenuItem.setTitle(R.string.unfavorite); + } else { + toggleFavoriteMenuItem.setIcon(R.drawable.ic_unset_favorite); + toggleFavoriteMenuItem.setTitle(R.string.favorite); + } + } else { + toggleFavoriteMenuItem.setIcon(R.drawable.ic_unset_favorite); + toggleFavoriteMenuItem.setTitle(String.format("%s / %s", getString(R.string.favorite), getString(R.string.unfavorite))); + } + } + + private void toggleFavorite(VaultEntry entry) { + _entryListView.toggleFavoriteState(entry); + } + @Override public void onLongEntryClick(VaultEntry entry) { if (!_selectedEntries.isEmpty()) { @@ -896,6 +924,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void startActionMode() { _actionMode = startSupportActionMode(_actionModeCallbacks); _actionModeBackPressHandler.setEnabled(true); + setFavoriteMenuItemVisiblity(); } @Override @@ -1021,7 +1050,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private class ActionModeCallbacks implements ActionMode.Callback { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { - MenuInflater inflater = mode.getMenuInflater(); + MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_action_mode, menu); return true; } @@ -1048,6 +1077,14 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene mode.finish(); return true; + case R.id.action_toggle_favorite: + for (VaultEntry entry : _selectedEntries) { + toggleFavorite(entry); + } + + mode.finish(); + return true; + case R.id.action_share_qr: Intent intent = new Intent(getBaseContext(), TransferEntriesActivity.class); ArrayList authInfos = new ArrayList<>(); 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 265e5a2b..263bbb04 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 @@ -19,6 +19,7 @@ import com.beemdevelopment.aegis.Preferences; import com.beemdevelopment.aegis.SortCategory; import com.beemdevelopment.aegis.ViewMode; import com.beemdevelopment.aegis.helpers.ItemTouchHelperAdapter; +import com.beemdevelopment.aegis.helpers.comparators.FavoriteComparator; import com.beemdevelopment.aegis.otp.HotpInfo; import com.beemdevelopment.aegis.otp.OtpInfo; import com.beemdevelopment.aegis.otp.OtpInfoException; @@ -41,6 +42,7 @@ public class EntryAdapter extends RecyclerView.Adapter private List _shownEntries; private List _selectedEntries; private Map _usageCounts; + private List _favorites; private VaultEntry _focusedEntry; private Preferences.CodeGrouping _codeGroupSize; private boolean _showAccountName; @@ -111,6 +113,17 @@ public class EntryAdapter extends RecyclerView.Adapter _pauseFocused = pauseFocused; } + public void toggleFavoriteState(VaultEntry entry) { + if (_favorites.contains(entry.getUUID())) { + _favorites.remove(entry.getUUID()); + } else { + _favorites.add(entry.getUUID()); + } + + entry.setIsFavorited(_favorites.contains(entry.getUUID())); + updateShownEntries(); + } + public VaultEntry getEntryAt(int position) { return _shownEntries.get(position); } @@ -126,7 +139,7 @@ public class EntryAdapter extends RecyclerView.Adapter if (comparator != null) { // insert the entry in the correct order // note: this assumes that _shownEntries has already been sorted - for (int i = 0; i < _shownEntries.size(); i++) { + for (int i = _favorites.size(); i < _shownEntries.size(); i++) { if (comparator.compare(_shownEntries.get(i), entry) > 0) { _shownEntries.add(i, entry); notifyItemInserted(i); @@ -156,6 +169,7 @@ public class EntryAdapter extends RecyclerView.Adapter public void addEntries(Collection entries) { for (VaultEntry entry: entries) { entry.setUsageCount(_usageCounts.containsKey(entry.getUUID()) ? _usageCounts.get(entry.getUUID()) : 0); + entry.setIsFavorited(_favorites.contains(entry.getUUID())); } _entries.addAll(entries); @@ -166,6 +180,10 @@ public class EntryAdapter extends RecyclerView.Adapter public void removeEntry(VaultEntry entry) { _entries.remove(entry); + if (_favorites.contains(entry.getUUID())) { + removeFavorite(entry); + } + if (_shownEntries.contains(entry)) { int position = _shownEntries.indexOf(entry); _shownEntries.remove(position); @@ -303,6 +321,9 @@ public class EntryAdapter extends RecyclerView.Adapter Collections.sort(_shownEntries, comparator); } + Comparator favoriteComparator = new FavoriteComparator(); + Collections.sort(_shownEntries, favoriteComparator); + _view.onListChange(); notifyDataSetChanged(); } @@ -315,6 +336,21 @@ public class EntryAdapter extends RecyclerView.Adapter public Map getUsageCounts() { return _usageCounts; } + public void setFavorites(List favorites) { _favorites = favorites; } + + public List getFavorites() { return _favorites; } + + public void removeFavorite(VaultEntry entry) { + int position = -1; + for (int i = 0; i < _favorites.size(); i++) { + if (_favorites.get(i).equals(entry.getUUID())) { + position = i; + } + } + + _favorites.remove(position); + } + public void setGroups(TreeSet groups) { _view.setGroups(groups); } @@ -449,7 +485,7 @@ public class EntryAdapter extends RecyclerView.Adapter boolean dragEnabled = _selectedEntries.size() == 0 || _selectedEntries.size() == 1 && _selectedEntries.get(0) == entryHolder.getEntry(); - if (dragEnabled && isDragAndDropAllowed()) { + if (dragEnabled && isDragAndDropAllowed() && !entryHolder.getEntry().getIsFavorited()) { _view.startDrag(_dragHandleHolder); } @@ -463,7 +499,8 @@ public class EntryAdapter extends RecyclerView.Adapter if (event.getActionMasked() == MotionEvent.ACTION_MOVE && _selectedEntries.size() == 1 && _selectedEntries.get(0) == entryHolder.getEntry() - && isDragAndDropAllowed()) { + && isDragAndDropAllowed() + && !entryHolder.getEntry().getIsFavorited()) { _view.startDrag(_dragHandleHolder); return true; } @@ -607,7 +644,7 @@ public class EntryAdapter extends RecyclerView.Adapter return; } - if (_selectedEntries.size() == 1 && _dragHandleHolder == null) { + if (_selectedEntries.size() == 1 && _dragHandleHolder == null && !_selectedEntries.get(0).getIsFavorited()) { // Find and enable dragging for the single selected EntryHolder // Not nice but this is the best method I could find for (int i = 0; i < _holders.size(); i++) { diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java index 88b40ac0..f31f5e0e 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java @@ -35,6 +35,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { private static final float DIMMED_ALPHA = 0.2f; private static final char HIDDEN_CHAR = '●'; + private View _favoriteIndicator; private TextView _profileName; private TextView _profileCode; private TextView _profileIssuer; @@ -76,6 +77,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { _buttonRefresh = view.findViewById(R.id.buttonRefresh); _selected = view.findViewById(R.id.ivSelected); _dragHandle = view.findViewById(R.id.drag_handle); + _favoriteIndicator = view.findViewById(R.id.favorite_indicator); _selectedHandler = new Handler(); _animationHandler = new Handler(); @@ -114,6 +116,8 @@ public class EntryHolder extends RecyclerView.ViewHolder { _selectedHandler.removeCallbacksAndMessages(null); _animationHandler.removeCallbacksAndMessages(null); + _favoriteIndicator.setVisibility(_entry.getIsFavorited() ? View.VISIBLE : View.INVISIBLE); + // only show the progress bar if there is no uniform period and the entry type is TotpInfo setShowProgress(showProgress); 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 5176154d..93ef8096 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 @@ -197,6 +197,12 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { return _adapter.getUsageCounts(); } + public void setFavorites(List favorites) { + _adapter.setFavorites(favorites); + } + + public List getFavorites() { return _adapter.getFavorites(); } + public void setSearchFilter(String search) { _adapter.setSearchFilter(search); _touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed()); @@ -350,6 +356,10 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { } } + public void toggleFavoriteState(VaultEntry entry) { + _adapter.toggleFavoriteState(entry); + } + public void tempHighlightEntry(VaultEntry entry) { _adapter.setTempHighlightEntry(true); @@ -543,7 +553,23 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { // the first item should also have a top margin outRect.top = _height; } - outRect.bottom = _height; + + int adapterPosition = parent.getChildAdapterPosition(view); + if (adapterPosition == -1) { + return; + } + + if (adapterPosition < _adapter.getEntriesCount() && _adapter.getEntryAt(adapterPosition).getIsFavorited()) { + if (_adapter.getFavorites().size() == parent.getChildAdapterPosition(view) + 1) { + outRect.bottom = MetricsHelper.convertDpToPixels(requireContext(), 20); + return; + } + + outRect.bottom = 0; + return; + } + + outRect.top = _height; } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultEntry.java b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultEntry.java index 1ed4ed4a..4aca13a3 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultEntry.java +++ b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultEntry.java @@ -26,6 +26,7 @@ public class VaultEntry extends UUIDMap.Value { private OtpInfo _info; private byte[] _icon; private IconType _iconType = IconType.INVALID; + private boolean _isFavorited; private int _usageCount; private String _note = ""; @@ -142,6 +143,8 @@ public class VaultEntry extends UUIDMap.Value { public String getNote() { return _note; } + public boolean getIsFavorited() { return _isFavorited; }; + public void setName(String name) { _name = name; } @@ -171,6 +174,8 @@ public class VaultEntry extends UUIDMap.Value { public void setNote(String note) { _note = note; } + public void setIsFavorited(boolean isFavorited) { _isFavorited = isFavorited; } + @Override public boolean equals(Object o) { if (!(o instanceof VaultEntry)) { diff --git a/app/src/main/res/drawable-anydpi/ic_set_favorite.xml b/app/src/main/res/drawable-anydpi/ic_set_favorite.xml new file mode 100644 index 00000000..13942be1 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_set_favorite.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable-anydpi/ic_unset_favorite.xml b/app/src/main/res/drawable-anydpi/ic_unset_favorite.xml new file mode 100644 index 00000000..7752b92f --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_unset_favorite.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/layout/card_entry.xml b/app/src/main/res/layout/card_entry.xml index 70027524..46ac5576 100644 --- a/app/src/main/res/layout/card_entry.xml +++ b/app/src/main/res/layout/card_entry.xml @@ -18,6 +18,14 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + + + android:layout_centerVertical="true" /> + + + + app:showAsAction="ifRoom"/> #5472d3 #FF5252 #FF5252 + #F9A825 #212121 #A0A0A0 #4c4c4c diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ccb3a7bb..75e1da2b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -152,6 +152,8 @@ Set up biometric unlock Copy Edit + Favorite + Unfavorite ERROR Password Confirm password