mirror of https://github.com/tasks/tasks
Convert task list recycler adapters to Kotlin
parent
34119391fc
commit
0f55cacf10
@ -1,41 +0,0 @@
|
||||
package org.tasks.tasklist;
|
||||
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import java.util.List;
|
||||
import org.tasks.data.TaskContainer;
|
||||
|
||||
class DiffCallback extends DiffUtil.Callback {
|
||||
|
||||
private final List<TaskContainer> oldList;
|
||||
private final List<TaskContainer> newList;
|
||||
@Deprecated private final TaskAdapter adapter;
|
||||
|
||||
DiffCallback(List<TaskContainer> oldList, List<TaskContainer> newList, TaskAdapter adapter) {
|
||||
this.oldList = oldList;
|
||||
this.newList = newList;
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOldListSize() {
|
||||
return oldList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewListSize() {
|
||||
return newList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
return oldList.get(oldItemPosition).getId() == newList.get(newItemPosition).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
TaskContainer oldItem = oldList.get(oldItemPosition);
|
||||
TaskContainer newItem = newList.get(newItemPosition);
|
||||
return oldItem.equals(newItem) && oldItem.getIndent() == adapter.getIndent(newItem);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.tasks.tasklist
|
||||
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.todoroo.astrid.adapter.TaskAdapter
|
||||
import org.tasks.data.TaskContainer
|
||||
|
||||
internal class DiffCallback(private val old: List<TaskContainer>, private val new: List<TaskContainer>, @Deprecated("") private val adapter: TaskAdapter) : DiffUtil.Callback() {
|
||||
|
||||
override fun getOldListSize() = old.size
|
||||
|
||||
override fun getNewListSize() = new.size
|
||||
|
||||
override fun areItemsTheSame(oldPosition: Int, newPosition: Int): Boolean {
|
||||
return old[oldPosition].id == new[newPosition].id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldPosition: Int, newPosition: Int): Boolean {
|
||||
val oldItem = old[oldPosition]
|
||||
val newItem = new[newPosition]
|
||||
return oldItem == newItem && oldItem.getIndent() == adapter.getIndent(newItem)
|
||||
}
|
||||
}
|
@ -1,271 +0,0 @@
|
||||
package org.tasks.tasklist;
|
||||
|
||||
import static androidx.recyclerview.widget.ItemTouchHelper.DOWN;
|
||||
import static androidx.recyclerview.widget.ItemTouchHelper.LEFT;
|
||||
import static androidx.recyclerview.widget.ItemTouchHelper.RIGHT;
|
||||
import static androidx.recyclerview.widget.ItemTouchHelper.UP;
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.assertMainThread;
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.assertNotMainThread;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Parcelable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.DiffUtil.DiffResult;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.ListUpdateCallback;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.todoroo.astrid.activity.TaskListFragment;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.utility.Flags;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import org.tasks.data.TaskContainer;
|
||||
|
||||
public class DragAndDropRecyclerAdapter extends TaskListRecyclerAdapter {
|
||||
|
||||
private static final int LONG_LIST_SIZE = 500;
|
||||
|
||||
private final TaskAdapter adapter;
|
||||
private final TaskListFragment taskList;
|
||||
private final RecyclerView recyclerView;
|
||||
private List<TaskContainer> list;
|
||||
private final PublishSubject<List<TaskContainer>> publishSubject = PublishSubject.create();
|
||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||
private final Queue<Pair<List<TaskContainer>, DiffResult>> updates = new LinkedList<>();
|
||||
private boolean dragging;
|
||||
|
||||
public DragAndDropRecyclerAdapter(
|
||||
TaskAdapter adapter,
|
||||
RecyclerView recyclerView,
|
||||
ViewHolderFactory viewHolderFactory,
|
||||
TaskListFragment taskList,
|
||||
List<TaskContainer> list,
|
||||
TaskDao taskDao) {
|
||||
super(adapter, viewHolderFactory, taskList, taskDao);
|
||||
|
||||
this.adapter = adapter;
|
||||
this.recyclerView = recyclerView;
|
||||
this.taskList = taskList;
|
||||
this.list = list;
|
||||
new ItemTouchHelper(new ItemTouchHelperCallback()).attachToRecyclerView(recyclerView);
|
||||
Pair<List<TaskContainer>, DiffResult> initial = Pair.create(list, null);
|
||||
disposables.add(
|
||||
publishSubject
|
||||
.observeOn(Schedulers.computation())
|
||||
.scan(initial, this::calculateDiff)
|
||||
.skip(1)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::applyDiff));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean dragAndDropEnabled() {
|
||||
return adapter.supportsParentingOrManualSort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskContainer getItem(int position) {
|
||||
return list.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitList(List<TaskContainer> list) {
|
||||
publishSubject.onNext(list);
|
||||
}
|
||||
|
||||
private Pair<List<TaskContainer>, DiffResult> calculateDiff(
|
||||
Pair<List<TaskContainer>, DiffResult> last, List<TaskContainer> next) {
|
||||
assertNotMainThread();
|
||||
|
||||
DiffCallback cb = new DiffCallback(last.first, next, adapter);
|
||||
DiffResult result = DiffUtil.calculateDiff(cb, next.size() < LONG_LIST_SIZE);
|
||||
|
||||
return Pair.create(next, result);
|
||||
}
|
||||
|
||||
private void applyDiff(Pair<List<TaskContainer>, DiffResult> update) {
|
||||
assertMainThread();
|
||||
|
||||
updates.add(update);
|
||||
|
||||
if (!dragging) {
|
||||
drainQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private void drainQueue() {
|
||||
assertMainThread();
|
||||
|
||||
Parcelable recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();
|
||||
|
||||
Pair<List<TaskContainer>, DiffResult> update = updates.poll();
|
||||
while (update != null) {
|
||||
list = update.first;
|
||||
update.second.dispatchUpdatesTo((ListUpdateCallback) this);
|
||||
update = updates.poll();
|
||||
}
|
||||
|
||||
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||
disposables.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
private int from = -1;
|
||||
private int to = -1;
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||
taskList.startActionMode();
|
||||
((ViewHolder) viewHolder).setMoving(true);
|
||||
dragging = true;
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
updateIndents((ViewHolder) viewHolder, position, position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMovementFlags(
|
||||
@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
return adapter.supportsParentingOrManualSort() && adapter.getNumSelected() == 0
|
||||
? makeMovementFlags(UP | DOWN | LEFT | RIGHT, 0)
|
||||
: makeMovementFlags(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(
|
||||
@NonNull RecyclerView recyclerView,
|
||||
@NonNull RecyclerView.ViewHolder src,
|
||||
@NonNull RecyclerView.ViewHolder target) {
|
||||
taskList.finishActionMode();
|
||||
int fromPosition = src.getAdapterPosition();
|
||||
int toPosition = target.getAdapterPosition();
|
||||
ViewHolder source = (ViewHolder) src;
|
||||
if (!adapter.canMove(source.task, fromPosition, ((ViewHolder) target).task, toPosition)) {
|
||||
return false;
|
||||
}
|
||||
if (from == -1) {
|
||||
source.setSelected(false);
|
||||
from = fromPosition;
|
||||
}
|
||||
to = toPosition;
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
updateIndents(source, from, to);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateIndents(ViewHolder source, int from, int to) {
|
||||
TaskContainer task = source.task;
|
||||
source.setMinIndent(
|
||||
to == 0 || to == getItemCount() - 1
|
||||
? 0
|
||||
: adapter.minIndent(from <= to ? to + 1 : to, task));
|
||||
source.setMaxIndent(to == 0 ? 0 : adapter.maxIndent(from >= to ? to - 1 : to, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildDraw(
|
||||
@NonNull Canvas c,
|
||||
@NonNull RecyclerView recyclerView,
|
||||
@NonNull RecyclerView.ViewHolder viewHolder,
|
||||
float dX,
|
||||
float dY,
|
||||
int actionState,
|
||||
boolean isCurrentlyActive) {
|
||||
ViewHolder vh = (ViewHolder) viewHolder;
|
||||
TaskContainer task = vh.task;
|
||||
float shiftSize = vh.getShiftSize();
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||
int currentIndent = ((ViewHolder) viewHolder).getIndent();
|
||||
int maxIndent = vh.getMaxIndent();
|
||||
int minIndent = vh.getMinIndent();
|
||||
if (isCurrentlyActive) {
|
||||
float dxAdjusted;
|
||||
if (dX > 0) {
|
||||
dxAdjusted = Math.min(dX, (maxIndent - currentIndent) * shiftSize);
|
||||
} else {
|
||||
dxAdjusted = Math.max((currentIndent - minIndent) * -shiftSize, dX);
|
||||
}
|
||||
|
||||
int targetIndent = currentIndent + Float.valueOf(dxAdjusted / shiftSize).intValue();
|
||||
|
||||
if (targetIndent != task.getIndent()) {
|
||||
if (from == -1) {
|
||||
taskList.finishActionMode();
|
||||
vh.setSelected(false);
|
||||
}
|
||||
}
|
||||
if (targetIndent < minIndent) {
|
||||
task.setTargetIndent(minIndent);
|
||||
} else
|
||||
task.setTargetIndent(Math.min(targetIndent, maxIndent));
|
||||
}
|
||||
|
||||
dX = (task.getTargetIndent() - task.getIndent()) * shiftSize;
|
||||
}
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(
|
||||
@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
ViewHolder vh = (ViewHolder) viewHolder;
|
||||
vh.setMoving(false);
|
||||
dragging = false;
|
||||
drainQueue();
|
||||
if (taskList.isActionModeActive()) {
|
||||
toggle(vh);
|
||||
} else {
|
||||
TaskContainer task = vh.task;
|
||||
int targetIndent = task.getTargetIndent();
|
||||
if (from >= 0 && from != to) {
|
||||
if (from < to) {
|
||||
to++;
|
||||
}
|
||||
vh.task.setIndent(targetIndent);
|
||||
vh.setIndent(targetIndent);
|
||||
moved(from, to, targetIndent);
|
||||
} else if (task.getIndent() != targetIndent) {
|
||||
int position = vh.getAdapterPosition();
|
||||
vh.task.setIndent(targetIndent);
|
||||
vh.setIndent(targetIndent);
|
||||
moved(position, position, targetIndent);
|
||||
}
|
||||
}
|
||||
from = -1;
|
||||
to = -1;
|
||||
Flags.clear(Flags.TLFP_NO_INTERCEPT_TOUCH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void moved(int from, int to, int indent) {
|
||||
adapter.moved(from, to, indent);
|
||||
TaskContainer task = list.remove(from);
|
||||
list.add(from < to ? to - 1 : to, task);
|
||||
taskList.loadTaskListContent();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
package org.tasks.tasklist
|
||||
|
||||
import android.graphics.Canvas
|
||||
import androidx.core.util.Pair
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ListUpdateCallback
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.todoroo.andlib.utility.AndroidUtilities
|
||||
import com.todoroo.astrid.activity.TaskListFragment
|
||||
import com.todoroo.astrid.adapter.TaskAdapter
|
||||
import com.todoroo.astrid.dao.TaskDao
|
||||
import com.todoroo.astrid.utility.Flags
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import org.tasks.data.TaskContainer
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class DragAndDropRecyclerAdapter(
|
||||
private val adapter: TaskAdapter,
|
||||
private val recyclerView: RecyclerView,
|
||||
viewHolderFactory: ViewHolderFactory,
|
||||
private val taskList: TaskListFragment,
|
||||
private var list: MutableList<TaskContainer>,
|
||||
taskDao: TaskDao) : TaskListRecyclerAdapter(adapter, viewHolderFactory, taskList, taskDao) {
|
||||
private val publishSubject = PublishSubject.create<List<TaskContainer>>()
|
||||
private val disposables = CompositeDisposable()
|
||||
private val updates: Queue<Pair<MutableList<TaskContainer>, DiffUtil.DiffResult>> = LinkedList()
|
||||
private var dragging = false
|
||||
override fun dragAndDropEnabled() = adapter.supportsParentingOrManualSort()
|
||||
|
||||
override fun getItem(position: Int) = list[position]
|
||||
|
||||
override fun submitList(list: List<TaskContainer>) = publishSubject.onNext(list)
|
||||
|
||||
private fun calculateDiff(
|
||||
last: Pair<MutableList<TaskContainer>, DiffUtil.DiffResult>, next: MutableList<TaskContainer>): Pair<MutableList<TaskContainer>, DiffUtil.DiffResult> {
|
||||
AndroidUtilities.assertNotMainThread()
|
||||
val cb = DiffCallback(last.first, next, adapter)
|
||||
val result = DiffUtil.calculateDiff(cb, next.size < LONG_LIST_SIZE)
|
||||
return Pair.create(next, result)
|
||||
}
|
||||
|
||||
private fun applyDiff(update: Pair<MutableList<TaskContainer>, DiffUtil.DiffResult>) {
|
||||
AndroidUtilities.assertMainThread()
|
||||
updates.add(update)
|
||||
if (!dragging) {
|
||||
drainQueue()
|
||||
}
|
||||
}
|
||||
|
||||
private fun drainQueue() {
|
||||
AndroidUtilities.assertMainThread()
|
||||
val recyclerViewState = recyclerView.layoutManager!!.onSaveInstanceState()
|
||||
var update = updates.poll()
|
||||
while (update != null) {
|
||||
list = update.first!!
|
||||
update.second!!.dispatchUpdatesTo((this as ListUpdateCallback))
|
||||
update = updates.poll()
|
||||
}
|
||||
recyclerView.layoutManager!!.onRestoreInstanceState(recyclerViewState)
|
||||
}
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) = disposables.dispose()
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return list.size
|
||||
}
|
||||
|
||||
private inner class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
|
||||
private var from = -1
|
||||
private var to = -1
|
||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||
super.onSelectedChanged(viewHolder, actionState)
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||
taskList.startActionMode()
|
||||
(viewHolder as ViewHolder?)!!.isMoving = true
|
||||
dragging = true
|
||||
val position = viewHolder!!.adapterPosition
|
||||
updateIndents(viewHolder as ViewHolder?, position, position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) = if (adapter.supportsParentingOrManualSort() && adapter.numSelected == 0) {
|
||||
makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT, 0)
|
||||
} else {
|
||||
makeMovementFlags(0, 0)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
src: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder): Boolean {
|
||||
taskList.finishActionMode()
|
||||
val fromPosition = src.adapterPosition
|
||||
val toPosition = target.adapterPosition
|
||||
val source = src as ViewHolder
|
||||
if (!adapter.canMove(source.task, fromPosition, (target as ViewHolder).task, toPosition)) {
|
||||
return false
|
||||
}
|
||||
if (from == -1) {
|
||||
source.setSelected(false)
|
||||
from = fromPosition
|
||||
}
|
||||
to = toPosition
|
||||
notifyItemMoved(fromPosition, toPosition)
|
||||
updateIndents(source, from, to)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun updateIndents(source: ViewHolder?, from: Int, to: Int) {
|
||||
val task = source!!.task
|
||||
source.minIndent = if (to == 0 || to == itemCount - 1) 0 else adapter.minIndent(if (from <= to) to + 1 else to, task)
|
||||
source.maxIndent = if (to == 0) 0 else adapter.maxIndent(if (from >= to) to - 1 else to, task)
|
||||
}
|
||||
|
||||
override fun onChildDraw(
|
||||
c: Canvas,
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
dXOrig: Float,
|
||||
dY: Float,
|
||||
actionState: Int,
|
||||
isCurrentlyActive: Boolean) {
|
||||
var dX = dXOrig
|
||||
val vh = viewHolder as ViewHolder
|
||||
val task = vh.task
|
||||
val shiftSize = vh.shiftSize
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||
val currentIndent = viewHolder.indent
|
||||
val maxIndent = vh.maxIndent
|
||||
val minIndent = vh.minIndent
|
||||
if (isCurrentlyActive) {
|
||||
val dxAdjusted: Float = if (dX > 0) {
|
||||
min(dX, (maxIndent - currentIndent) * shiftSize)
|
||||
} else {
|
||||
max((currentIndent - minIndent) * -shiftSize, dX)
|
||||
}
|
||||
val targetIndent = currentIndent + java.lang.Float.valueOf(dxAdjusted / shiftSize).toInt()
|
||||
if (targetIndent != task.getIndent()) {
|
||||
if (from == -1) {
|
||||
taskList.finishActionMode()
|
||||
vh.setSelected(false)
|
||||
}
|
||||
}
|
||||
if (targetIndent < minIndent) {
|
||||
task.targetIndent = minIndent
|
||||
} else task.targetIndent = Math.min(targetIndent, maxIndent)
|
||||
}
|
||||
dX = (task.targetIndent - task.getIndent()) * shiftSize
|
||||
}
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||
}
|
||||
|
||||
override fun clearView(
|
||||
recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
val vh = viewHolder as ViewHolder
|
||||
vh.isMoving = false
|
||||
dragging = false
|
||||
drainQueue()
|
||||
if (taskList.isActionModeActive) {
|
||||
toggle(vh)
|
||||
} else {
|
||||
val task = vh.task
|
||||
val targetIndent = task.targetIndent
|
||||
if (from >= 0 && from != to) {
|
||||
if (from < to) {
|
||||
to++
|
||||
}
|
||||
vh.task.setIndent(targetIndent)
|
||||
vh.indent = targetIndent
|
||||
moved(from, to, targetIndent)
|
||||
} else if (task.getIndent() != targetIndent) {
|
||||
val position = vh.adapterPosition
|
||||
vh.task.setIndent(targetIndent)
|
||||
vh.indent = targetIndent
|
||||
moved(position, position, targetIndent)
|
||||
}
|
||||
}
|
||||
from = -1
|
||||
to = -1
|
||||
Flags.clear(Flags.TLFP_NO_INTERCEPT_TOUCH)
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
private fun moved(from: Int, to: Int, indent: Int) {
|
||||
adapter.moved(from, to, indent)
|
||||
val task: TaskContainer = list.removeAt(from)
|
||||
list.add(if (from < to) to - 1 else to, task)
|
||||
taskList.loadTaskListContent()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val LONG_LIST_SIZE = 500
|
||||
}
|
||||
|
||||
init {
|
||||
ItemTouchHelper(ItemTouchHelperCallback()).attachToRecyclerView(recyclerView)
|
||||
val initial = Pair.create<MutableList<TaskContainer>, DiffUtil.DiffResult>(list, null)
|
||||
disposables.add(
|
||||
publishSubject
|
||||
.observeOn(Schedulers.computation())
|
||||
.scan(initial, { last: Pair<MutableList<TaskContainer>, DiffUtil.DiffResult>, next: List<TaskContainer> ->
|
||||
calculateDiff(last, next.toMutableList())
|
||||
})
|
||||
.skip(1)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { update: Pair<MutableList<TaskContainer>, DiffUtil.DiffResult> -> applyDiff(update) })
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package org.tasks.tasklist;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import androidx.paging.AsyncPagedListDiffer;
|
||||
import androidx.paging.PagedList;
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.todoroo.astrid.activity.TaskListFragment;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import java.util.List;
|
||||
import org.tasks.data.TaskContainer;
|
||||
|
||||
public class PagedListRecyclerAdapter extends TaskListRecyclerAdapter {
|
||||
|
||||
private final RecyclerView recyclerView;
|
||||
private final AsyncPagedListDiffer<TaskContainer> differ;
|
||||
|
||||
public PagedListRecyclerAdapter(
|
||||
TaskAdapter adapter,
|
||||
RecyclerView recyclerView,
|
||||
ViewHolderFactory viewHolderFactory,
|
||||
TaskListFragment taskList,
|
||||
List<TaskContainer> list,
|
||||
TaskDao taskDao) {
|
||||
super(adapter, viewHolderFactory, taskList, taskDao);
|
||||
this.recyclerView = recyclerView;
|
||||
differ =
|
||||
new AsyncPagedListDiffer<>(
|
||||
this, new AsyncDifferConfig.Builder<>(new ItemCallback()).build());
|
||||
if (list instanceof PagedList) {
|
||||
differ.submitList((PagedList<TaskContainer>) list);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskContainer getItem(int position) {
|
||||
return differ.getItem(position);
|
||||
}
|
||||
|
||||
public void submitList(List<TaskContainer> list) {
|
||||
differ.submitList((PagedList<TaskContainer>) list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoved(int fromPosition, int toPosition) {
|
||||
Parcelable recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();
|
||||
|
||||
super.onMoved(fromPosition, toPosition);
|
||||
|
||||
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean dragAndDropEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return differ.getItemCount();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package org.tasks.tasklist
|
||||
|
||||
import androidx.paging.AsyncPagedListDiffer
|
||||
import androidx.paging.PagedList
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.todoroo.astrid.activity.TaskListFragment
|
||||
import com.todoroo.astrid.adapter.TaskAdapter
|
||||
import com.todoroo.astrid.dao.TaskDao
|
||||
import org.tasks.data.TaskContainer
|
||||
|
||||
class PagedListRecyclerAdapter(
|
||||
adapter: TaskAdapter,
|
||||
private val recyclerView: RecyclerView,
|
||||
viewHolderFactory: ViewHolderFactory,
|
||||
taskList: TaskListFragment,
|
||||
list: List<TaskContainer>,
|
||||
taskDao: TaskDao) : TaskListRecyclerAdapter(adapter, viewHolderFactory, taskList, taskDao) {
|
||||
|
||||
private val differ: AsyncPagedListDiffer<TaskContainer> =
|
||||
AsyncPagedListDiffer(this, AsyncDifferConfig.Builder(ItemCallback()).build())
|
||||
|
||||
override fun getItem(position: Int) = differ.getItem(position)!!
|
||||
|
||||
override fun submitList(list: List<TaskContainer>) = differ.submitList(list as PagedList<TaskContainer>)
|
||||
|
||||
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
||||
val recyclerViewState = recyclerView.layoutManager!!.onSaveInstanceState()
|
||||
super.onMoved(fromPosition, toPosition)
|
||||
recyclerView.layoutManager!!.onRestoreInstanceState(recyclerViewState)
|
||||
}
|
||||
|
||||
override fun dragAndDropEnabled() = false
|
||||
|
||||
override fun getItemCount() = differ.itemCount
|
||||
|
||||
init {
|
||||
if (list is PagedList<*>) {
|
||||
differ.submitList(list as PagedList<TaskContainer>?)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
package org.tasks.tasklist;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.recyclerview.widget.ListUpdateCallback;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.todoroo.astrid.activity.TaskListFragment;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.adapter.TaskAdapterDataSource;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
|
||||
import org.tasks.data.TaskContainer;
|
||||
import org.tasks.intents.TaskIntents;
|
||||
import org.tasks.tasklist.ViewHolder.ViewHolderCallbacks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
|
||||
implements ViewHolderCallbacks, ListUpdateCallback, TaskAdapterDataSource {
|
||||
|
||||
private final TaskAdapter adapter;
|
||||
private final TaskListFragment taskList;
|
||||
private final ViewHolderFactory viewHolderFactory;
|
||||
private final TaskDao taskDao;
|
||||
|
||||
TaskListRecyclerAdapter(
|
||||
TaskAdapter adapter,
|
||||
ViewHolderFactory viewHolderFactory,
|
||||
TaskListFragment taskList,
|
||||
TaskDao taskDao) {
|
||||
this.adapter = adapter;
|
||||
this.viewHolderFactory = viewHolderFactory;
|
||||
this.taskList = taskList;
|
||||
this.taskDao = taskDao;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return viewHolderFactory.newViewHolder(parent, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
TaskContainer task = getItem(position);
|
||||
if (task != null) {
|
||||
holder.bindView(task, taskList.getFilter());
|
||||
holder.setMoving(false);
|
||||
int indent = adapter.getIndent(task);
|
||||
task.setIndent(indent);
|
||||
holder.setIndent(indent);
|
||||
holder.setSelected(adapter.isSelected(task));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompletedTask(TaskContainer task, boolean newState) {
|
||||
adapter.onCompletedTask(task, newState);
|
||||
taskList.loadTaskListContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(ViewHolder viewHolder) {
|
||||
if (taskList.isActionModeActive()) {
|
||||
toggle(viewHolder);
|
||||
} else {
|
||||
taskList.onTaskListItemClicked(viewHolder.task.getTask());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(Filter filter) {
|
||||
if (!taskList.isActionModeActive()) {
|
||||
FragmentActivity context = taskList.getActivity();
|
||||
if (context != null) {
|
||||
context.startActivity(TaskIntents.getTaskListIntent(context, filter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongPress(ViewHolder viewHolder) {
|
||||
if (!dragAndDropEnabled()) {
|
||||
taskList.startActionMode();
|
||||
}
|
||||
if (taskList.isActionModeActive() && !viewHolder.isMoving()) {
|
||||
toggle(viewHolder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeDueDate(TaskContainer task) {
|
||||
taskList.showDateTimePicker(task);
|
||||
}
|
||||
|
||||
protected abstract boolean dragAndDropEnabled();
|
||||
|
||||
@Override
|
||||
public void toggleSubtasks(TaskContainer task, boolean collapsed) {
|
||||
taskDao.setCollapsed(task.getId(), collapsed);
|
||||
taskList.broadcastRefresh();
|
||||
}
|
||||
|
||||
void toggle(ViewHolder viewHolder) {
|
||||
adapter.toggleSelection(viewHolder.task);
|
||||
notifyItemChanged(viewHolder.getAdapterPosition());
|
||||
if (adapter.getSelected().isEmpty()) {
|
||||
taskList.finishActionMode();
|
||||
} else {
|
||||
taskList.updateModeTitle();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract TaskContainer getItem(int position);
|
||||
|
||||
public abstract void submitList(List<TaskContainer> list);
|
||||
|
||||
@Override
|
||||
public void onInserted(int position, int count) {
|
||||
notifyItemRangeInserted(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(int position, int count) {
|
||||
notifyItemRangeRemoved(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoved(int fromPosition, int toPosition) {
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(int position, int count, @Nullable Object payload) {
|
||||
notifyItemRangeChanged(position, count, payload);
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package org.tasks.tasklist
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.ListUpdateCallback
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.todoroo.astrid.activity.TaskListFragment
|
||||
import com.todoroo.astrid.adapter.TaskAdapter
|
||||
import com.todoroo.astrid.adapter.TaskAdapterDataSource
|
||||
import com.todoroo.astrid.api.Filter
|
||||
import com.todoroo.astrid.dao.TaskDao
|
||||
import org.tasks.data.TaskContainer
|
||||
import org.tasks.intents.TaskIntents
|
||||
import org.tasks.tasklist.ViewHolder.ViewHolderCallbacks
|
||||
|
||||
abstract class TaskListRecyclerAdapter internal constructor(
|
||||
private val adapter: TaskAdapter,
|
||||
private val viewHolderFactory: ViewHolderFactory,
|
||||
private val taskList: TaskListFragment,
|
||||
private val taskDao: TaskDao) : RecyclerView.Adapter<ViewHolder>(), ViewHolderCallbacks, ListUpdateCallback, TaskAdapterDataSource {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return viewHolderFactory.newViewHolder(parent, this)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val task = getItem(position)
|
||||
if (task != null) {
|
||||
holder.bindView(task, taskList.getFilter())
|
||||
holder.isMoving = false
|
||||
val indent = adapter.getIndent(task)
|
||||
task.setIndent(indent)
|
||||
holder.indent = indent
|
||||
holder.setSelected(adapter.isSelected(task))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCompletedTask(task: TaskContainer, newState: Boolean) {
|
||||
adapter.onCompletedTask(task, newState)
|
||||
taskList.loadTaskListContent()
|
||||
}
|
||||
|
||||
override fun onClick(viewHolder: ViewHolder) {
|
||||
if (taskList.isActionModeActive) {
|
||||
toggle(viewHolder)
|
||||
} else {
|
||||
taskList.onTaskListItemClicked(viewHolder.task.getTask())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(filter: Filter) {
|
||||
if (!taskList.isActionModeActive) {
|
||||
val context = taskList.activity
|
||||
context?.startActivity(TaskIntents.getTaskListIntent(context, filter))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLongPress(viewHolder: ViewHolder): Boolean {
|
||||
if (!dragAndDropEnabled()) {
|
||||
taskList.startActionMode()
|
||||
}
|
||||
if (taskList.isActionModeActive && !viewHolder.isMoving) {
|
||||
toggle(viewHolder)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onChangeDueDate(task: TaskContainer) {
|
||||
taskList.showDateTimePicker(task)
|
||||
}
|
||||
|
||||
override fun toggleSubtasks(task: TaskContainer, collapsed: Boolean) {
|
||||
taskDao.setCollapsed(task.id, collapsed)
|
||||
taskList.broadcastRefresh()
|
||||
}
|
||||
|
||||
fun toggle(viewHolder: ViewHolder) {
|
||||
adapter.toggleSelection(viewHolder.task)
|
||||
notifyItemChanged(viewHolder.adapterPosition)
|
||||
if (adapter.getSelected().isEmpty()) {
|
||||
taskList.finishActionMode()
|
||||
} else {
|
||||
taskList.updateModeTitle()
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun dragAndDropEnabled(): Boolean
|
||||
|
||||
abstract override fun getItem(position: Int): TaskContainer
|
||||
|
||||
abstract fun submitList(list: List<TaskContainer>)
|
||||
|
||||
override fun onInserted(position: Int, count: Int) {
|
||||
notifyItemRangeInserted(position, count)
|
||||
}
|
||||
|
||||
override fun onRemoved(position: Int, count: Int) {
|
||||
notifyItemRangeRemoved(position, count)
|
||||
}
|
||||
|
||||
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
||||
notifyItemMoved(fromPosition, toPosition)
|
||||
}
|
||||
|
||||
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
||||
notifyItemRangeChanged(position, count, payload)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue