From f8c106bcb94fb6fe0946f21cfd1670ed44ed7c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Sat, 4 Jan 2020 20:38:40 +0100 Subject: [PATCH] Add ability to select multiple entries Improve code and add select listeners --- .../com/beemdevelopment/aegis/ui/Dialogs.java | 18 ++++++ .../aegis/ui/MainActivity.java | 59 ++++++++++++++----- .../aegis/ui/views/EntryAdapter.java | 37 +++++++++--- .../aegis/ui/views/EntryListView.java | 14 ++++- app/src/main/res/values/strings.xml | 2 + 5 files changed, 107 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/Dialogs.java b/app/src/main/java/com/beemdevelopment/aegis/ui/Dialogs.java index 4b2b9bcd..3731e2ef 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/Dialogs.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/Dialogs.java @@ -57,6 +57,24 @@ public class Dialogs { .create()); } + public static void showDeleteEntriesDialog(Activity activity, DialogInterface.OnClickListener onDelete, int totalEntries) { + String title, message; + if (totalEntries > 1) { + title = activity.getString(R.string.delete_entries); + message = String.format(activity.getString(R.string.delete_entries_description), totalEntries); + } else { + title = activity.getString(R.string.delete_entry); + message = activity.getString(R.string.delete_entry_description); + } + + showSecureDialog(new AlertDialog.Builder(activity) + .setTitle(title) + .setMessage(message) + .setPositiveButton(android.R.string.yes, onDelete) + .setNegativeButton(android.R.string.no, null) + .create()); + } + public static void showDiscardDialog(Activity activity, DialogInterface.OnClickListener onSave, DialogInterface.OnClickListener onDiscard) { showSecureDialog(new AlertDialog.Builder(activity) .setTitle(activity.getString(R.string.discard_changes)) 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 64a5946e..a841af8d 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -73,7 +73,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private String _selectedGroup; private boolean _searchSubmitted; - private VaultEntry _selectedEntry; + private List _selectedEntries; private ActionMode _actionMode; private Menu _menu; @@ -123,6 +123,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene }); _fabScrollHelper = new FabScrollHelper(_fabMenu); + _selectedEntries = new ArrayList<>(); } @Override @@ -502,6 +503,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene super.onBackPressed(); } + private void deleteEntries(List entries) { + for (VaultEntry entry: entries) { + VaultEntry oldEntry = _vault.removeEntry(entry); + _entryListView.removeEntry(oldEntry); + } + + saveVault(); + } + private void deleteEntry(VaultEntry entry) { VaultEntry oldEntry = _vault.removeEntry(entry); saveVault(); @@ -671,9 +681,11 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene @Override public void onEntryClick(VaultEntry entry) { - if (_selectedEntry != null) { - if (_selectedEntry == entry) { + if (_actionMode != null) { + if (_selectedEntries.isEmpty()) { _actionMode.finish(); + } else { + setIsMultipleSelected(_selectedEntries.size() > 1); } return; @@ -682,13 +694,29 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene copyEntryCode(entry); } + @Override + public void onSelect(VaultEntry entry) { + _selectedEntries.add(entry); + } + + @Override + public void onDeselect(VaultEntry entry) { + _selectedEntries.remove(entry); + } + + private void setIsMultipleSelected(boolean multipleSelected) { + _entryListView.setIsLongPressDragEnabled(!multipleSelected); + _actionMode.getMenu().findItem(R.id.action_edit).setVisible(!multipleSelected); + _actionMode.getMenu().findItem(R.id.action_copy).setVisible(!multipleSelected); + } + @Override public void onLongEntryClick(VaultEntry entry) { - if (_selectedEntry != null) { + if (!_selectedEntries.isEmpty()) { return; } - _selectedEntry = entry; + _selectedEntries.add(entry); _entryListView.setActionModeState(true, entry); _actionMode = this.startSupportActionMode(_actionModeCallbacks); } @@ -753,26 +781,29 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.action_copy: - copyEntryCode(_selectedEntry); + copyEntryCode(_selectedEntries.get(0)); mode.finish(); return true; case R.id.action_edit: - startEditProfileActivity(CODE_EDIT_ENTRY, _selectedEntry, false); + startEditProfileActivity(CODE_EDIT_ENTRY, _selectedEntries.get(0), false); mode.finish(); return true; case R.id.action_delete: - Dialogs.showDeleteEntryDialog(MainActivity.this, (d, which) -> { - deleteEntry(_selectedEntry); + Dialogs.showDeleteEntriesDialog(MainActivity.this, (d, which) -> { + deleteEntries(_selectedEntries); - if (_selectedEntry.getGroup() != null) { - if (!_vault.getGroups().contains(_selectedEntry.getGroup())) { - updateGroupFilterMenu(); + for (VaultEntry entry : _selectedEntries) { + if (entry.getGroup() != null) { + if (!_vault.getGroups().contains(entry.getGroup())) { + updateGroupFilterMenu(); + } } } + mode.finish(); - }); + }, _selectedEntries.size()); return true; default: return false; @@ -782,7 +813,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene @Override public void onDestroyActionMode(ActionMode mode) { _entryListView.setActionModeState(false, null); - _selectedEntry = null; + _selectedEntries.clear(); _actionMode = null; } } 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 fbf36061..c2bc113d 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 @@ -26,7 +26,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I private EntryListView _view; private List _entries; private List _shownEntries; - private VaultEntry _selectedEntry; + private List _selectedEntries; private VaultEntry _focusedEntry; private boolean _showAccountName; private boolean _searchAccountName; @@ -46,6 +46,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I public EntryAdapter(EntryListView view) { _entries = new ArrayList<>(); _shownEntries = new ArrayList<>(); + _selectedEntries = new ArrayList<>(); _holders = new ArrayList<>(); _dimHandler = new Handler(); _view = view; @@ -302,7 +303,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I @Override public void onBindViewHolder(final EntryHolder holder, int position) { VaultEntry entry = _shownEntries.get(position); - holder.setFocused(entry == _selectedEntry); + holder.setFocused(_selectedEntries.contains(entry)); boolean hidden = _tapToReveal && entry != _focusedEntry; boolean dimmed = _highlightEntry && _focusedEntry != null && _focusedEntry != entry; @@ -315,7 +316,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I public void onClick(View v) { boolean handled = false; - if (_selectedEntry == null) { + if (_selectedEntries.isEmpty()) { if (_highlightEntry || _tapToReveal) { if (_focusedEntry == entry) { resetFocus(); @@ -324,6 +325,16 @@ public class EntryAdapter extends RecyclerView.Adapter implements I focusEntry(entry); } } + } else { + if (_selectedEntries.contains(entry)) { + _view.onDeselect(entry); + removeSelectedEntry(entry); + holder.setFocused(false); + } else { + holder.setFocused(true); + addSelectedEntry(entry); + _view.onSelect(entry); + } } if (!handled) { @@ -335,8 +346,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I @Override public boolean onLongClick(View v) { int position = holder.getAdapterPosition(); - if (_selectedEntry == null) { - setSelectedEntry(_shownEntries.get(position)); + if (_selectedEntries.isEmpty()) { holder.setFocused(true); } @@ -444,14 +454,23 @@ public class EntryAdapter extends RecyclerView.Adapter implements I _focusedEntry = null; } - public void setSelectedEntry(VaultEntry entry) { + public void removeSelectedEntry(VaultEntry entry) { + _selectedEntries.remove(entry); + } + + public void addSelectedEntry(VaultEntry entry) { if (entry == null) { - notifyItemChanged(_shownEntries.indexOf(_selectedEntry)); + for (VaultEntry vaultEntry: _selectedEntries) { + notifyItemChanged(_shownEntries.indexOf(vaultEntry)); + } + + _selectedEntries.clear(); + return; } else if (_highlightEntry) { resetFocus(); } - _selectedEntry = entry; + _selectedEntries.add(entry); } public boolean isDragAndDropAllowed() { @@ -474,5 +493,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I void onEntryDrop(VaultEntry entry); void onEntryChange(VaultEntry entry); void onPeriodUniformityChanged(boolean uniform); + void onSelect(VaultEntry entry); + void onDeselect(VaultEntry entry); } } 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 d7dab9d4..c174811b 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 @@ -132,10 +132,14 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { } } + public void setIsLongPressDragEnabled(boolean enabled) { + _touchCallback.setIsLongPressDragEnabled(enabled); + } + public void setActionModeState(boolean enabled, VaultEntry entry) { _touchCallback.setSelectedEntry(entry); _touchCallback.setIsLongPressDragEnabled(enabled && _adapter.isDragAndDropAllowed()); - _adapter.setSelectedEntry(entry); + _adapter.addSelectedEntry(entry); } public void setSortCategory(SortCategory sortCategory, boolean apply) { @@ -194,6 +198,12 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { _listener.onEntryChange(entry); } + @Override + public void onSelect(VaultEntry entry) { _listener.onSelect(entry); } + + @Override + public void onDeselect(VaultEntry entry) { _listener.onDeselect(entry); } + @Override public void onPeriodUniformityChanged(boolean isUniform) { setShowProgress(isUniform); @@ -298,6 +308,8 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { void onEntryChange(VaultEntry entry); void onLongEntryClick(VaultEntry entry); void onScroll(int dx, int dy); + void onSelect(VaultEntry entry); + void onDeselect(VaultEntry entry); } private class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e9fd23a4..d149d768 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -92,6 +92,8 @@ Encrypting the vault Delete entry Are you sure you want to delete this entry? + Delete entries + Are you sure you want to delete %d entries? Discard changes? Your changes have not been saved Folder