diff --git a/app/src/main/java/com/todoroo/andlib/sql/Query.java b/app/src/main/java/com/todoroo/andlib/sql/Query.java index a3452c323..9983781da 100644 --- a/app/src/main/java/com/todoroo/andlib/sql/Query.java +++ b/app/src/main/java/com/todoroo/andlib/sql/Query.java @@ -23,6 +23,7 @@ public final class Query { private final ArrayList joins = new ArrayList<>(); private SqlTable table; private String queryTemplate = null; + private String preClause = null; private Query(Field... fields) { this.fields.addAll(asList(fields)); @@ -61,6 +62,9 @@ public final class Query { @Override public String toString() { StringBuilder sql = new StringBuilder(); + if (preClause != null) { + sql.append(preClause); + } visitSelectClause(sql); visitFromClause(sql); @@ -118,4 +122,9 @@ public final class Query { queryTemplate = template; return this; } + + public Query withPreClause(String clause) { + preClause = clause; + return this; + } } diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java index 96e38dfc2..77e3051bc 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java @@ -259,7 +259,7 @@ public final class TaskListFragment extends InjectingFragment taskAdapter.isManuallySorted()); recyclerAdapter = - taskAdapter.isManuallySorted() + taskAdapter.supportsParentingOrManualSort() ? new ManualSortRecyclerAdapter( taskAdapter, recyclerView, diff --git a/app/src/main/java/com/todoroo/astrid/adapter/AstridTaskAdapter.java b/app/src/main/java/com/todoroo/astrid/adapter/AstridTaskAdapter.java index de5d07b5a..81708b458 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/AstridTaskAdapter.java +++ b/app/src/main/java/com/todoroo/astrid/adapter/AstridTaskAdapter.java @@ -55,6 +55,11 @@ public final class AstridTaskAdapter extends TaskAdapter { return true; } + @Override + public boolean supportsParentingOrManualSort() { + return true; + } + @Override public void moved(int from, int to, int indent) { TaskContainer source = getTask(from); diff --git a/app/src/main/java/com/todoroo/astrid/adapter/CaldavTaskAdapter.java b/app/src/main/java/com/todoroo/astrid/adapter/CaldavTaskAdapter.java new file mode 100644 index 000000000..86fa94a3c --- /dev/null +++ b/app/src/main/java/com/todoroo/astrid/adapter/CaldavTaskAdapter.java @@ -0,0 +1,159 @@ +package com.todoroo.astrid.adapter; + +import static com.todoroo.andlib.utility.DateUtilities.now; +import com.todoroo.andlib.utility.DateUtilities; +import com.todoroo.astrid.dao.TaskDao; +import com.todoroo.astrid.data.Task; +import org.tasks.data.CaldavDao; +import org.tasks.data.CaldavTask; +import org.tasks.data.TaskContainer; +import org.tasks.tasklist.ViewHolder; +import timber.log.Timber; +import java.util.ArrayList; +import java.util.List; + +public final class CaldavTaskAdapter extends TaskAdapter { + + private final TaskDao taskDao; + private final CaldavDao caldavDao; + + CaldavTaskAdapter(TaskDao taskDao, CaldavDao caldavDao) { + this.taskDao = taskDao; + this.caldavDao = caldavDao; + } + + @Override + public int getIndent(TaskContainer task) { + return task.getIndent(); + } + + @Override + public boolean canMove(ViewHolder sourceVh, ViewHolder targetVh) { + TaskContainer source = sourceVh.task; + int to = targetVh.getAdapterPosition(); + + if (taskIsChild(source.getCaldavTask(), to)) { + return false; + } + + return true; + } + + @Override + public int maxIndent(int previousPosition, TaskContainer task) { + TaskContainer previous = getTask(previousPosition); + return previous.getIndent() + 1; + } + + @Override + public int minIndent(int nextPosition, TaskContainer task) { + return 0; + } + + @Override + public boolean isManuallySorted() { + return false; + } + + @Override + public boolean supportsParentingOrManualSort() { + return true; + } + + @Override + public void moved(int from, int to, int indent) { + TaskContainer task = getTask(from); + TaskContainer previous = to > 0 ? getTask(to-1) : null; + + String prevTitle = previous != null ? previous.getTitle() : ""; + Timber.d("Moving %s (index %s) to %s (index %s)", task.getTitle(), from, prevTitle, to); + + long newParent = task.getParent(); + if (indent == 0) { + newParent = 0; + } else if (previous != null) { + if (indent == previous.getIndent()) { + newParent = previous.getParent(); + } else if (indent > previous.getIndent()) { + newParent = previous.getId(); + } + } + + // If nothing is changing, return + if (newParent == task.getParent()) { + return; + } + + changeParent(task, newParent); + + Task update = task.getTask(); + update.setModificationDate(now()); + taskDao.save(update); + } + + public void changeParent(TaskContainer task, long newParent) { + CaldavTask caldavTask = task.getCaldavTask(); + + if (newParent == 0) { + caldavTask.setRemoteParent(""); + caldavTask.setParent(0); + } else { + CaldavTask parentTask = caldavDao.getTask(newParent); + if (parentTask == null) + return; + caldavTask.setRemoteParent(parentTask.getRemoteId()); + caldavTask.setParent(newParent); + } + caldavDao.update(caldavTask); + } + + private boolean taskIsChild(CaldavTask parent, int destinationIndex) { + // Don't allow dropping a parent onto their child + TaskContainer ownChildCheck = getTask(destinationIndex); + long movingCaldavTaskId = parent.getId(); + int itemIndex = destinationIndex; + // Iterate levels of the hierarchy + while (ownChildCheck != null && ownChildCheck.getParent() != 0) { + // If the task we're trying to move is a parent of the destination, cancel the move + if (ownChildCheck.getParent() == movingCaldavTaskId) + return true; + + // Loop through the items in the view above the current task, looking for the parent + long searchParent = ownChildCheck.getParent(); + while (ownChildCheck.getId() != searchParent) { + // Handle case of parent not found in search, which shouldn't ever occur + if (itemIndex == 0) { + Timber.w("Couldn't find parent"); + return true; + } + ownChildCheck = getTask(--itemIndex); + } + } + return false; + } + + @Override + public void onCompletedTask(TaskContainer item, boolean completedState) { + final long completionDate = completedState ? DateUtilities.now() : 0; + + // TODO handle recurring tasks ala AstridTaskManager? + + List parents = new ArrayList<>(); + parents.add(item.getCaldavTask().getId()); + + TaskContainer checkTask; + Task updateTask; + for (int i = 0; i < getCount(); i++) { + checkTask = getTask(i); + if (parents.contains(checkTask.getParent())) { + Timber.d("Marking child %s completed (%s)", checkTask.getTitle(), completionDate); + + updateTask = checkTask.getTask(); + updateTask.setCompletionDate(completionDate); + taskDao.save(updateTask); + + parents.add(checkTask.getCaldavTask().getId()); + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskAdapter.java b/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskAdapter.java index 49b3501f1..de7e4b984 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskAdapter.java +++ b/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskAdapter.java @@ -70,6 +70,11 @@ public final class GoogleTaskAdapter extends TaskAdapter { return true; } + @Override + public boolean supportsParentingOrManualSort() { + return true; + } + @Override public void moved(int from, int to, int indent) { TaskContainer task = getTask(from); diff --git a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java index bcab58c1e..97a857929 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java @@ -85,6 +85,10 @@ public class TaskAdapter { return false; } + public boolean supportsParentingOrManualSort() { + return false; + } + public void moved(int from, int to, int indent) {} public TaskContainer getTask(int position) { diff --git a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapterProvider.java b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapterProvider.java index e9bcbeab7..b9675317b 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapterProvider.java +++ b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapterProvider.java @@ -78,7 +78,7 @@ public class TaskAdapterProvider { CaldavFilter caldavFilter = (CaldavFilter) filter; CaldavCalendar calendar = caldavDao.getCalendarByUuid(caldavFilter.getUuid()); if (calendar != null) { - return new TaskAdapter(); + return new CaldavTaskAdapter(taskDao, caldavDao); } } else { return subtasksHelper.shouldUseSubtasksFragmentForFilter(filter) diff --git a/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java b/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java index 867c14d17..d6bab21bc 100644 --- a/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java +++ b/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java @@ -51,7 +51,7 @@ public class CaldavFilter extends Filter { private static QueryTemplate queryTemplate(CaldavCalendar caldavCalendar) { return new QueryTemplate() - .join(Join.left(CaldavTask.TABLE, Task.ID.eq(Field.field("caldav_tasks.cd_task")))) + .join(getJoin()) .where( Criterion.and( TaskDao.TaskCriteria.activeAndVisible(), @@ -106,4 +106,12 @@ public class CaldavFilter extends Filter { public boolean areContentsTheSame(@NonNull FilterListItem other) { return calendar.equals(((CaldavFilter) other).calendar); } + + private static Join getJoin() { + return Join.left(CaldavTask.TABLE, Task.ID.eq(Field.field("caldav_tasks.cd_task"))); + } + + public static String getJoinSql() { + return getJoin().toString(); + } } diff --git a/app/src/main/java/com/todoroo/astrid/core/SortHelper.java b/app/src/main/java/com/todoroo/astrid/core/SortHelper.java index b7e69a1d2..1d2ea2943 100644 --- a/app/src/main/java/com/todoroo/astrid/core/SortHelper.java +++ b/app/src/main/java/com/todoroo/astrid/core/SortHelper.java @@ -49,24 +49,31 @@ public class SortHelper { originalSql += " ORDER BY " + order; } + return adjustQueryForFlags(preferences, originalSql); + } + + public static String adjustQueryForFlags( + Preferences preferences, String originalSql) { + String adjustedSql = originalSql; + // flags if (preferences.getBoolean(R.string.p_show_completed_tasks, false)) { - originalSql = - originalSql.replace(Task.COMPLETION_DATE.eq(0).toString(), Criterion.all.toString()); + adjustedSql = + adjustedSql.replace(Task.COMPLETION_DATE.eq(0).toString(), Criterion.all.toString()); } else { - originalSql = - originalSql.replace( - Task.COMPLETION_DATE.eq(0).toString(), - Criterion.or( - Task.COMPLETION_DATE.lte(0), - Task.COMPLETION_DATE.gt(DateUtilities.now() - 60000)) - .toString()); + adjustedSql = + adjustedSql.replace( + Task.COMPLETION_DATE.eq(0).toString(), + Criterion.or( + Task.COMPLETION_DATE.lte(0), + Task.COMPLETION_DATE.gt(DateUtilities.now() - 60000)) + .toString()); } if (preferences.getBoolean(R.string.p_show_hidden_tasks, false)) { - originalSql = originalSql.replace(isVisible().toString(), Criterion.all.toString()); + adjustedSql = adjustedSql.replace(isVisible().toString(), Criterion.all.toString()); } - return originalSql; + return adjustedSql; } private static Order orderForSortType(int sortType) { @@ -110,4 +117,70 @@ public class SortHelper { return order; } + + public static String orderSelectForSortTypeRecursive(int sortType) { + String select; + switch (sortType) { + case SORT_ALPHA: + // Return an empty string, providing a value to fill the WITH clause template + select = "''"; + break; + case SORT_DUE: + select = "(CASE WHEN (tasks.dueDate=0) THEN (strftime('%s','now')*1000)*2 ELSE " + + ADJUSTED_DUE_DATE.replace("dueDate", "tasks.dueDate") + + " END)+tasks.importance AS sort_duedate"; + break; + case SORT_IMPORTANCE: + select = "tasks.importance*(strftime('%s','now')*1000)+(CASE WHEN (tasks.dueDate=0) THEN (strftime('%s','now')*1000) ELSE tasks.dueDate END) AS sort_importance"; + break; + case SORT_MODIFIED: + select = "tasks.modified AS sort_modified"; + break; + case SORT_WIDGET: + default: + select ="(CASE WHEN (tasks.dueDate=0) " + + // if no due date + "THEN (strftime('%s','now')*1000)*2 " + + // then now * 2 + "ELSE (" + + ADJUSTED_DUE_DATE.replace("dueDate", "tasks.dueDate") + + ") END) " + + // else due time + "+ 172800000 * tasks.importance AS sort_smart"; // add 2 days * importance + } + + return select; + } + + public static Order orderForSortTypeRecursive(Preferences preferences) { + Order order; + switch (preferences.getSortMode()) { + case SORT_ALPHA: + order = Order.asc("sort_title"); + break; + case SORT_DUE: + order = Order.asc("sort_duedate"); + break; + case SORT_IMPORTANCE: + order = Order.asc("sort_importance"); + break; + case SORT_MODIFIED: + order = Order.desc("sort_modified"); + break; + case SORT_WIDGET: + default: + order = Order.asc("sort_smart"); + } + if (preferences.getSortMode() != SORT_ALPHA) { + order.addSecondaryExpression(Order.asc("sort_title")); + } + + if (preferences.getBoolean(R.string.p_reverse_sort, false)) { + order = order.reverse(); + } + + return order; + } + + } diff --git a/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java b/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java index 5bf3d0e5e..0f35320a9 100644 --- a/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java +++ b/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java @@ -60,6 +60,7 @@ import org.tasks.data.TagDao; import org.tasks.data.TagData; import org.tasks.data.TagDataDao; import org.tasks.injection.ForApplication; +import retrofit2.http.HEAD; import timber.log.Timber; public class CaldavSynchronizer { diff --git a/app/src/main/java/org/tasks/data/CaldavDao.java b/app/src/main/java/org/tasks/data/CaldavDao.java index 6e11671db..6fc98fe2c 100644 --- a/app/src/main/java/org/tasks/data/CaldavDao.java +++ b/app/src/main/java/org/tasks/data/CaldavDao.java @@ -11,88 +11,88 @@ import java.util.List; import org.tasks.filters.CaldavFilters; @Dao -public interface CaldavDao { +public abstract class CaldavDao { @Query("SELECT * FROM caldav_lists") - LiveData> subscribeToCalendars(); + public abstract LiveData> subscribeToCalendars(); @Query("SELECT * FROM caldav_lists WHERE cdl_uuid = :uuid LIMIT 1") - CaldavCalendar getCalendarByUuid(String uuid); + public abstract CaldavCalendar getCalendarByUuid(String uuid); @Query("SELECT * FROM caldav_accounts WHERE cda_uuid = :uuid LIMIT 1") - CaldavAccount getAccountByUuid(String uuid); + public abstract CaldavAccount getAccountByUuid(String uuid); @Query("SELECT COUNT(*) FROM caldav_accounts") - Single accountCount(); + public abstract Single accountCount(); @Query("SELECT * FROM caldav_accounts ORDER BY UPPER(cda_name) ASC") - List getAccounts(); + public abstract List getAccounts(); @Insert - long insert(CaldavAccount caldavAccount); + public abstract long insert(CaldavAccount caldavAccount); @Update - void update(CaldavAccount caldavAccount); + public abstract void update(CaldavAccount caldavAccount); @Insert - long insert(CaldavCalendar caldavCalendar); + public abstract long insert(CaldavCalendar caldavCalendar); @Update - void update(CaldavCalendar caldavCalendar); + public abstract void update(CaldavCalendar caldavCalendar); @Insert - long insert(CaldavTask caldavTask); + public abstract long insert(CaldavTask caldavTask); @Insert - void insert(Iterable tasks); + public abstract void insert(Iterable tasks); @Update - void update(CaldavTask caldavTask); + public abstract void update(CaldavTask caldavTask); @Delete - void delete(CaldavTask caldavTask); + public abstract void delete(CaldavTask caldavTask); @Query("SELECT * FROM caldav_tasks WHERE cd_deleted > 0 AND cd_calendar = :calendar") - List getDeleted(String calendar); + public abstract List getDeleted(String calendar); @Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted = 0 LIMIT 1") - CaldavTask getTask(long taskId); + public abstract CaldavTask getTask(long taskId); @Query("SELECT * FROM caldav_tasks WHERE cd_calendar = :calendar AND cd_object = :object LIMIT 1") - CaldavTask getTask(String calendar, String object); + public abstract CaldavTask getTask(String calendar, String object); @Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId") - List getTasks(long taskId); + public abstract List getTasks(long taskId); @Query( "SELECT task.*, caldav_task.* FROM tasks AS task " + "INNER JOIN caldav_tasks AS caldav_task ON _id = cd_task " + "WHERE cd_deleted = 0 AND cd_vtodo IS NOT NULL AND cd_vtodo != ''") - List getTasks(); + public abstract List getTasks(); @Query("SELECT * FROM caldav_lists ORDER BY cdl_name COLLATE NOCASE") - List getCalendars(); + public abstract List getCalendars(); @Query("SELECT * FROM caldav_lists WHERE cdl_uuid = :uuid LIMIT 1") - CaldavCalendar getCalendar(String uuid); + public abstract CaldavCalendar getCalendar(String uuid); @Query("SELECT cd_object FROM caldav_tasks WHERE cd_calendar = :calendar") - List getObjects(String calendar); + public abstract List getObjects(String calendar); @Query("SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :calendar AND cd_object IN (:objects)") - List getTasks(String calendar, List objects); + public abstract List getTasks(String calendar, List objects); @Query("SELECT * FROM caldav_lists WHERE cdl_account = :account AND cdl_url NOT IN (:urls)") - List findDeletedCalendars(String account, List urls); + public abstract List findDeletedCalendars(String account, List urls); @Query("SELECT * FROM caldav_lists WHERE cdl_account = :account AND cdl_url = :url LIMIT 1") - CaldavCalendar getCalendarByUrl(String account, String url); + public abstract CaldavCalendar getCalendarByUrl(String account, String url); @Query("SELECT * FROM caldav_accounts WHERE cda_name = :name COLLATE NOCASE LIMIT 1") - CaldavAccount getAccountByName(String name); + public abstract CaldavAccount getAccountByName(String name); @Query("SELECT DISTINCT cd_calendar FROM caldav_tasks WHERE cd_deleted = 0 AND cd_task IN (:tasks)") - List getCalendars(List tasks); + public abstract List getCalendars(List tasks); @Query( "SELECT caldav_lists.*, caldav_accounts.*, COUNT(tasks._id) AS count" @@ -102,17 +102,17 @@ public interface CaldavDao { + " LEFT JOIN tasks ON caldav_tasks.cd_task = tasks._id AND tasks.deleted = 0 AND tasks.completed = 0 AND tasks.hideUntil < :now" + " GROUP BY caldav_lists.cdl_uuid" + " ORDER BY caldav_accounts.cda_name COLLATE NOCASE, caldav_lists.cdl_name COLLATE NOCASE") - List getCaldavFilters(long now); + public abstract List getCaldavFilters(long now); @Query( "SELECT tasks._id FROM tasks " + "INNER JOIN tags ON tags.task = tasks._id " + "INNER JOIN caldav_tasks ON cd_task = tasks._id " + "GROUP BY tasks._id") - List getTasksWithTags(); + public abstract List getTasksWithTags(); @Query("UPDATE caldav_tasks SET cd_parent = IFNULL((SELECT cd_task FROM caldav_tasks AS p WHERE p.cd_remote_id = caldav_tasks.cd_remote_parent), cd_parent) WHERE cd_calendar = :calendar AND cd_remote_parent IS NOT NULL and cd_remote_parent != ''") - void updateParents(String calendar); + public abstract void updateParents(String calendar); @Query("WITH RECURSIVE " + " recursive_caldav (cd_task) AS ( " @@ -132,5 +132,5 @@ public interface CaldavDao { + " WHERE tasks.deleted = 0 " + " ) " + "SELECT cd_task FROM recursive_caldav") - List getChildren(List ids); + public abstract List getChildren(List ids); } diff --git a/app/src/main/java/org/tasks/data/TaskContainer.java b/app/src/main/java/org/tasks/data/TaskContainer.java index 9b16a8a89..e75574507 100644 --- a/app/src/main/java/org/tasks/data/TaskContainer.java +++ b/app/src/main/java/org/tasks/data/TaskContainer.java @@ -190,11 +190,21 @@ public class TaskContainer { } public long getParent() { - return googletask == null ? 0 : googletask.getParent(); + if (googletask != null) { + return googletask.getParent(); + } else if (caldavTask != null) { + return caldavTask.getParent(); + } else { + return 0; + } } public void setParent(long parent) { - googletask.setParent(parent); + if (googletask != null) { + googletask.setParent(parent); + } else if (caldavTask != null) { + caldavTask.setParent(parent); + } } public boolean hasParent() { @@ -213,6 +223,10 @@ public class TaskContainer { return googletask; } + public CaldavTask getCaldavTask() { + return caldavTask; + } + public int getTargetIndent() { return targetIndent; } diff --git a/app/src/main/java/org/tasks/tasklist/ItemTouchHelperCallback.java b/app/src/main/java/org/tasks/tasklist/ItemTouchHelperCallback.java index 94cea53ce..b02f52a9c 100644 --- a/app/src/main/java/org/tasks/tasklist/ItemTouchHelperCallback.java +++ b/app/src/main/java/org/tasks/tasklist/ItemTouchHelperCallback.java @@ -9,6 +9,7 @@ import android.graphics.Canvas; import androidx.annotation.NonNull; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; +import com.todoroo.astrid.adapter.CaldavTaskAdapter; import com.todoroo.astrid.adapter.TaskAdapter; import com.todoroo.astrid.utility.Flags; import org.tasks.data.TaskContainer; @@ -42,7 +43,7 @@ public class ItemTouchHelperCallback extends ItemTouchHelper.Callback { @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { - return adapter.isManuallySorted() && adapter.getNumSelected() == 0 + return adapter.supportsParentingOrManualSort() && adapter.getNumSelected() == 0 ? makeMovementFlags(UP | DOWN | LEFT | RIGHT, 0) : makeMovementFlags(0, 0); } @@ -140,13 +141,17 @@ public class ItemTouchHelperCallback extends ItemTouchHelper.Callback { if (from < to) { to++; } - vh.task.setIndent(targetIndent); - vh.setIndent(targetIndent); + if (!(adapter instanceof CaldavTaskAdapter)) { + vh.task.setIndent(targetIndent); + vh.setIndent(targetIndent); + } recyclerAdapter.moved(from, to, targetIndent); } else if (task.getIndent() != targetIndent) { int position = vh.getAdapterPosition(); - vh.task.setIndent(targetIndent); - vh.setIndent(targetIndent); + if (!(adapter instanceof CaldavTaskAdapter)) { + vh.task.setIndent(targetIndent); + vh.setIndent(targetIndent); + } recyclerAdapter.moved(position, position, targetIndent); } } diff --git a/app/src/main/java/org/tasks/tasklist/ManualSortRecyclerAdapter.java b/app/src/main/java/org/tasks/tasklist/ManualSortRecyclerAdapter.java index ea0ee2126..12b2f21f6 100644 --- a/app/src/main/java/org/tasks/tasklist/ManualSortRecyclerAdapter.java +++ b/app/src/main/java/org/tasks/tasklist/ManualSortRecyclerAdapter.java @@ -16,6 +16,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.PublishSubject; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -103,8 +104,10 @@ public class ManualSortRecyclerAdapter extends TaskListRecyclerAdapter { 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); + if (list instanceof ArrayList) { + TaskContainer task = list.remove(from); + list.add(from < to ? to - 1 : to, task); + } taskList.loadTaskListContent(); } } diff --git a/app/src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java b/app/src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java index 83c0ea4ef..4231d501e 100644 --- a/app/src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java +++ b/app/src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java @@ -91,7 +91,7 @@ public abstract class TaskListRecyclerAdapter extends RecyclerView.Adapter fields = Lists.newArrayList(TASKS, TAGS, GTASK, CALDAV, GEOFENCE, PLACE); + List fields = Lists.newArrayList(TASKS, GTASK, CALDAV, GEOFENCE, PLACE); Criterion tagsJoinCriterion = Criterion.and(Task.ID.eq(field(TAGS_METADATA_JOIN + ".task"))); Criterion gtaskJoinCriterion = @@ -114,32 +124,96 @@ public class TaskListViewModel extends ViewModel implements Observer taskContainers) { + if (filter instanceof CaldavFilter) { + // Populate child count for CalDAV + // TODO Review if there's a better place to call this, and regardless, where to + // put a function that does this work + HashMap parents = new HashMap<>(); + TaskContainer prev = null; + for (TaskContainer cont: taskContainers) { + CaldavTask caldavTask = cont.getCaldavTask(); + if (caldavTask.getParent() != 0) { + long parentId = caldavTask.getParent(); + if (!parents.containsKey(parentId) && prev != null && prev.getId() == parentId) { + parents.put(parentId, prev); + } + parents.get(parentId).children++; + } + prev = cont; + } + } tasks.setValue(taskContainers); } }