mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-06-08 07:37:44 +00:00
Add tiles view mode
Minor UI improvements Fix animations Fix typo Improvements made after PR review PR improvements Co-authored-by: Alexander Bakkker <ab@alexbakker.me>
This commit is contained in:
parent
94a38e82e4
commit
d90303cf0e
16 changed files with 461 additions and 107 deletions
|
@ -5,7 +5,8 @@ import androidx.annotation.LayoutRes;
|
|||
public enum ViewMode {
|
||||
NORMAL,
|
||||
COMPACT,
|
||||
SMALL;
|
||||
SMALL,
|
||||
TILES;
|
||||
|
||||
private static ViewMode[] _values;
|
||||
|
||||
|
@ -26,6 +27,8 @@ public enum ViewMode {
|
|||
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 enum ViewMode {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
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 class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
}
|
||||
|
||||
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 class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
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 class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||
if (_positionChanged) {
|
||||
_adapter.onItemDrop(viewHolder.getAdapterPosition());
|
||||
_positionChanged = false;
|
||||
_adapter.refresh(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -952,7 +952,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
|
||||
@Override
|
||||
public void onEntryMove(VaultEntry entry1, VaultEntry entry2) {
|
||||
_vaultManager.getVault().swapEntries(entry1, entry2);
|
||||
_vaultManager.getVault().moveEntry(entry1, entry2);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
|||
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 class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
_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)
|
||||
|
@ -110,9 +112,9 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
});
|
||||
|
||||
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())
|
||||
|
@ -120,7 +122,7 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
.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();
|
||||
})
|
||||
|
@ -135,5 +137,17 @@ public class AppearancePreferencesFragment extends PreferencesFragment {
|
|||
getResult().putExtra("needsRefresh", true);
|
||||
return true;
|
||||
});
|
||||
|
||||
overrideAccountNamePosition(_prefs.getCurrentViewMode() == ViewMode.TILES);
|
||||
}
|
||||
|
||||
private void overrideAccountNamePosition(boolean override) {
|
||||
if (override) {
|
||||
_currentAccountNamePositionPreference.setEnabled(false);
|
||||
_currentAccountNamePositionPreference.setSummary(getString(R.string.pref_account_name_position_summary_override));
|
||||
} 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()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.beemdevelopment.aegis.otp.HotpInfo;
|
|||
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;
|
||||
|
@ -382,9 +383,10 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
// notify the vault first
|
||||
_view.onEntryMove(_entries.get(firstPosition), _entries.get(secondPosition));
|
||||
|
||||
// update our side of things
|
||||
Collections.swap(_entries, firstPosition, secondPosition);
|
||||
Collections.swap(_shownEntries, firstPosition, secondPosition);
|
||||
// then update our end
|
||||
CollectionUtils.move(_entries, firstPosition, secondPosition);
|
||||
CollectionUtils.move(_shownEntries, firstPosition, secondPosition);
|
||||
|
||||
notifyItemMoved(firstPosition, secondPosition);
|
||||
}
|
||||
|
||||
|
@ -438,7 +440,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
}
|
||||
|
||||
AccountNamePosition accountNamePosition = showAccountName ? _accountNamePosition : AccountNamePosition.HIDDEN;
|
||||
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));
|
||||
|
||||
|
@ -467,7 +469,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
case SINGLETAP:
|
||||
if (!handled) {
|
||||
_view.onEntryCopy(entry);
|
||||
entryHolder.animateCopyText();
|
||||
entryHolder.animateCopyText(_viewMode != ViewMode.TILES);
|
||||
_clickedEntry = null;
|
||||
}
|
||||
break;
|
||||
|
@ -476,7 +478,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
|
||||
if(entry == _clickedEntry) {
|
||||
_view.onEntryCopy(entry);
|
||||
entryHolder.animateCopyText();
|
||||
entryHolder.animateCopyText(_viewMode != ViewMode.TILES);
|
||||
_clickedEntry = null;
|
||||
} else {
|
||||
_clickedEntry = entry;
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.amulyakhare.textdrawable.TextDrawable;
|
|||
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 class EntryHolder extends RecyclerView.ViewHolder {
|
|||
});
|
||||
}
|
||||
|
||||
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 class EntryHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
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 class EntryHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
private void setAccountNameLayout(AccountNamePosition accountNamePosition) {
|
||||
if (_viewMode == ViewMode.TILES) {
|
||||
return;
|
||||
}
|
||||
|
||||
RelativeLayout.LayoutParams profileNameLayoutParams;
|
||||
RelativeLayout.LayoutParams copiedLayoutParams;
|
||||
switch (accountNamePosition) {
|
||||
|
@ -367,7 +374,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
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 class EntryHolder extends RecyclerView.ViewHolder {
|
|||
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) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import androidx.annotation.NonNull;
|
|||
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<VaultEntry> _preloadSizeProvider;
|
||||
private TotpProgressBar _progressBar;
|
||||
private boolean _showProgress;
|
||||
|
@ -122,7 +124,17 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
RecyclerViewPreloader<VaultEntry> 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 class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
_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) {
|
||||
|
@ -536,18 +555,28 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
@ -653,6 +682,30 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
}
|
||||
}
|
||||
|
||||
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<VaultEntry> {
|
||||
@NonNull
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.beemdevelopment.aegis.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CollectionUtils {
|
||||
|
||||
public static <T> void move(List<T> list, int fromIndex, int toIndex) {
|
||||
if (fromIndex == toIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
T item = list.remove(fromIndex);
|
||||
list.add(toIndex, item);
|
||||
}
|
||||
}
|
|
@ -64,34 +64,31 @@ public class UUIDMap <T extends UUIDMap.Value> implements Iterable<T>, Serializa
|
|||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws AssertionError if no map value exists with the UUID of the given entries.
|
||||
*/
|
||||
public void swap(T value1, T value2) {
|
||||
boolean found1 = false;
|
||||
boolean found2 = false;
|
||||
List<T> values = new ArrayList<>();
|
||||
* Moves value1 to the position of value2.
|
||||
*/
|
||||
public void move(T value1, T value2) {
|
||||
List<T> values = new ArrayList<>(_map.values());
|
||||
|
||||
for (T value : _map.values()) {
|
||||
int vi1 = -1, vi2 = -1;
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
T value = values.get(i);
|
||||
if (value.getUUID().equals(value1.getUUID())) {
|
||||
values.add(value2);
|
||||
found1 = true;
|
||||
} else if (value.getUUID().equals(value2.getUUID())) {
|
||||
values.add(value1);
|
||||
found2 = true;
|
||||
} else {
|
||||
values.add(value);
|
||||
vi1 = i;
|
||||
}
|
||||
if (value.getUUID().equals(value2.getUUID())) {
|
||||
vi2 = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found1) {
|
||||
if (vi1 < 0) {
|
||||
throw new AssertionError(String.format("No value found for value1 with UUID: %s", value1.getUUID()));
|
||||
}
|
||||
if (!found2) {
|
||||
if (vi2 < 0) {
|
||||
throw new AssertionError(String.format("No value found for value2 with UUID: %s", value2.getUUID()));
|
||||
}
|
||||
|
||||
CollectionUtils.move(values, vi1, vi2);
|
||||
|
||||
_map.clear();
|
||||
for (T value : values) {
|
||||
_map.put(value.getUUID(), value);
|
||||
|
|
|
@ -239,8 +239,11 @@ public class VaultRepository {
|
|||
return _vault.getEntries().replace(entry);
|
||||
}
|
||||
|
||||
public void swapEntries(VaultEntry entry1, VaultEntry entry2) {
|
||||
_vault.getEntries().swap(entry1, entry2);
|
||||
/**
|
||||
* Moves entry1 to the position of entry2.
|
||||
*/
|
||||
public void moveEntry(VaultEntry entry1, VaultEntry entry2) {
|
||||
_vault.getEntries().move(entry1, entry2);
|
||||
}
|
||||
|
||||
public boolean isEntryDuplicate(VaultEntry entry) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue