Replace cursors with lists

pull/618/head
Alex Baker 8 years ago
parent 39c10a8ac9
commit 8e3936b159

@ -6,8 +6,6 @@
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle; import android.os.Bundle;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
@ -18,13 +16,12 @@ import com.todoroo.astrid.data.Task;
import org.tasks.data.GoogleTask; import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskList; import org.tasks.data.GoogleTaskList;
import org.tasks.injection.ForApplication;
import org.tasks.injection.FragmentComponent; import org.tasks.injection.FragmentComponent;
import org.tasks.tasklist.GtasksListFragment; import org.tasks.tasklist.GtasksListFragment;
import org.tasks.themes.Theme;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -37,8 +34,6 @@ public class GtasksSubtaskListFragment extends GtasksListFragment {
return fragment; return fragment;
} }
@Inject @ForApplication Context context;
@Inject Theme theme;
@Inject OrderedMetadataListFragmentHelper helper; @Inject OrderedMetadataListFragmentHelper helper;
@Override @Override
@ -78,8 +73,8 @@ public class GtasksSubtaskListFragment extends GtasksListFragment {
} }
@Override @Override
protected TaskAdapter createTaskAdapter(Cursor cursor) { protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return helper.createTaskAdapter(theme.wrap(context), cursor); return helper.createTaskAdapter(tasks);
} }
@Override @Override

@ -5,8 +5,6 @@
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils; import android.text.TextUtils;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
@ -23,6 +21,7 @@ import org.tasks.data.GoogleTaskList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
@ -55,8 +54,8 @@ class OrderedMetadataListFragmentHelper {
updater.initialize(filter); updater.initialize(filter);
} }
TaskAdapter createTaskAdapter(Context context, Cursor cursor) { TaskAdapter createTaskAdapter(List<Task> cursor) {
taskAdapter = new DraggableTaskAdapter(context, cursor); taskAdapter = new DraggableTaskAdapter(cursor);
taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks);
@ -65,8 +64,8 @@ class OrderedMetadataListFragmentHelper {
private final class DraggableTaskAdapter extends TaskAdapter { private final class DraggableTaskAdapter extends TaskAdapter {
private DraggableTaskAdapter(Context context, Cursor c) { private DraggableTaskAdapter(List<Task> tasks) {
super(context, c); super(tasks);
} }
@Override @Override
@ -87,11 +86,11 @@ class OrderedMetadataListFragmentHelper {
@Override @Override
public void moved(int from, int to) { public void moved(int from, int to) {
long targetTaskId = taskAdapter.getItemId(from); long targetTaskId = taskAdapter.getTaskId(from);
if (targetTaskId <= 0) { if (targetTaskId <= 0) {
return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks) return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks)
} }
long destinationTaskId = taskAdapter.getItemId(to); long destinationTaskId = taskAdapter.getTaskId(to);
try { try {
if(to >= taskAdapter.getCount()) { if(to >= taskAdapter.getCount()) {
@ -108,7 +107,7 @@ class OrderedMetadataListFragmentHelper {
@Override @Override
public void indented(int which, int delta) { public void indented(int which, int delta) {
long targetTaskId = taskAdapter.getItemId(which); long targetTaskId = taskAdapter.getTaskId(which);
if (targetTaskId <= 0) { if (targetTaskId <= 0) {
return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks) return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks)
} }
@ -137,7 +136,7 @@ class OrderedMetadataListFragmentHelper {
task.setCompletionDate(completionDate); task.setCompletionDate(completionDate);
taskDao.save(task); taskDao.save(task);
} }
taskAdapter.notifyDataSetInvalidated(); fragment.loadTaskListContent();
} }
return; return;
} }
@ -159,7 +158,7 @@ class OrderedMetadataListFragmentHelper {
if(chained.size() > 0) { if(chained.size() > 0) {
chainedCompletions.put(itemId, chained); chainedCompletions.put(itemId, chained);
taskAdapter.notifyDataSetInvalidated(); fragment.loadTaskListContent();
} }
} }
@ -169,6 +168,6 @@ class OrderedMetadataListFragmentHelper {
void onDeleteTask(Task task) { void onDeleteTask(Task task) {
updater.onDeleteTask(list, task.getId()); updater.onDeleteTask(list, task.getId());
taskAdapter.notifyDataSetInvalidated(); fragment.loadTaskListContent();
} }
} }

@ -5,7 +5,6 @@
*/ */
package com.todoroo.andlib.data; package com.todoroo.andlib.data;
import android.database.Cursor;
import android.text.TextUtils; import android.text.TextUtils;
import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Field;
@ -50,11 +49,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
this.name = columnName; this.name = columnName;
} }
/**
* Accept a visitor
*/
abstract public TYPE getValue(Cursor data);
/** /**
* Return a clone of this property * Return a clone of this property
*/ */
@ -104,11 +98,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
IntegerProperty(String name, String expression) { IntegerProperty(String name, String expression) {
super(null, name, expression); super(null, name, expression);
} }
@Override
public Integer getValue(Cursor data) {
return data.getInt(data.getColumnIndexOrThrow(getColumnName()));
}
} }
/** /**
@ -123,11 +112,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
super(table, name); super(table, name);
} }
@Override
public String getValue(Cursor data) {
return data.getString(data.getColumnIndexOrThrow(getColumnName()));
}
@Override @Override
public StringProperty as(String newAlias) { public StringProperty as(String newAlias) {
return (StringProperty) super.as(newAlias); return (StringProperty) super.as(newAlias);
@ -146,11 +130,6 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
super(table, name); super(table, name);
} }
@Override
public Long getValue(Cursor data) {
return data.getLong(data.getColumnIndexOrThrow(getColumnName()));
}
@Override @Override
public LongProperty cloneAs(String tableAlias, String columnAlias) { public LongProperty cloneAs(String tableAlias, String columnAlias) {
return (LongProperty) super.cloneAs(tableAlias, columnAlias); return (LongProperty) super.cloneAs(tableAlias, columnAlias);

@ -9,7 +9,6 @@ import android.app.Activity;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle; import android.os.Bundle;
import android.speech.RecognizerIntent; import android.speech.RecognizerIntent;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -286,13 +285,13 @@ public class TaskListFragment extends InjectingFragment implements
case R.id.menu_show_hidden: case R.id.menu_show_hidden:
item.setChecked(!item.isChecked()); item.setChecked(!item.isChecked());
preferences.setBoolean(R.string.p_show_hidden_tasks, item.isChecked()); preferences.setBoolean(R.string.p_show_hidden_tasks, item.isChecked());
reconstructCursor(); loadTaskListContent();
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();
return true; return true;
case R.id.menu_show_completed: case R.id.menu_show_completed:
item.setChecked(!item.isChecked()); item.setChecked(!item.isChecked());
preferences.setBoolean(R.string.p_show_completed_tasks, item.isChecked()); preferences.setBoolean(R.string.p_show_completed_tasks, item.isChecked());
reconstructCursor(); loadTaskListContent();
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();
return true; return true;
case R.id.menu_filter_settings: case R.id.menu_filter_settings:
@ -366,16 +365,6 @@ public class TaskListFragment extends InjectingFragment implements
return snackbar; return snackbar;
} }
@Override
public void onDestroy() {
super.onDestroy();
Cursor cursor = taskAdapter.getCursor();
if (cursor != null) {
cursor.close();
}
}
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
@ -416,12 +405,15 @@ public class TaskListFragment extends InjectingFragment implements
* Load or re-load action items and update views * Load or re-load action items and update views
*/ */
public void loadTaskListContent() { public void loadTaskListContent() {
Cursor taskCursor = taskAdapter.getCursor(); if (taskAdapter == null) {
return;
}
// stash selected items // stash selected items
Bundle saveState = recyclerAdapter.getSaveState(); Bundle saveState = recyclerAdapter.getSaveState();
taskCursor.requery(); List<Task> tasks = taskListDataProvider.toList(filter, taskProperties());
taskAdapter.setTasks(tasks);
if (taskAdapter.getCount() == 0) { if (taskAdapter.getCount() == 0) {
swipeRefreshLayout.setVisibility(View.GONE); swipeRefreshLayout.setVisibility(View.GONE);
emptyRefreshLayout.setVisibility(View.VISIBLE); emptyRefreshLayout.setVisibility(View.VISIBLE);
@ -433,8 +425,8 @@ public class TaskListFragment extends InjectingFragment implements
} }
} }
protected TaskAdapter createTaskAdapter(Cursor cursor) { protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return new TaskAdapter(context, cursor); return new TaskAdapter(tasks);
} }
public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$ public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$
@ -449,13 +441,10 @@ public class TaskListFragment extends InjectingFragment implements
return; return;
} }
Cursor currentCursor = taskListDataProvider.constructCursor(filter, taskProperties()); List<Task> tasks = taskListDataProvider.toList(filter, taskProperties());
if (currentCursor == null) {
return;
}
// set up list adapters // set up list adapters
taskAdapter = createTaskAdapter(currentCursor); taskAdapter = createTaskAdapter(tasks);
recyclerAdapter = new TaskListRecyclerAdapter(getActivity(), taskAdapter, viewHolderFactory, recyclerAdapter = new TaskListRecyclerAdapter(getActivity(), taskAdapter, viewHolderFactory,
this, taskDeleter, taskDuplicator, tracker, dialogBuilder); this, taskDeleter, taskDuplicator, tracker, dialogBuilder);
} }
@ -468,14 +457,6 @@ public class TaskListFragment extends InjectingFragment implements
return filter; return filter;
} }
public void reconstructCursor() {
Cursor cursor = taskListDataProvider.constructCursor(filter, taskProperties());
if (cursor == null || taskAdapter == null) {
return;
}
taskAdapter.changeCursor(cursor);
}
/* /*
* ====================================================================== * ======================================================================
* ============================================================== actions * ============================================================== actions

@ -5,13 +5,6 @@
*/ */
package com.todoroo.astrid.adapter; package com.todoroo.astrid.adapter;
import android.content.Context;
import android.database.Cursor;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.Filterable;
import com.google.common.collect.ObjectArrays; import com.google.common.collect.ObjectArrays;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.LongProperty;
@ -24,25 +17,37 @@ import org.tasks.data.TaskAttachment;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.todoroo.astrid.data.Task.NO_ID;
import static com.todoroo.astrid.data.Task.NO_UUID;
/** /**
* Adapter for displaying a user's tasks as a list * Adapter for displaying a user's tasks as a list
* *
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class TaskAdapter extends CursorAdapter implements Filterable { public class TaskAdapter {
private List<Task> tasks;
public List<Integer> getTaskPositions(List<Long> longs) { public List<Integer> getTaskPositions(List<Long> longs) {
List<Integer> result = new ArrayList<>(); List<Integer> result = new ArrayList<>();
Cursor taskCursor = getTaskCursor(); for (int i = 0 ; i < tasks.size() ; i++) {
for (taskCursor.moveToFirst() ; !taskCursor.isAfterLast() ; taskCursor.moveToNext()) { if (longs.contains(tasks.get(i).getId())) {
if (longs.contains(Task.ID.getValue(taskCursor))) { result.add(i);
result.add(taskCursor.getPosition());
} }
} }
return result; return result;
} }
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
public int getCount() {
return tasks.size();
}
public interface OnCompletedTaskListener { public interface OnCompletedTaskListener {
void onCompletedTask(Task item, boolean newState); void onCompletedTask(Task item, boolean newState);
} }
@ -59,18 +64,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private OnCompletedTaskListener onCompletedTaskListener = null; private OnCompletedTaskListener onCompletedTaskListener = null;
public TaskAdapter(Context context, Cursor c) { public TaskAdapter(List<Task> tasks) {
super(context, c, false); this.tasks = tasks;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
throw new RuntimeException();
}
@Override
public void bindView(View view, Context context, Cursor c) {
throw new RuntimeException();
} }
public int getIndent(Task task) { public int getIndent(Task task) {
@ -93,41 +88,20 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
private Cursor getTaskCursor() { public List<Task> getTasks() {
return getCursor(); return tasks;
} }
public long getTaskId(int position) { public long getTaskId(int position) {
Cursor c = getTaskCursor(); return position < tasks.size() ? tasks.get(position).getId() : NO_ID;
if (c != null) {
if (c.moveToPosition(position)) {
return Task.ID.getValue(c);
}
}
return Task.NO_ID;
} }
public Task getTask(int position) { public Task getTask(int position) {
Cursor c = getTaskCursor(); return position < tasks.size() ? tasks.get(position) : null;
if (c != null) {
if (c.moveToPosition(position)) {
return new Task(c);
}
}
return null;
} }
protected String getItemUuid(int position) { protected String getItemUuid(int position) {
Cursor c = getTaskCursor(); return position < tasks.size() ? tasks.get(position).getUuid() : NO_UUID;
if (c != null) {
if (c.moveToPosition(position)) {
return Task.UUID.getValue(c);
} else {
return Task.NO_UUID;
}
} else {
return Task.NO_UUID;
}
} }
public void onCompletedTask(Task task, boolean newState) { public void onCompletedTask(Task task, boolean newState) {

@ -225,12 +225,7 @@ public abstract class TaskDao {
} }
public int count(Filter filter) { public int count(Filter filter) {
Cursor cursor = fetchFiltered(filter.getSqlQuery(), Task.ID); return fetchFiltered(filter.getSqlQuery()).size();
try {
return cursor.getCount();
} finally {
cursor.close();
}
} }
public List<Task> fetchFiltered(Filter filter) { public List<Task> fetchFiltered(Filter filter) {
@ -238,25 +233,25 @@ public abstract class TaskDao {
} }
public List<Task> fetchFiltered(String query) { public List<Task> fetchFiltered(String query) {
Cursor cursor = fetchFiltered(query, Task.PROPERTIES); return fetchFiltered(query, Task.PROPERTIES);
}
public List<Task> fetchFiltered(String queryTemplate, Property<?>... properties) {
Query query = Query.select(properties).withQueryTemplate(PermaSql.replacePlaceholders(queryTemplate));
String queryString = query.from(Task.TABLE).toString();
if (BuildConfig.DEBUG) {
Timber.v(queryString);
}
Cursor cursor = database.rawQuery(queryString);
List<Task> result = new ArrayList<>(); List<Task> result = new ArrayList<>();
try { try {
for (cursor.moveToFirst() ; !cursor.isAfterLast() ; cursor.moveToNext()) { for (cursor.moveToFirst() ; !cursor.isAfterLast() ; cursor.moveToNext()) {
result.add(new Task(cursor)); result.add(new Task(cursor));
} }
return result;
} finally { } finally {
cursor.close(); cursor.close();
} }
return result;
}
public Cursor fetchFiltered(String queryTemplate, Property<?>... properties) {
Query query = Query.select(properties).withQueryTemplate(PermaSql.replacePlaceholders(queryTemplate));
String queryString = query.from(Task.TABLE).toString();
if (BuildConfig.DEBUG) {
Timber.v(queryString);
}
return database.rawQuery(queryString);
} }
} }

@ -213,6 +213,12 @@ public class Task implements Parcelable {
@Ignore @Ignore
private int googleTaskIndent; private int googleTaskIndent;
@Ignore
private String tags;
@Ignore
private boolean hasFiles;
@Ignore @Ignore
private HashMap<String, Object> transitoryData = null; private HashMap<String, Object> transitoryData = null;
@ -245,6 +251,8 @@ public class Task implements Parcelable {
final int _cursorIndexOfCalendarUri = _cursor.getColumnIndexOrThrow("calendarUri"); final int _cursorIndexOfCalendarUri = _cursor.getColumnIndexOrThrow("calendarUri");
final int _cursorIndexOfRemoteId = _cursor.getColumnIndexOrThrow("remoteId"); final int _cursorIndexOfRemoteId = _cursor.getColumnIndexOrThrow("remoteId");
final int _cursorIndexOfIndent = _cursor.getColumnIndex("index"); final int _cursorIndexOfIndent = _cursor.getColumnIndex("index");
final int _cursorIndexOfTags = _cursor.getColumnIndex("tags");
final int _cursorIndexOfFileId = _cursor.getColumnIndex("fileId");
if (_cursor.isNull(_cursorIndexOfId)) { if (_cursor.isNull(_cursorIndexOfId)) {
id = null; id = null;
} else { } else {
@ -333,6 +341,12 @@ public class Task implements Parcelable {
if (_cursorIndexOfIndent >= 0) { if (_cursorIndexOfIndent >= 0) {
googleTaskIndent = _cursor.getInt(_cursorIndexOfIndent); googleTaskIndent = _cursor.getInt(_cursorIndexOfIndent);
} }
if (_cursorIndexOfTags >= 0) {
tags = _cursor.getString(_cursorIndexOfTags);
}
if (_cursorIndexOfFileId >= 0) {
hasFiles = _cursor.getInt(_cursorIndexOfFileId) > 0;
}
} }
@Ignore @Ignore
@ -979,4 +993,12 @@ public class Task implements Parcelable {
Object trans = clearTransitory(flag); Object trans = clearTransitory(flag);
return trans != null; return trans != null;
} }
public String getTagsString() {
return tags;
}
public boolean hasFiles() {
return hasFiles;
}
} }

@ -1,7 +1,5 @@
package com.todoroo.astrid.subtasks; package com.todoroo.astrid.subtasks;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils; import android.text.TextUtils;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
@ -46,8 +44,8 @@ class AstridOrderedListFragmentHelper {
updater.initialize(list, filter); updater.initialize(list, filter);
} }
TaskAdapter createTaskAdapter(Context context, Cursor cursor) { TaskAdapter createTaskAdapter(List<Task> tasks) {
taskAdapter = new DraggableTaskAdapter(context, cursor); taskAdapter = new DraggableTaskAdapter(tasks);
taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks);
@ -56,8 +54,8 @@ class AstridOrderedListFragmentHelper {
private final class DraggableTaskAdapter extends TaskAdapter { private final class DraggableTaskAdapter extends TaskAdapter {
private DraggableTaskAdapter(Context context, Cursor c) { private DraggableTaskAdapter(List<Task> tasks) {
super(context, c); super(tasks);
} }
@Override @Override
@ -95,7 +93,6 @@ class AstridOrderedListFragmentHelper {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
} }
fragment.reconstructCursor();
fragment.loadTaskListContent(); fragment.loadTaskListContent();
} }
@ -111,7 +108,6 @@ class AstridOrderedListFragmentHelper {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
} }
fragment.reconstructCursor();
fragment.loadTaskListContent(); fragment.loadTaskListContent();
} }
} }
@ -130,7 +126,7 @@ class AstridOrderedListFragmentHelper {
for(String taskId : chained) { for(String taskId : chained) {
taskDao.setCompletionDate(taskId, completionDate); taskDao.setCompletionDate(taskId, completionDate);
} }
taskAdapter.notifyDataSetInvalidated(); fragment.loadTaskListContent();
} }
return; return;
} }
@ -159,7 +155,7 @@ class AstridOrderedListFragmentHelper {
} }
chainedCompletions.put(itemId, chained); chainedCompletions.put(itemId, chained);
taskAdapter.notifyDataSetInvalidated(); fragment.loadTaskListContent();
} }
} }
@ -169,12 +165,11 @@ class AstridOrderedListFragmentHelper {
void onCreateTask(String uuid) { void onCreateTask(String uuid) {
updater.onCreateTask(list, fragment.getFilter(), uuid); updater.onCreateTask(list, fragment.getFilter(), uuid);
fragment.reconstructCursor();
fragment.loadTaskListContent(); fragment.loadTaskListContent();
} }
void onDeleteTask(Task task) { void onDeleteTask(Task task) {
updater.onDeleteTask(list, fragment.getFilter(), task.getUuid()); updater.onDeleteTask(list, fragment.getFilter(), task.getUuid());
taskAdapter.notifyDataSetInvalidated(); fragment.loadTaskListContent();
} }
} }

@ -1,17 +1,15 @@
package com.todoroo.astrid.subtasks; package com.todoroo.astrid.subtasks;
import android.database.Cursor;
import android.text.TextUtils; import android.text.TextUtils;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import org.tasks.data.TaskListMetadataDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskListMetadata;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.tasks.data.TaskListMetadata;
import org.tasks.data.TaskListMetadataDao;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -120,28 +118,24 @@ public class SubtasksFilterUpdater {
sql = sql.replace( sql = sql.replace(
TaskDao.TaskCriteria.activeAndVisible().toString(), TaskDao.TaskCriteria.activeAndVisible().toString(),
TaskDao.TaskCriteria.notDeleted().toString()); TaskDao.TaskCriteria.notDeleted().toString());
Cursor tasks = taskDao.fetchFiltered(sql, Task.UUID); List<Task> tasks = taskDao.fetchFiltered(sql);
try { for (Task task : tasks) {
for (tasks.moveToFirst(); !tasks.isAfterLast(); tasks.moveToNext()) { String id = task.getUuid();
String id = tasks.getString(0); idsInQuery.add(id);
idsInQuery.add(id); if (idToNode.containsKey(id)) {
if (idToNode.containsKey(id)) { continue;
continue;
}
changedThings = true;
Node newNode = new Node(id, treeRoot, 0);
treeRoot.children.add(0, newNode);
idToNode.put(id, newNode);
} }
currentIds.removeAll(idsInQuery); changedThings = true;
if (currentIds.size() > 0) { Node newNode = new Node(id, treeRoot, 0);
removeNodes(currentIds); treeRoot.children.add(0, newNode);
changedThings = true; idToNode.put(id, newNode);
} }
} finally {
tasks.close(); currentIds.removeAll(idsInQuery);
if (currentIds.size() > 0) {
removeNodes(currentIds);
changedThings = true;
} }
if (changedThings) { if (changedThings) {
writeSerialization(list, serializeTree()); writeSerialization(list, serializeTree());

@ -7,7 +7,6 @@ package com.todoroo.astrid.subtasks;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils; import android.text.TextUtils;
import com.todoroo.astrid.activity.TaskListFragment; import com.todoroo.astrid.activity.TaskListFragment;
@ -15,14 +14,15 @@ import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.core.BuiltInFilterExposer; import com.todoroo.astrid.core.BuiltInFilterExposer;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import org.tasks.data.TaskListMetadataDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskListMetadata;
import org.tasks.data.TaskListMetadata;
import org.tasks.data.TaskListMetadataDao;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.injection.FragmentComponent; import org.tasks.injection.FragmentComponent;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.themes.Theme;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -43,7 +43,6 @@ public class SubtasksListFragment extends TaskListFragment {
@Inject Preferences preferences; @Inject Preferences preferences;
@Inject @ForApplication Context context; @Inject @ForApplication Context context;
@Inject TaskListMetadataDao taskListMetadataDao; @Inject TaskListMetadataDao taskListMetadataDao;
@Inject Theme theme;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject AstridOrderedListFragmentHelper helper; @Inject AstridOrderedListFragmentHelper helper;
@ -102,8 +101,8 @@ public class SubtasksListFragment extends TaskListFragment {
} }
@Override @Override
protected TaskAdapter createTaskAdapter(Cursor cursor) { protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return helper.createTaskAdapter(theme.wrap(context), cursor); return helper.createTaskAdapter(tasks);
} }
@Override @Override

@ -6,21 +6,19 @@
package com.todoroo.astrid.subtasks; package com.todoroo.astrid.subtasks;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import com.todoroo.astrid.activity.TaskListFragment; import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.adapter.TaskAdapter; import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.TagFilter; import com.todoroo.astrid.api.TagFilter;
import org.tasks.data.TaskListMetadataDao;
import org.tasks.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskListMetadata;
import org.tasks.injection.ForApplication; import org.tasks.data.TagData;
import org.tasks.data.TaskListMetadata;
import org.tasks.data.TaskListMetadataDao;
import org.tasks.injection.FragmentComponent; import org.tasks.injection.FragmentComponent;
import org.tasks.tasklist.TagListFragment; import org.tasks.tasklist.TagListFragment;
import org.tasks.themes.Theme;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -33,9 +31,7 @@ public class SubtasksTagListFragment extends TagListFragment {
return fragment; return fragment;
} }
@Inject @ForApplication Context context;
@Inject TaskListMetadataDao taskListMetadataDao; @Inject TaskListMetadataDao taskListMetadataDao;
@Inject Theme theme;
@Inject AstridOrderedListFragmentHelper helper; @Inject AstridOrderedListFragmentHelper helper;
@Override @Override
@ -72,8 +68,8 @@ public class SubtasksTagListFragment extends TagListFragment {
} }
@Override @Override
protected TaskAdapter createTaskAdapter(Cursor cursor) { protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return helper.createTaskAdapter(theme.wrap(context), cursor); return helper.createTaskAdapter(tasks);
} }
@Override @Override

@ -1,8 +1,5 @@
package org.tasks.data; package org.tasks.data;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Field;
@ -15,14 +12,11 @@ import com.todoroo.astrid.data.Task;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import timber.log.Timber;
import static com.todoroo.astrid.activity.TaskListFragment.FILE_METADATA_JOIN; import static com.todoroo.astrid.activity.TaskListFragment.FILE_METADATA_JOIN;
import static com.todoroo.astrid.activity.TaskListFragment.TAGS_METADATA_JOIN; import static com.todoroo.astrid.activity.TaskListFragment.TAGS_METADATA_JOIN;
@ -39,19 +33,10 @@ public class TaskListDataProvider {
} }
public List<Task> toList(Filter filter) { public List<Task> toList(Filter filter) {
Cursor cursor = constructCursor(filter, Task.PROPERTIES); return toList(filter, Task.PROPERTIES);
List<Task> result = new ArrayList<>();
try {
for (cursor.moveToFirst() ; !cursor.isAfterLast() ; cursor.moveToNext()) {
result.add(new Task(cursor));
}
} finally {
cursor.close();
}
return result;
} }
public Cursor constructCursor(Filter filter, Property<?>[] properties) { public List<Task> toList(Filter filter, Property<?>[] properties) {
Criterion tagsJoinCriterion = Criterion.and( Criterion tagsJoinCriterion = Criterion.and(
Task.ID.eq(Field.field(TAGS_METADATA_JOIN + ".task"))); Task.ID.eq(Field.field(TAGS_METADATA_JOIN + ".task")));
@ -81,16 +66,6 @@ public class TaskListDataProvider {
} }
sqlQueryTemplate.set(groupedQuery); sqlQueryTemplate.set(groupedQuery);
// Peform query return taskDao.fetchFiltered(sqlQueryTemplate.get(), properties);
try {
return taskDao.fetchFiltered(sqlQueryTemplate.get(), properties);
} catch (SQLiteException e) {
// We don't show this error anymore--seems like this can get triggered
// by a strange bug, but there seems to not be any negative side effect.
// For now, we'll suppress the error
// See http://astrid.com/home#tags-7tsoi/task-1119pk
Timber.e(e, e.getMessage());
return null;
}
} }
} }

@ -1,7 +1,6 @@
package org.tasks.tasklist; package org.tasks.tasklist;
import android.app.Activity; import android.app.Activity;
import android.database.Cursor;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.view.ActionMode; import android.support.v7.view.ActionMode;
@ -105,9 +104,7 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder> im
@Override @Override
public void onBindViewHolder(ViewHolder holder, int position) { public void onBindViewHolder(ViewHolder holder, int position) {
Cursor cursor = adapter.getCursor(); holder.bindView(adapter.getTask(position));
cursor.moveToPosition(position);
holder.bindView(cursor);
holder.setMoving(false); holder.setMoving(false);
holder.setIndent(adapter.getIndent(holder.task)); holder.setIndent(adapter.getIndent(holder.task));
} }

@ -3,7 +3,6 @@ package org.tasks.tasklist;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import android.graphics.Paint; import android.graphics.Paint;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.text.SpannableString; import android.text.SpannableString;
@ -20,7 +19,6 @@ import com.bignerdranch.android.multiselector.MultiSelector;
import com.bignerdranch.android.multiselector.MultiSelectorBindingHolder; import com.bignerdranch.android.multiselector.MultiSelectorBindingHolder;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.TaskAction; import com.todoroo.astrid.api.TaskAction;
import com.todoroo.astrid.core.LinkActionExposer; import com.todoroo.astrid.core.LinkActionExposer;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
@ -103,8 +101,6 @@ class ViewHolder extends MultiSelectorBindingHolder {
public Task task; public Task task;
private String tagsString; // From join query, not part of the task model
private boolean hasFiles; // From join query, not part of the task model
private final Context context; private final Context context;
private final CheckBoxes checkBoxes; private final CheckBoxes checkBoxes;
private final TagFormatter tagFormatter; private final TagFormatter tagFormatter;
@ -191,12 +187,9 @@ class ViewHolder extends MultiSelectorBindingHolder {
return indent > 0; return indent > 0;
} }
void bindView(Cursor cursor) { void bindView(Task task) {
tagsString = TaskAdapter.TAGS.getValue(cursor);
hasFiles = TaskAdapter.FILE_ID_PROPERTY.getValue(cursor) > 0;
// TODO: see if this is a performance issue // TODO: see if this is a performance issue
task = new Task(cursor); this.task = task;
setFieldContentsAndVisibility(); setFieldContentsAndVisibility();
setTaskAppearance(); setTaskAppearance();
@ -215,7 +208,7 @@ class ViewHolder extends MultiSelectorBindingHolder {
setupDueDateAndTags(); setupDueDateAndTags();
// Task action // Task action
TaskAction action = getTaskAction(task, hasFiles); TaskAction action = getTaskAction(task, task.hasFiles());
if (action != null) { if (action != null) {
taskActionIcon.setVisibility(View.VISIBLE); taskActionIcon.setVisibility(View.VISIBLE);
taskActionIcon.setImageResource(action.icon); taskActionIcon.setImageResource(action.icon);
@ -291,7 +284,7 @@ class ViewHolder extends MultiSelectorBindingHolder {
if (task.isCompleted()) { if (task.isCompleted()) {
tagBlock.setVisibility(View.GONE); tagBlock.setVisibility(View.GONE);
} else { } else {
String tags = tagsString; String tags = task.getTagsString();
List<String> tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.newArrayList(); List<String> tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.newArrayList();
CharSequence tagString = tagFormatter.getTagString(tagUuids); CharSequence tagString = tagFormatter.getTagString(tagUuids);

@ -4,7 +4,6 @@ import android.appwidget.AppWidgetManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Paint; import android.graphics.Paint;
import android.text.TextUtils; import android.text.TextUtils;
@ -29,6 +28,8 @@ import org.tasks.themes.ThemeCache;
import org.tasks.themes.WidgetTheme; import org.tasks.themes.WidgetTheme;
import org.tasks.ui.WidgetCheckBoxes; import org.tasks.ui.WidgetCheckBoxes;
import java.util.List;
import timber.log.Timber; import timber.log.Timber;
import static android.support.v4.content.ContextCompat.getColor; import static android.support.v4.content.ContextCompat.getColor;
@ -55,7 +56,7 @@ class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private int textColorPrimary; private int textColorPrimary;
private int textColorSecondary; private int textColorSecondary;
private Cursor cursor; private List<Task> tasks;
ScrollableViewsFactory( ScrollableViewsFactory(
SubtasksHelper subtasksHelper, SubtasksHelper subtasksHelper,
@ -85,25 +86,21 @@ class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory {
@Override @Override
public void onCreate() { public void onCreate() {
database.openForReading(); database.openForReading();
cursor = getCursor(); tasks = getTasks();
} }
@Override @Override
public void onDataSetChanged() { public void onDataSetChanged() {
if (cursor != null) { tasks = getTasks();
cursor.close();
}
cursor = getCursor();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
cursor.close();
} }
@Override @Override
public int getCount() { public int getCount() {
return cursor.getCount(); return tasks.size();
} }
@Override @Override
@ -202,18 +199,13 @@ class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory {
return null; return null;
} }
private Cursor getCursor() { private List<Task> getTasks() {
String query = getQuery(); String query = getQuery();
return taskDao.fetchFiltered(query, Task.PROPERTIES); return taskDao.fetchFiltered(query);
} }
private Task getTask(int position) { private Task getTask(int position) {
if (position < cursor.getCount()) { return position < tasks.size() ? tasks.get(position) : null;
cursor.moveToPosition(position);
return new Task(cursor);
}
Timber.w("requested task at position %s, cursor count is %s", position, cursor.getCount());
return null;
} }
private String getQuery() { private String getQuery() {

Loading…
Cancel
Save