]> git.ktnx.net Git - mobile-ledger.git/commitdiff
implement swipe-remove and drag-move in template details
authorDamyan Ivanov <dam+mobileledger@ktnx.net>
Tue, 16 Feb 2021 20:15:40 +0000 (22:15 +0200)
committerDamyan Ivanov <dam+mobileledger@ktnx.net>
Thu, 18 Feb 2021 07:19:43 +0000 (07:19 +0000)
app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsAdapter.java
app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsFragment.java
app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsViewModel.java
app/src/main/res/layout/template_details_account.xml

index 1d79120bad2716d96627441328361112628e8ec5..c7e59c3d43ac2b3b3d5990e644741ceefbde4969 100644 (file)
@@ -20,6 +20,7 @@ package net.ktnx.mobileledger.ui.templates;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.view.LayoutInflater;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
@@ -28,6 +29,7 @@ import androidx.annotation.NonNull;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.recyclerview.widget.AsyncListDiffer;
 import androidx.recyclerview.widget.DiffUtil;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.recyclerview.widget.AsyncListDiffer;
 import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.ItemTouchHelper;
 import androidx.recyclerview.widget.RecyclerView;
 
 import net.ktnx.mobileledger.R;
 import androidx.recyclerview.widget.RecyclerView;
 
 import net.ktnx.mobileledger.R;
@@ -54,8 +56,11 @@ import java.util.regex.Pattern;
 class TemplateDetailsAdapter extends RecyclerView.Adapter<TemplateDetailsAdapter.ViewHolder> {
     private static final String D_TEMPLATE_UI = "template-ui";
     private final AsyncListDiffer<TemplateDetailsItem> differ;
 class TemplateDetailsAdapter extends RecyclerView.Adapter<TemplateDetailsAdapter.ViewHolder> {
     private static final String D_TEMPLATE_UI = "template-ui";
     private final AsyncListDiffer<TemplateDetailsItem> differ;
-    public TemplateDetailsAdapter() {
+    private final TemplateDetailsViewModel mModel;
+    private final ItemTouchHelper itemTouchHelper;
+    public TemplateDetailsAdapter(TemplateDetailsViewModel model) {
         super();
         super();
+        mModel = model;
         setHasStableIds(true);
         differ = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<TemplateDetailsItem>() {
             @Override
         setHasStableIds(true);
         differ = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<TemplateDetailsItem>() {
             @Override
@@ -90,6 +95,97 @@ class TemplateDetailsAdapter extends RecyclerView.Adapter<TemplateDetailsAdapter
                 }
             }
         });
                 }
             }
         });
+        itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
+            @Override
+            public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
+                return 0.1f;
+            }
+            @Override
+            public boolean isLongPressDragEnabled() {
+                return false;
+            }
+            @Override
+            public RecyclerView.ViewHolder chooseDropTarget(
+                    @NonNull RecyclerView.ViewHolder selected,
+                    @NonNull List<RecyclerView.ViewHolder> dropTargets, int curX, int curY) {
+                RecyclerView.ViewHolder best = null;
+                int bestDistance = 0;
+                for (RecyclerView.ViewHolder v : dropTargets) {
+                    if (v == selected)
+                        continue;
+
+                    final int viewTop = v.itemView.getTop();
+                    int distance = Math.abs(viewTop - curY);
+                    if (best == null) {
+                        best = v;
+                        bestDistance = distance;
+                    }
+                    else {
+                        if (distance < bestDistance) {
+                            bestDistance = distance;
+                            best = v;
+                        }
+                    }
+                }
+
+                Logger.debug("dnd", "Best target is " + best);
+                return best;
+            }
+            @Override
+            public boolean canDropOver(@NonNull RecyclerView recyclerView,
+                                       @NonNull RecyclerView.ViewHolder current,
+                                       @NonNull RecyclerView.ViewHolder target) {
+                final int adapterPosition = target.getAdapterPosition();
+
+                // first item is immovable
+                if (adapterPosition == 0)
+                    return false;
+
+                return super.canDropOver(recyclerView, current, target);
+            }
+            @Override
+            public int getMovementFlags(@NonNull RecyclerView recyclerView,
+                                        @NonNull RecyclerView.ViewHolder viewHolder) {
+                int flags = 0;
+                // the top item (transaction params) is always there
+                final int adapterPosition = viewHolder.getAdapterPosition();
+                if (adapterPosition > 0)
+                    flags |= makeFlag(ItemTouchHelper.ACTION_STATE_DRAG,
+                            ItemTouchHelper.UP | ItemTouchHelper.DOWN) |
+                             makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE,
+                                     ItemTouchHelper.START | ItemTouchHelper.END);
+
+                return flags;
+            }
+            @Override
+            public boolean onMove(@NonNull RecyclerView recyclerView,
+                                  @NonNull RecyclerView.ViewHolder viewHolder,
+                                  @NonNull RecyclerView.ViewHolder target) {
+
+                final int fromPosition = viewHolder.getAdapterPosition();
+                final int toPosition = target.getAdapterPosition();
+                mModel.moveItem(fromPosition, toPosition);
+
+                return true;
+            }
+            @Override
+            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
+                int pos = viewHolder.getAdapterPosition();
+                mModel.removeItem(pos);
+            }
+        });
+    }
+    @Override
+    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
+        super.onAttachedToRecyclerView(recyclerView);
+
+        itemTouchHelper.attachToRecyclerView(recyclerView);
+    }
+    @Override
+    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
+        super.onDetachedFromRecyclerView(recyclerView);
+
+        itemTouchHelper.attachToRecyclerView(null);
     }
     @Override
     public long getItemId(int position) {
     }
     @Override
     public long getItemId(int position) {
@@ -560,6 +656,12 @@ class TemplateDetailsAdapter extends RecyclerView.Adapter<TemplateDetailsAdapter
             };
             b.templateDetailsNegateAmountLabel.setOnClickListener(negLabelClickListener);
             b.templateDetailsNegateAmountText.setOnClickListener(negLabelClickListener);
             };
             b.templateDetailsNegateAmountLabel.setOnClickListener(negLabelClickListener);
             b.templateDetailsNegateAmountText.setOnClickListener(negLabelClickListener);
+            b.patternAccountLabel.setOnTouchListener((v, event) -> {
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                    itemTouchHelper.startDrag(this);
+                }
+                return false;
+            });
         }
         @Override
         void bind(TemplateDetailsItem item) {
         }
         @Override
         void bind(TemplateDetailsItem item) {
index d8d1bb907195d71fb3016b9716e198ab5c22846c..50088be306dd7bdd3f83c779d1e1d71879f29786 100644 (file)
@@ -117,7 +117,7 @@ public class TemplateDetailsFragment extends QRScanCapableFragment {
         }
 
 
         }
 
 
-        TemplateDetailsAdapter adapter = new TemplateDetailsAdapter();
+        TemplateDetailsAdapter adapter = new TemplateDetailsAdapter(mViewModel);
         b.patternDetailsRecyclerView.setAdapter(adapter);
         mViewModel.getItems(mPatternId)
                   .observe(getViewLifecycleOwner(), adapter::setItems);
         b.patternDetailsRecyclerView.setAdapter(adapter);
         mViewModel.getItems(mPatternId)
                   .observe(getViewLifecycleOwner(), adapter::setItems);
index 40647875199f688c77a1a4602382318456815092..5132af264025056cb95a9ab9fde9271aadeea702 100644 (file)
@@ -184,4 +184,16 @@ public class TemplateDetailsViewModel extends ViewModel {
             taDAO.finishSave(mPatternId);
         });
     }
             taDAO.finishSave(mPatternId);
         });
     }
+    public void moveItem(int sourcePos, int targetPos) {
+        ArrayList<TemplateDetailsItem> newList = new ArrayList<>(items.getValue());
+        TemplateDetailsItem item = newList.remove(sourcePos);
+        newList.add(targetPos, item);
+        items.setValue(newList);
+    }
+    public void removeItem(int position) {
+        ArrayList<TemplateDetailsItem> newList = new ArrayList<>(items.getValue());
+        newList.remove(position);
+        checkItemConsistency(newList);
+        items.setValue(newList);
+    }
 }
\ No newline at end of file
 }
\ No newline at end of file
index c8c5285f02b7cd60983c7ab5a1c5e7d5e8cd4212..a0cae77467a260268830fc13cdac16202087b154 100644 (file)
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:animateLayoutChanges="true"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:animateLayoutChanges="true"
-    android:paddingHorizontal="@dimen/text_margin"
+    android:padding="@dimen/text_margin"
     >
     <TextView
         android:id="@+id/pattern_account_label"
     >
     <TextView
         android:id="@+id/pattern_account_label"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
         android:gravity="end"
         android:gravity="end"
-        android:paddingTop="@dimen/text_margin"
         android:text="@string/template_details_account_row_label"
         android:textAppearance="?attr/textAppearanceListItem"
         app:drawableBottomCompat="@drawable/dashed_border_8dp"
         android:text="@string/template_details_account_row_label"
         android:textAppearance="?attr/textAppearanceListItem"
         app:drawableBottomCompat="@drawable/dashed_border_8dp"
+        app:drawableStartCompat="@drawable/ic_baseline_drag_handle_24"
+        app:layout_constraintBottom_toTopOf="@id/template_account_name_source_label"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="1.0"
+        app:layout_constraintTop_toTopOf="parent"
         />
     <TextView
         android:id="@+id/template_account_name_source_label"
         />
     <TextView
         android:id="@+id/template_account_name_source_label"