Convert task list recycler adapters to Kotlin

pull/996/head
Alex Baker 5 years ago
parent 34119391fc
commit 0f55cacf10

@ -41,7 +41,7 @@ class CaldavManualSortTaskAdapterTest : InjectingTestCase() {
private val dataSource = object : TaskAdapterDataSource { private val dataSource = object : TaskAdapterDataSource {
override fun getItem(position: Int) = tasks[position] override fun getItem(position: Int) = tasks[position]
override val itemCount get() = tasks.size override fun getItemCount() = tasks.size
} }
@Before @Before

@ -36,7 +36,7 @@ class CaldavTaskAdapterTest : InjectingTestCase() {
adapter.setDataSource(object : TaskAdapterDataSource { adapter.setDataSource(object : TaskAdapterDataSource {
override fun getItem(position: Int) = tasks[position] override fun getItem(position: Int) = tasks[position]
override val itemCount get() = tasks.size override fun getItemCount() = tasks.size
}) })
} }

@ -40,7 +40,7 @@ class GoogleTaskManualSortAdapterTest : InjectingTestCase() {
private val dataSource = object : TaskAdapterDataSource { private val dataSource = object : TaskAdapterDataSource {
override fun getItem(position: Int) = tasks[position] override fun getItem(position: Int) = tasks[position]
override val itemCount get() = tasks.size override fun getItemCount() = tasks.size
} }
@Test @Test

@ -237,7 +237,7 @@ class TaskListFragment : InjectingFragment(), OnRefreshListener, Toolbar.OnMenuI
} else if (recyclerAdapter !is DragAndDropRecyclerAdapter) { } else if (recyclerAdapter !is DragAndDropRecyclerAdapter) {
setAdapter( setAdapter(
DragAndDropRecyclerAdapter( DragAndDropRecyclerAdapter(
taskAdapter, recyclerView, viewHolderFactory, this, tasks, taskDao)) taskAdapter, recyclerView, viewHolderFactory, this, tasks as MutableList, taskDao))
return return
} }
recyclerAdapter!!.submitList(tasks) recyclerAdapter!!.submitList(tasks)

@ -34,7 +34,6 @@ open class GoogleTaskAdapter internal constructor(private val taskDao: TaskDao,
override fun moved(from: Int, to: Int, indent: Int) { override fun moved(from: Int, to: Int, indent: Int) {
val task = getTask(from) val task = getTask(from)
val googleTask = task.googleTask val googleTask = task.googleTask
val previous = if (to > 0) getTask(to - 1) else null
if (indent == 0) { if (indent == 0) {
if (googleTask.indent == 0) { if (googleTask.indent == 0) {
return return
@ -42,6 +41,7 @@ open class GoogleTaskAdapter internal constructor(private val taskDao: TaskDao,
googleTaskDao.move( googleTaskDao.move(
googleTask, 0, if (newTasksOnTop) 0 else googleTaskDao.getBottom(googleTask.listId, 0)) googleTask, 0, if (newTasksOnTop) 0 else googleTaskDao.getBottom(googleTask.listId, 0))
} else { } else {
val previous = if (to > 0) getTask(to - 1) else null
val newParent = if (previous!!.hasParent()) previous.parent else previous.id val newParent = if (previous!!.hasParent()) previous.parent else previous.id
if (googleTask.parent == newParent) { if (googleTask.parent == newParent) {
return return

@ -14,7 +14,7 @@ open class TaskAdapter {
private lateinit var dataSource: TaskAdapterDataSource private lateinit var dataSource: TaskAdapterDataSource
val count: Int val count: Int
get() = dataSource.itemCount get() = dataSource.getItemCount()
fun setDataSource(dataSource: TaskAdapterDataSource) { fun setDataSource(dataSource: TaskAdapterDataSource) {
this.dataSource = dataSource this.dataSource = dataSource

@ -5,5 +5,5 @@ import org.tasks.data.TaskContainer
interface TaskAdapterDataSource { interface TaskAdapterDataSource {
fun getItem(position: Int): TaskContainer fun getItem(position: Int): TaskContainer
val itemCount: Int fun getItemCount(): Int
} }

@ -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…
Cancel
Save