Feature: Add drag-and-drop reordering for checklist items
Users can now reorder checklist items by dragging them up or down using the drag handle icon (6-dot pattern) on each item. Changes: - Added ic_drag_handle.xml drawable with 6-dot pattern icon - Updated item_checklist_row.xml to include drag handle ImageButton - Modified ChecklistAdapter to support moveItem() operation - Added ItemTouchHelper in NoteEditorFragment for drag-and-drop functionality - Items reorder smoothly and changes are auto-saved
This commit is contained in:
parent
30bfe441f8
commit
342262e892
|
|
@ -23,6 +23,7 @@ public class ChecklistAdapter extends RecyclerView.Adapter<ChecklistAdapter.Chec
|
||||||
void onTextChange(ChecklistItem item, String text);
|
void onTextChange(ChecklistItem item, String text);
|
||||||
void onCheckedChange(ChecklistItem item, boolean checked);
|
void onCheckedChange(ChecklistItem item, boolean checked);
|
||||||
void onDeleteClick(int position, ChecklistItem item);
|
void onDeleteClick(int position, ChecklistItem item);
|
||||||
|
void onMoveItems(int fromPosition, int toPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChecklistAdapter(OnItemChangeListener listener) {
|
public ChecklistAdapter(OnItemChangeListener listener) {
|
||||||
|
|
@ -88,13 +89,34 @@ public class ChecklistAdapter extends RecyclerView.Adapter<ChecklistAdapter.Chec
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move item from one position to another
|
||||||
|
public void moveItem(int fromPosition, int toPosition) {
|
||||||
|
if (fromPosition < toPosition) {
|
||||||
|
for (int i = fromPosition; i < toPosition; i++) {
|
||||||
|
ChecklistItem temp = items.get(i);
|
||||||
|
items.set(i, items.get(i + 1));
|
||||||
|
items.set(i + 1, temp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = fromPosition; i > toPosition; i--) {
|
||||||
|
ChecklistItem temp = items.get(i);
|
||||||
|
items.set(i, items.get(i - 1));
|
||||||
|
items.set(i - 1, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyItemMoved(fromPosition, toPosition);
|
||||||
|
}
|
||||||
|
|
||||||
static class ChecklistViewHolder extends RecyclerView.ViewHolder {
|
static class ChecklistViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ImageButton dragHandle;
|
||||||
CheckBox checkBox;
|
CheckBox checkBox;
|
||||||
EditText editText;
|
EditText editText;
|
||||||
ImageButton deleteButton;
|
ImageButton deleteButton;
|
||||||
|
|
||||||
public ChecklistViewHolder(@NonNull View itemView) {
|
public ChecklistViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
dragHandle = itemView.findViewById(R.id.drag_handle);
|
||||||
checkBox = itemView.findViewById(R.id.check_box);
|
checkBox = itemView.findViewById(R.id.check_box);
|
||||||
editText = itemView.findViewById(R.id.item_text);
|
editText = itemView.findViewById(R.id.item_text);
|
||||||
deleteButton = itemView.findViewById(R.id.delete_button);
|
deleteButton = itemView.findViewById(R.id.delete_button);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import android.widget.Toast;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
|
@ -175,12 +176,39 @@ public class NoteEditorFragment extends Fragment {
|
||||||
updateProgress();
|
updateProgress();
|
||||||
saveNoteImmediately();
|
saveNoteImmediately();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMoveItems(int fromPosition, int toPosition) {
|
||||||
|
scheduleSave();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
checklistAdapter.setItems(note.getItems());
|
checklistAdapter.setItems(note.getItems());
|
||||||
checklistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
checklistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||||
checklistRecyclerView.setAdapter(checklistAdapter);
|
checklistRecyclerView.setAdapter(checklistAdapter);
|
||||||
|
|
||||||
|
// Add drag-and-drop support
|
||||||
|
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(
|
||||||
|
new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0) {
|
||||||
|
@Override
|
||||||
|
public boolean onMove(@NonNull RecyclerView recyclerView,
|
||||||
|
@NonNull RecyclerView.ViewHolder viewHolder,
|
||||||
|
@NonNull RecyclerView.ViewHolder target) {
|
||||||
|
int fromPosition = viewHolder.getAdapterPosition();
|
||||||
|
int toPosition = target.getAdapterPosition();
|
||||||
|
|
||||||
|
checklistAdapter.moveItem(fromPosition, toPosition);
|
||||||
|
scheduleSave();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
itemTouchHelper.attachToRecyclerView(checklistRecyclerView);
|
||||||
|
|
||||||
addImageButton.setOnClickListener(v -> {
|
addImageButton.setOnClickListener(v -> {
|
||||||
ChecklistItem newItem = new ChecklistItem("");
|
ChecklistItem newItem = new ChecklistItem("");
|
||||||
note.getItems().add(newItem);
|
note.getItems().add(newItem);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<!-- Top row of dots -->
|
||||||
|
<path
|
||||||
|
android:pathData="M9,3C10.105,3 11,3.895 11,5C11,6.105 10.105,7 9,7C7.895,7 7,6.105 7,5C7,3.895 7.895,3 9,3Z"
|
||||||
|
android:fillColor="@android:color/darker_gray"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M15,3C16.105,3 17,3.895 17,5C17,6.105 16.105,7 15,7C13.895,7 13,6.105 13,5C13,3.895 13.895,3 15,3Z"
|
||||||
|
android:fillColor="@android:color/darker_gray"/>
|
||||||
|
|
||||||
|
<!-- Middle row of dots -->
|
||||||
|
<path
|
||||||
|
android:pathData="M9,12C10.105,12 11,12.895 11,14C11,15.105 10.105,16 9,16C7.895,16 7,15.105 7,14C7,12.895 7.895,12 9,12Z"
|
||||||
|
android:fillColor="@android:color/darker_gray"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M15,12C16.105,12 17,12.895 17,14C17,15.105 16.105,16 15,16C13.895,16 13,15.105 13,14C13,12.895 13.895,12 15,12Z"
|
||||||
|
android:fillColor="@android:color/darker_gray"/>
|
||||||
|
|
||||||
|
<!-- Bottom row of dots -->
|
||||||
|
<path
|
||||||
|
android:pathData="M9,21C10.105,21 11,21.895 11,23C11,24.105 10.105,25 9,25C7.895,25 7,24.105 7,23C7,21.895 7.895,21 9,21Z"
|
||||||
|
android:fillColor="@android:color/darker_gray"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M15,21C16.105,21 17,21.895 17,23C17,24.105 16.105,25 15,25C13.895,25 13,24.105 13,23C13,21.895 13.895,21 15,21Z"
|
||||||
|
android:fillColor="@android:color/darker_gray"/>
|
||||||
|
|
||||||
|
</vector>
|
||||||
|
|
@ -1,16 +1,27 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/item_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingVertical="4dp">
|
android:paddingVertical="4dp">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/drag_handle"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_drag_handle"
|
||||||
|
app:tint="@color/text_secondary" />
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/check_box"
|
android:id="@+id/check_box"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical" />
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="4dp" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/item_text"
|
android:id="@+id/item_text"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue