diff --git a/app/src/main/java/com/beemdevelopment/aegis/ViewMode.java b/app/src/main/java/com/beemdevelopment/aegis/ViewMode.java index e1e4e6941e..9d3498507b 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ViewMode.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ViewMode.java @@ -5,7 +5,8 @@ public enum ViewMode { NORMAL, COMPACT, - SMALL; + SMALL, + TILES; private static ViewMode[] _values; @@ -26,6 +27,8 @@ public int getLayoutId() { return R.layout.card_entry_compact; case SMALL: return R.layout.card_entry_small; + case TILES: + return R.layout.card_entry_tile; default: return R.layout.card_entry; } @@ -37,8 +40,34 @@ public int getLayoutId() { public float getDividerHeight() { if (this == ViewMode.COMPACT) { return 0; + } else if (this == ViewMode.TILES) { + return 4; } return 20; } + + public int getColumnSpan() { + if (this == ViewMode.TILES) { + return 2; + } + + return 1; + } + + public float getDividerWidth() { + if (this == ViewMode.TILES) { + return 4; + } + + return 0; + } + + public String getFormattedAccountName(String accountName) { + if (this == ViewMode.TILES) { + return accountName; + } + + return String.format("(%s)", accountName); + } } 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 eb84351f00..959f2cf801 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/helpers/SimpleItemTouchHelperCallback.java +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/SimpleItemTouchHelperCallback.java @@ -16,6 +16,7 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { private final EntryAdapter _adapter; private boolean _positionChanged = false; private boolean _isLongPressDragEnabled = true; + private int _dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; public SimpleItemTouchHelperCallback(EntryAdapter adapter) { _adapter = adapter; @@ -46,6 +47,10 @@ public boolean isItemViewSwipeEnabled() { return false; } + public void setDragFlags(int dragFlags) { + _dragFlags = dragFlags; + } + @Override public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { // It's not clear when this can happen, but sometimes the ViewHolder @@ -57,16 +62,15 @@ public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull Recycle } int swipeFlags = 0; - int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; EntryAdapter adapter = (EntryAdapter) recyclerView.getAdapter(); if (adapter.isPositionFooter(position) || adapter.getEntryAt(position) != _selectedEntry || !isLongPressDragEnabled()) { - dragFlags = 0; + return makeMovementFlags(0, swipeFlags); } - return makeMovementFlags(dragFlags, swipeFlags); + return makeMovementFlags(_dragFlags, swipeFlags); } @Override @@ -75,7 +79,11 @@ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHol if (target.getAdapterPosition() < _adapter.getShownFavoritesCount()){ return false; } - _adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); + + int firstPosition = viewHolder.getLayoutPosition(); + int secondPosition = target.getAdapterPosition(); + + _adapter.onItemMove(firstPosition, secondPosition); _positionChanged = true; return true; } @@ -92,6 +100,7 @@ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHol if (_positionChanged) { _adapter.onItemDrop(viewHolder.getAdapterPosition()); _positionChanged = false; + _adapter.refresh(false); } } } 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 1708fdffa0..5938512fa5 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -948,8 +948,8 @@ private void startActionMode() { } @Override - public void onEntryMove(VaultEntry entry1, VaultEntry entry2) { - _vaultManager.getVault().swapEntries(entry1, entry2); + public void onEntryMove(VaultEntry entry1, VaultEntry entry2, boolean adjacent) { + _vaultManager.getVault().swapEntries(entry1, entry2, adjacent); } @Override diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java index 798a5e6e42..7253860a0b 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AppearancePreferencesFragment.java @@ -17,6 +17,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment { private Preference _groupsPreference; private Preference _resetUsageCountPreference; + private Preference _currentAccountNamePositionPreference; @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { @@ -89,6 +90,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { _prefs.setCurrentViewMode(ViewMode.fromInteger(i)); viewModePreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.view_mode_titles)[i])); getResult().putExtra("needsRefresh", true); + overrideAccountNamePosition(ViewMode.fromInteger(i) == ViewMode.TILES); dialog.dismiss(); }) .setNegativeButton(android.R.string.cancel, null) @@ -104,9 +106,9 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { }); int currentAccountNamePosition = _prefs.getAccountNamePosition().ordinal(); - Preference currentAccountNamePositionPreference = requirePreference("pref_account_name_position"); - currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[currentAccountNamePosition])); - currentAccountNamePositionPreference.setOnPreferenceClickListener(preference -> { + _currentAccountNamePositionPreference = requirePreference("pref_account_name_position"); + _currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[currentAccountNamePosition])); + _currentAccountNamePositionPreference.setOnPreferenceClickListener(preference -> { int currentAccountNamePosition1 = _prefs.getAccountNamePosition().ordinal(); Dialogs.showSecureDialog(new AlertDialog.Builder(requireContext()) @@ -114,7 +116,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { .setSingleChoiceItems(R.array.account_name_position_titles, currentAccountNamePosition1, (dialog, which) -> { int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); _prefs.setAccountNamePosition(AccountNamePosition.fromInteger(i)); - currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[i])); + _currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[i])); getResult().putExtra("needsRefresh", true); dialog.dismiss(); }) @@ -130,4 +132,14 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { return true; }); } + + private void overrideAccountNamePosition(boolean override) { + if (override) { + _currentAccountNamePositionPreference.setEnabled(false); + _currentAccountNamePositionPreference.setSummary("This setting is overridden by the tiles view mode. Account name will always be shown below the issuer."); + } else { + _currentAccountNamePositionPreference.setEnabled(true); + _currentAccountNamePositionPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.account_name_position_titles)[_prefs.getAccountNamePosition().ordinal()])); + } + } } 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 c3ff1ae801..0e877781a8 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 @@ -29,6 +29,7 @@ import com.beemdevelopment.aegis.otp.OtpInfo; import com.beemdevelopment.aegis.otp.OtpInfoException; import com.beemdevelopment.aegis.otp.TotpInfo; +import com.beemdevelopment.aegis.util.CollectionUtils; import com.beemdevelopment.aegis.vault.VaultEntry; import java.util.ArrayList; @@ -375,11 +376,17 @@ public void onItemMove(int firstPosition, int secondPosition) { } // notify the vault first - _view.onEntryMove(_entries.get(firstPosition), _entries.get(secondPosition)); + int difference = firstPosition - secondPosition; + _view.onEntryMove(_entries.get(firstPosition), _entries.get(secondPosition), Math.abs(difference) == 1); + + if (Math.abs(difference) > 1) { + CollectionUtils.move(_entries, firstPosition, secondPosition); + CollectionUtils.move(_shownEntries, firstPosition, secondPosition); + } else { + Collections.swap(_entries, firstPosition, secondPosition); + Collections.swap(_shownEntries, firstPosition, secondPosition); + } - // update our side of things - Collections.swap(_entries, firstPosition, secondPosition); - Collections.swap(_shownEntries, firstPosition, secondPosition); notifyItemMoved(firstPosition, secondPosition); } @@ -424,7 +431,7 @@ public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) boolean paused = _pauseFocused && entry == _focusedEntry; boolean dimmed = (_highlightEntry || _tempHighlightEntry) && _focusedEntry != null && _focusedEntry != entry; boolean showProgress = entry.getInfo() instanceof TotpInfo && ((TotpInfo) entry.getInfo()).getPeriod() != getMostFrequentPeriod(); - entryHolder.setData(entry, _codeGroupSize, _accountNamePosition, _showIcon, showProgress, hidden, paused, dimmed); + entryHolder.setData(entry, _codeGroupSize, _viewMode, _accountNamePosition, _showIcon, showProgress, hidden, paused, dimmed); entryHolder.setFocused(_selectedEntries.contains(entry)); entryHolder.setShowDragHandle(isEntryDraggable(entry)); @@ -453,7 +460,7 @@ public void onClick(View v) { case SINGLETAP: if (!handled) { _view.onEntryCopy(entry); - entryHolder.animateCopyText(); + entryHolder.animateCopyText(_viewMode != ViewMode.TILES); _clickedEntry = null; } break; @@ -462,7 +469,7 @@ public void onClick(View v) { if(entry == _clickedEntry) { _view.onEntryCopy(entry); - entryHolder.animateCopyText(); + entryHolder.animateCopyText(_viewMode != ViewMode.TILES); _clickedEntry = null; } else { _clickedEntry = entry; @@ -754,7 +761,7 @@ public void refresh() { public interface Listener { void onEntryClick(VaultEntry entry); boolean onLongEntryClick(VaultEntry entry); - void onEntryMove(VaultEntry entry1, VaultEntry entry2); + void onEntryMove(VaultEntry entry1, VaultEntry entry2, boolean adjacent); void onEntryDrop(VaultEntry entry); void onEntryChange(VaultEntry entry); void onEntryCopy(VaultEntry entry); 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 4c5070c34f..05e5a4f0c2 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 @@ -16,6 +16,7 @@ import com.beemdevelopment.aegis.AccountNamePosition; import com.beemdevelopment.aegis.Preferences; import com.beemdevelopment.aegis.R; +import com.beemdevelopment.aegis.ViewMode; import com.beemdevelopment.aegis.helpers.IconViewHelper; import com.beemdevelopment.aegis.helpers.TextDrawableHelper; import com.beemdevelopment.aegis.helpers.ThemeHelper; @@ -46,6 +47,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { private ImageView _buttonRefresh; private RelativeLayout _description; private ImageView _dragHandle; + private ViewMode _viewMode; private final ImageView _selected; private final Handler _selectedHandler; @@ -107,11 +109,12 @@ public long getMillisTillNextRefresh() { }); } - public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, AccountNamePosition accountNamePosition, boolean showIcon, boolean showProgress, boolean hidden, boolean paused, boolean dimmed) { + public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMode viewMode, AccountNamePosition accountNamePosition, boolean showIcon, boolean showProgress, boolean hidden, boolean paused, boolean dimmed) { _entry = entry; _hidden = hidden; _paused = paused; _codeGrouping = groupSize; + _viewMode = viewMode; _accountNamePosition = accountNamePosition; _selected.clearAnimation(); @@ -129,12 +132,12 @@ public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, Accoun String profileIssuer = entry.getIssuer(); String profileName = entry.getName(); - if (!profileIssuer.isEmpty() && !profileName.isEmpty() && accountNamePosition == AccountNamePosition.END) { - profileName = String.format(" (%s)", profileName); + if (!profileIssuer.isEmpty() && !profileName.isEmpty() && _accountNamePosition == AccountNamePosition.END) { + profileName = _viewMode.getFormattedAccountName(profileName); } _profileIssuer.setText(profileIssuer); _profileName.setText(profileName); - setAccountNameLayout(accountNamePosition); + setAccountNameLayout(_accountNamePosition); if (_hidden) { hideCode(); @@ -148,6 +151,10 @@ public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, Accoun } private void setAccountNameLayout(AccountNamePosition accountNamePosition) { + if (_viewMode == ViewMode.TILES) { + return; + } + RelativeLayout.LayoutParams profileNameLayoutParams; RelativeLayout.LayoutParams copiedLayoutParams; switch (accountNamePosition) { @@ -367,7 +374,7 @@ public void highlight() { animateAlphaTo(DEFAULT_ALPHA); } - public void animateCopyText() { + public void animateCopyText(boolean includeSlideAnimation) { _animationHandler.removeCallbacksAndMessages(null); Animation slideDownFadeIn = AnimationUtils.loadAnimation(itemView.getContext(), R.anim.slide_down_fade_in); @@ -375,16 +382,25 @@ public void animateCopyText() { Animation fadeOut = AnimationUtils.loadAnimation(itemView.getContext(), R.anim.fade_out); Animation fadeIn = AnimationUtils.loadAnimation(itemView.getContext(), R.anim.fade_in); - _profileCopied.startAnimation(slideDownFadeIn); - - View fadeOutView = (_accountNamePosition == AccountNamePosition.BELOW) ? _profileName : _description; + if (includeSlideAnimation) { + _profileCopied.startAnimation(slideDownFadeIn); + View fadeOutView = (_accountNamePosition == AccountNamePosition.BELOW) ? _profileName : _description; fadeOutView.startAnimation(slideDownFadeOut); - _animationHandler.postDelayed(() -> { - _profileCopied.startAnimation(fadeOut); - fadeOutView.startAnimation(fadeIn); - }, 3000); + _animationHandler.postDelayed(() -> { + _profileCopied.startAnimation(fadeOut); + fadeOutView.startAnimation(fadeIn); + }, 3000); + } else { + _profileCopied.startAnimation(fadeIn); + _profileName.startAnimation(fadeOut); + + _animationHandler.postDelayed(() -> { + _profileCopied.startAnimation(fadeOut); + _profileName.startAnimation(fadeIn); + }, 3000); + } } private void animateAlphaTo(float alpha) { 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 a33103c153..4aeefe02e3 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 @@ -19,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -64,7 +65,8 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { private ItemTouchHelper _touchHelper; private RecyclerView _recyclerView; - private RecyclerView.ItemDecoration _dividerDecoration; + private RecyclerView.ItemDecoration _verticalDividerDecoration; + private RecyclerView.ItemDecoration _horizontalDividerDecoration; private ViewPreloadSizeProvider _preloadSizeProvider; private TotpProgressBar _progressBar; private boolean _showProgress; @@ -122,7 +124,17 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { RecyclerViewPreloader preloader = new RecyclerViewPreloader<>(Glide.with(this), modelProvider, _preloadSizeProvider, 10); _recyclerView.addOnScrollListener(preloader); - LinearLayoutManager layoutManager = new LinearLayoutManager(requireContext()); + GridLayoutManager layoutManager = new GridLayoutManager(requireContext(), 1); + layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + if (_viewMode == ViewMode.TILES && position == _adapter.getEntriesCount()) { + return 2; + } + + return 1; + } + }); _recyclerView.setLayoutManager(layoutManager); _touchCallback = new SimpleItemTouchHelperCallback(_adapter); _touchHelper = new ItemTouchHelper(_touchCallback); @@ -222,6 +234,13 @@ public void setViewMode(ViewMode mode) { _viewMode = mode; updateDividerDecoration(); _adapter.setViewMode(_viewMode); + if (_viewMode == ViewMode.TILES) { + _touchCallback.setDragFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); + } else { + _touchCallback.setDragFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN); + } + + ((GridLayoutManager)_recyclerView.getLayoutManager()).setSpanCount(mode.getColumnSpan()); } public void startDrag(RecyclerView.ViewHolder viewHolder) { @@ -255,9 +274,9 @@ public boolean onLongEntryClick(VaultEntry entry) { } @Override - public void onEntryMove(VaultEntry entry1, VaultEntry entry2) { + public void onEntryMove(VaultEntry entry1, VaultEntry entry2, boolean adjacent) { if (_listener != null) { - _listener.onEntryMove(entry1, entry2); + _listener.onEntryMove(entry1, entry2, adjacent); } } @@ -532,18 +551,28 @@ private List cleanGroupFilter(List groupFilter) { } private void updateDividerDecoration() { - if (_dividerDecoration != null) { - _recyclerView.removeItemDecoration(_dividerDecoration); + if (_verticalDividerDecoration != null) { + _recyclerView.removeItemDecoration(_verticalDividerDecoration); + } + + if(_horizontalDividerDecoration != null) { + _recyclerView.removeItemDecoration(_horizontalDividerDecoration); } float height = _viewMode.getDividerHeight(); + float width = _viewMode.getDividerWidth(); if (_showProgress && height == 0) { - _dividerDecoration = new CompactDividerDecoration(); + _verticalDividerDecoration = new CompactDividerDecoration(); } else { - _dividerDecoration = new VerticalSpaceItemDecoration(height); + _verticalDividerDecoration = new VerticalSpaceItemDecoration(height); } - _recyclerView.addItemDecoration(_dividerDecoration); + if (width != 0) { + _horizontalDividerDecoration = new TileSpaceItemDecoration(width, height); + _recyclerView.addItemDecoration(_horizontalDividerDecoration); + } else { + _recyclerView.addItemDecoration(_verticalDividerDecoration); + } } private void updateEmptyState() { @@ -560,7 +589,7 @@ private void updateEmptyState() { public interface Listener { void onEntryClick(VaultEntry entry); - void onEntryMove(VaultEntry entry1, VaultEntry entry2); + void onEntryMove(VaultEntry entry1, VaultEntry entry2, boolean adjacent); void onEntryDrop(VaultEntry entry); void onEntryChange(VaultEntry entry); void onEntryCopy(VaultEntry entry); @@ -649,6 +678,30 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R } } + private class TileSpaceItemDecoration extends RecyclerView.ItemDecoration { + private final int _width; + private final int _height; + + private TileSpaceItemDecoration(float width, float height) { + // convert dp to pixels + _width = MetricsHelper.convertDpToPixels(requireContext(), width); + _height = MetricsHelper.convertDpToPixels(requireContext(), height); + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + int adapterPosition = parent.getChildAdapterPosition(view); + if (adapterPosition == NO_POSITION) { + return; + } + + outRect.left = _width; + outRect.right = _width; + outRect.top = _height; + outRect.bottom = _height; + } + } + private class IconPreloadProvider implements ListPreloader.PreloadModelProvider { @NonNull @Override diff --git a/app/src/main/java/com/beemdevelopment/aegis/util/CollectionUtils.java b/app/src/main/java/com/beemdevelopment/aegis/util/CollectionUtils.java new file mode 100644 index 0000000000..ef0cd776aa --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/util/CollectionUtils.java @@ -0,0 +1,15 @@ +package com.beemdevelopment.aegis.util; + +import java.util.List; + +public class CollectionUtils { + + public static void move(List list, int fromIndex, int toIndex) { + if (fromIndex == toIndex) { + return; + } + + T item = list.remove(fromIndex); + list.add(toIndex, item); + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/util/UUIDMap.java b/app/src/main/java/com/beemdevelopment/aegis/util/UUIDMap.java index c5b29f09a2..fb186328f8 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/util/UUIDMap.java +++ b/app/src/main/java/com/beemdevelopment/aegis/util/UUIDMap.java @@ -63,6 +63,25 @@ public T replace(T newValue) { return oldValue; } + public void move(T value1, T value2) { + List values = new ArrayList<>(); + + for (T value : _map.values()) { + if (!value.getUUID().equals(value1.getUUID())) { + values.add(value); + + if (value.getUUID().equals(value2.getUUID())) { + values.add(value1); + } + } + } + + _map.clear(); + for (T value : values) { + _map.put(value.getUUID(), value); + } + } + /** * Swaps the position of value1 and value2 in the internal map. This operation is * quite expensive because it has to reallocate the entire underlying LinkedHashMap. diff --git a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java index 6b96fe7908..7a1ce1f1aa 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java +++ b/app/src/main/java/com/beemdevelopment/aegis/vault/VaultRepository.java @@ -239,8 +239,12 @@ public VaultEntry replaceEntry(VaultEntry entry) { return _vault.getEntries().replace(entry); } - public void swapEntries(VaultEntry entry1, VaultEntry entry2) { - _vault.getEntries().swap(entry1, entry2); + public void swapEntries(VaultEntry entry1, VaultEntry entry2, boolean adjacent) { + if (adjacent) { + _vault.getEntries().swap(entry1, entry2); + } else { + _vault.getEntries().move(entry1, entry2); + } } public boolean isEntryDuplicate(VaultEntry entry) { diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml index 481e19e056..763c8a54bf 100644 --- a/app/src/main/res/anim/fade_in.xml +++ b/app/src/main/res/anim/fade_in.xml @@ -1,5 +1,7 @@ - + - + + - \ No newline at end of file diff --git a/app/src/main/res/layout/card_entry_tile.xml b/app/src/main/res/layout/card_entry_tile.xml new file mode 100644 index 0000000000..18748c0b45 --- /dev/null +++ b/app/src/main/res/layout/card_entry_tile.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index e01112f8a2..81d6abbce6 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -32,6 +32,7 @@ @string/normal_viewmode_title @string/compact_mode_title @string/small_mode_title + @string/tiles_mode_title diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 58a6a87f18..1df297cd87 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -43,6 +43,7 @@ Code digit grouping Select number of digits to group codes by Show the account name + This setting is overridden by the tiles view mode. Account name will always be shown below the issuer. Import from file Import tokens from a file Android cloud backups @@ -327,6 +328,7 @@ Normal Compact Small + Tiles Unknown issuer Unknown account name