Improve usability of drag-and-drop feature

This commit is contained in:
Connor Lim 2020-08-07 00:20:38 +08:00
parent c73c29d2ec
commit 5886462d2c
8 changed files with 177 additions and 43 deletions

View file

@ -43,7 +43,7 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
int position = viewHolder.getAdapterPosition();
EntryAdapter adapter = (EntryAdapter)recyclerView.getAdapter();
if (adapter.getEntryAt(position) != _selectedEntry)
if (adapter.getEntryAt(position) != _selectedEntry || !isLongPressDragEnabled())
{
dragFlags = 0;
}

View file

@ -2,6 +2,7 @@ package com.beemdevelopment.aegis.ui.views;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@ -49,6 +50,7 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
// keeps track of the viewholders that are currently bound
private List<EntryHolder> _holders;
private EntryHolder _dragHandleHolder; // holder with enabled drag handle
public EntryAdapter(EntryListView view) {
_entries = new ArrayList<>();
@ -386,7 +388,29 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
holder.setFocusedAndAnimate(true);
}
return _view.onLongEntryClick(_shownEntries.get(position));
boolean returnVal = _view.onLongEntryClick(_shownEntries.get(position));
boolean dragEnabled = _selectedEntries.size() == 0
|| _selectedEntries.size() == 1 && _selectedEntries.get(0) == holder.getEntry();
if (dragEnabled && isDragAndDropAllowed()) {
_view.startDrag(_dragHandleHolder);
}
return returnVal;
}
});
holder.itemView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// Start drag if this is the only item selected
if (event.getActionMasked() == MotionEvent.ACTION_MOVE
&& _selectedEntries.size() == 1
&& _selectedEntries.get(0) == holder.getEntry()
&& isDragAndDropAllowed()) {
_view.startDrag(_dragHandleHolder);
return true;
}
return false;
}
});
holder.setOnRefreshClickListener(new View.OnClickListener() {
@ -508,8 +532,33 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
_focusedEntry = null;
}
private void updateDraggableStatus() {
if (!isDragAndDropAllowed()) {
return;
}
if (_selectedEntries.size() == 1 && _dragHandleHolder == null) {
// 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++) {
if (_holders.get(i).getEntry() == _selectedEntries.get(0)) {
_dragHandleHolder = _holders.get(i);
_dragHandleHolder.setShowDragHandle(true);
_view.setSelectedEntry(_selectedEntries.get(0));
return;
}
}
} else if (_dragHandleHolder != null) {
// Disable dragging if necessary when more/less than 1 selected entry
_dragHandleHolder.setShowDragHandle(false);
_dragHandleHolder = null;
_view.setSelectedEntry(null);
}
}
public void removeSelectedEntry(VaultEntry entry) {
_selectedEntries.remove(entry);
updateDraggableStatus();
}
public void addSelectedEntry(VaultEntry entry) {
@ -518,6 +567,7 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
}
_selectedEntries.add(entry);
updateDraggableStatus();
}
public void deselectAllEntries() {
@ -531,6 +581,8 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
}
_selectedEntries.clear();
updateDraggableStatus();
}
public boolean isDragAndDropAllowed() {

View file

@ -39,6 +39,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
private VaultEntry _entry;
private ImageView _buttonRefresh;
private RelativeLayout _description;
private ImageView _dragHandle;
private final ImageView _selected;
private final Handler _selectedHandler;
@ -69,6 +70,8 @@ public class EntryHolder extends RecyclerView.ViewHolder {
_profileDrawable = view.findViewById(R.id.ivTextDrawable);
_buttonRefresh = view.findViewById(R.id.buttonRefresh);
_selected = view.findViewById(R.id.ivSelected);
_dragHandle = view.findViewById(R.id.drag_handle);
_selectedHandler = new Handler();
_animationHandler = new Handler();
@ -158,6 +161,14 @@ public class EntryHolder extends RecyclerView.ViewHolder {
_buttonRefresh.setOnClickListener(listener);
}
public void setShowDragHandle(boolean showDragHandle) {
if (showDragHandle) {
_dragHandle.setVisibility(View.VISIBLE);
} else {
_dragHandle.setVisibility(View.INVISIBLE);
}
}
public void setShowProgress(boolean showProgress) {
if (_entry.getInfo() instanceof HotpInfo) {
showProgress = false;

View file

@ -42,6 +42,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
private EntryAdapter _adapter;
private Listener _listener;
private SimpleItemTouchHelperCallback _touchCallback;
private ItemTouchHelper _touchHelper;
private RecyclerView _recyclerView;
private RecyclerView.ItemDecoration _dividerDecoration;
@ -90,8 +91,8 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
LinearLayoutManager layoutManager = new LinearLayoutManager(view.getContext());
_recyclerView.setLayoutManager(layoutManager);
_touchCallback = new SimpleItemTouchHelperCallback(_adapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(_touchCallback);
touchHelper.attachToRecyclerView(_recyclerView);
_touchHelper = new ItemTouchHelper(_touchCallback);
_touchHelper.attachToRecyclerView(_recyclerView);
_recyclerView.setAdapter(_adapter);
int resId = R.anim.layout_animation_fall_down;
@ -167,12 +168,20 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
_touchCallback.setIsLongPressDragEnabled(_adapter.isDragAndDropAllowed());
}
public void setSelectedEntry(VaultEntry entry) {
_touchCallback.setSelectedEntry(entry);
}
public void setViewMode(ViewMode mode) {
_viewMode = mode;
updateDividerDecoration();
_adapter.setViewMode(_viewMode);
}
public void startDrag(RecyclerView.ViewHolder viewHolder) {
_touchHelper.startDrag(viewHolder);
}
public void refresh(boolean hard) {
if (_showProgress) {
_progressBar.restart();

View file

@ -0,0 +1,5 @@
<vector android:height="32dp" android:tint="?attr/colorControlNormal"
android:viewportHeight="24" android:viewportWidth="24"
android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
</vector>

View file

@ -129,20 +129,39 @@
android:textStyle="normal|bold"/>
</RelativeLayout>
<ImageView
android:id="@+id/buttonRefresh"
android:visibility="gone"
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_refresh_black_24dp"
android:tint="?attr/iconColorPrimary"
android:background="?android:attr/selectableItemBackground" />
android:layout_height="match_parent">
<ImageView
android:id="@+id/buttonRefresh"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginEnd="4dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_refresh_black_24dp"
android:tint="?attr/iconColorPrimary"
android:background="?android:attr/selectableItemBackground" />
<ImageView
android:id="@+id/drag_handle"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="-12dp"
android:visibility="invisible"
android:scaleType="fitXY"
android:src="@drawable/ic_baseline_menu_black_32" />
</LinearLayout>
</LinearLayout>
<LinearLayout

View file

@ -128,20 +128,39 @@
android:textStyle="normal|bold"/>
</RelativeLayout>
<ImageView
android:id="@+id/buttonRefresh"
android:visibility="gone"
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_refresh_black_24dp"
android:tint="?attr/iconColorPrimary"
android:background="?android:attr/selectableItemBackground" />
android:layout_height="match_parent">
<ImageView
android:id="@+id/buttonRefresh"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="0dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_refresh_black_24dp"
android:tint="?attr/iconColorPrimary"
android:background="?android:attr/selectableItemBackground" />
<ImageView
android:id="@+id/drag_handle"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="-12dp"
android:visibility="invisible"
android:scaleType="fitXY"
android:src="@drawable/ic_baseline_menu_black_32" />
</LinearLayout>
</LinearLayout>
<LinearLayout

View file

@ -127,20 +127,39 @@
android:textStyle="normal|bold"/>
</RelativeLayout>
<ImageView
android:id="@+id/buttonRefresh"
android:visibility="gone"
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_refresh_black_24dp"
android:tint="?attr/iconColorPrimary"
android:background="?android:attr/selectableItemBackground" />
android:layout_height="match_parent">
<ImageView
android:id="@+id/buttonRefresh"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="0dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_refresh_black_24dp"
android:tint="?attr/iconColorPrimary"
android:background="?android:attr/selectableItemBackground" />
<ImageView
android:id="@+id/drag_handle"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="-12dp"
android:visibility="invisible"
android:scaleType="fitXY"
android:src="@drawable/ic_baseline_menu_black_32" />
</LinearLayout>
</LinearLayout>
<LinearLayout