Add 'google_tasks' table

pull/618/head
Alex Baker 8 years ago committed by Alex Baker
parent f4de1bf0df
commit 3943d620a5

@ -0,0 +1,693 @@
{
"formatVersion": 1,
"database": {
"version": 50,
"identityHash": "e08be332b5c3e35040e5fd89d68fd304",
"entities": [
{
"tableName": "notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `type` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "taskId",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"uid"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_notification_task",
"unique": true,
"columnNames": [
"task"
],
"createSql": "CREATE UNIQUE INDEX `index_notification_task` ON `${TABLE_NAME}` (`task`)"
}
],
"foreignKeys": []
},
{
"tableName": "tagdata",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `name` TEXT, `color` INTEGER, `tagOrdering` TEXT, `deleted` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "tagOrdering",
"columnName": "tagOrdering",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "userActivity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `action` TEXT, `message` TEXT, `picture` TEXT, `target_id` TEXT, `created_at` INTEGER, `deleted_at` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "action",
"columnName": "action",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "picture",
"columnName": "picture",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "targetId",
"columnName": "target_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created_at",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted_at",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "task_attachments",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `task_id` TEXT, `name` TEXT, `path` TEXT, `content_type` TEXT, `deleted_at` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskId",
"columnName": "task_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "contentType",
"columnName": "content_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted_at",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "task_list_metadata",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "tagUuid",
"columnName": "tag_uuid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "filter",
"columnName": "filter",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskIds",
"columnName": "task_ids",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "store",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `item` TEXT, `value` TEXT, `value2` TEXT, `value3` TEXT, `value4` TEXT, `deleted` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "item",
"columnName": "item",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value2",
"columnName": "value2",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value3",
"columnName": "value3",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value4",
"columnName": "value4",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "so_id",
"unique": false,
"columnNames": [
"type",
"item"
],
"createSql": "CREATE INDEX `so_id` ON `${TABLE_NAME}` (`type`, `item`)"
}
],
"foreignKeys": []
},
{
"tableName": "tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `importance` INTEGER, `dueDate` INTEGER, `hideUntil` INTEGER, `created` INTEGER, `modified` INTEGER, `completed` INTEGER, `deleted` INTEGER, `notes` TEXT, `estimatedSeconds` INTEGER, `elapsedSeconds` INTEGER, `timerStart` INTEGER, `notificationFlags` INTEGER, `notifications` INTEGER, `lastNotified` INTEGER, `snoozeTime` INTEGER, `recurrence` TEXT, `repeatUntil` INTEGER, `calendarUri` TEXT, `remoteId` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "importance",
"columnName": "importance",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "dueDate",
"columnName": "dueDate",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "hideUntil",
"columnName": "hideUntil",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "modified",
"columnName": "modified",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "completed",
"columnName": "completed",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notes",
"columnName": "notes",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "estimatedSeconds",
"columnName": "estimatedSeconds",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "elapsedSeconds",
"columnName": "elapsedSeconds",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "timerStart",
"columnName": "timerStart",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notificationFlags",
"columnName": "notificationFlags",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notifications",
"columnName": "notifications",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastNotified",
"columnName": "lastNotified",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "snoozeTime",
"columnName": "snoozeTime",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "recurrence",
"columnName": "recurrence",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "repeatUntil",
"columnName": "repeatUntil",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "calendarUri",
"columnName": "calendarUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "t_rid",
"unique": true,
"columnNames": [
"remoteId"
],
"createSql": "CREATE UNIQUE INDEX `t_rid` ON `${TABLE_NAME}` (`remoteId`)"
}
],
"foreignKeys": []
},
{
"tableName": "alarms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `time` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `radius` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "latitude",
"columnName": "latitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "longitude",
"columnName": "longitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "radius",
"columnName": "radius",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "tags",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `tag_uid` TEXT, `task_uid` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "tagUid",
"columnName": "tag_uid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskUid",
"columnName": "task_uid",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "google_tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `remote_id` TEXT, `list_id` TEXT, `parent` INTEGER NOT NULL, `indent` INTEGER NOT NULL, `order` INTEGER NOT NULL, `remote_order` INTEGER NOT NULL, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteId",
"columnName": "remote_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "listId",
"columnName": "list_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "parent",
"columnName": "parent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "indent",
"columnName": "indent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "order",
"columnName": "order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteOrder",
"columnName": "remote_order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastSync",
"columnName": "last_sync",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"e08be332b5c3e35040e5fd89d68fd304\")"
]
}
}

@ -1,5 +1,7 @@
package org.tasks.location; package org.tasks.location;
import org.tasks.data.Location;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -12,15 +14,15 @@ public class GeofenceApi {
} }
public void register(List<Geofence> activeGeofences) { public void register(List<Location> activeGeofences) {
} }
public void cancel(Geofence geofence) { public void cancel(Location geofence) {
} }
public void cancel(List<Geofence> geofences) { public void cancel(List<Location> geofences) {
} }
} }

@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import org.tasks.data.Location;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
public class PlacePicker { public class PlacePicker {
@ -11,7 +12,7 @@ public class PlacePicker {
return null; return null;
} }
public static Geofence getPlace(Context context, Intent data, Preferences preferences) { public static Location getPlace(Context context, Intent data, Preferences preferences) {
return null; return null;
} }
} }

@ -2,9 +2,7 @@ package com.todoroo.astrid.alarms;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.junit.After; import org.junit.After;
@ -12,6 +10,8 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import org.tasks.jobs.AlarmJob; import org.tasks.jobs.AlarmJob;
@ -30,7 +30,7 @@ import static org.tasks.makers.TaskMaker.newTask;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class AlarmJobServiceTest extends InjectingTestCase { public class AlarmJobServiceTest extends InjectingTestCase {
@Inject MetadataDao metadataDao; @Inject AlarmDao alarmDao;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
private AlarmService alarmService; private AlarmService alarmService;
@ -39,7 +39,7 @@ public class AlarmJobServiceTest extends InjectingTestCase {
@Before @Before
public void before() { public void before() {
jobs = mock(JobQueue.class); jobs = mock(JobQueue.class);
alarmService = new AlarmService(metadataDao, jobs); alarmService = new AlarmService(alarmDao, jobs);
} }
@After @After
@ -54,12 +54,8 @@ public class AlarmJobServiceTest extends InjectingTestCase {
taskDao.persist(task); taskDao.persist(task);
DateTime alarmTime = new DateTime(2017, 9, 24, 19, 57); DateTime alarmTime = new DateTime(2017, 9, 24, 19, 57);
Metadata alarm = new Metadata(); Alarm alarm = new Alarm(task.getId(), alarmTime.getMillis());
alarm.setTask(task.getId()); alarm.setId(alarmDao.insert(alarm));
alarm.setKey(AlarmFields.METADATA_KEY);
alarm.setValue(AlarmFields.TYPE, AlarmFields.TYPE_SINGLE);
alarm.setValue(AlarmFields.TIME, alarmTime.getMillis());
metadataDao.persist(alarm);
alarmService.scheduleAllAlarms(); alarmService.scheduleAllAlarms();
@ -75,12 +71,7 @@ public class AlarmJobServiceTest extends InjectingTestCase {
taskDao.persist(task); taskDao.persist(task);
Metadata alarm = new Metadata(); alarmDao.insert(new Alarm(task.getId(), alarmTime.getMillis()));
alarm.setTask(task.getId());
alarm.setKey(AlarmFields.METADATA_KEY);
alarm.setValue(AlarmFields.TYPE, AlarmFields.TYPE_SINGLE);
alarm.setValue(AlarmFields.TIME, alarmTime.getMillis());
metadataDao.persist(alarm);
alarmService.scheduleAllAlarms(); alarmService.scheduleAllAlarms();

@ -1,169 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.dao;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent;
import java.util.List;
import javax.inject.Inject;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@RunWith(AndroidJUnit4.class)
public class MetadataDaoTests extends InjectingTestCase {
@Inject MetadataDao metadataDao;
@Inject TaskDao taskDao;
private Metadata metadata;
public static Property<?>[] KEYS = new Property<?>[] { Metadata.ID, Metadata.KEY };
@Override
public void setUp() {
super.setUp();
metadata = new Metadata();
}
@Override
protected void inject(TestComponent component) {
component.inject(this);
}
/**
* Test basic creation, fetch, and save
*/
@Test
public void testCrud() throws Exception {
assertTrue(metadataDao.toList(Query.select(Metadata.ID)).isEmpty());
// create "happy"
Metadata metadata = new Metadata();
metadata.setTask(1L);
metadata.setKey("happy");
assertTrue(metadataDao.persist(metadata));
assertEquals(1, metadataDao.toList(Query.select(Metadata.ID)).size());
long happyId = metadata.getId();
assertNotSame(Metadata.NO_ID, happyId);
metadata = metadataDao.fetch(happyId);
assertEquals("happy", metadata.getKey());
// create "sad"
metadata = new Metadata();
metadata.setTask(1L);
metadata.setKey("sad");
assertTrue(metadataDao.persist(metadata));
assertEquals(2, metadataDao.toList(Query.select(Metadata.ID)).size());
// rename sad to melancholy
long sadId = metadata.getId();
assertNotSame(Metadata.NO_ID, sadId);
metadata.setKey("melancholy");
assertTrue(metadataDao.persist(metadata));
assertEquals(2, metadataDao.toList(Query.select(Metadata.ID)).size());
// check state
metadata = metadataDao.fetch(happyId);
assertEquals("happy", metadata.getKey());
metadata = metadataDao.fetch(sadId);
assertEquals("melancholy", metadata.getKey());
// delete sad
assertTrue(metadataDao.delete(sadId));
List<Metadata> metadataList = metadataDao.toList(Query.select(KEYS));
assertEquals(1, metadataList.size());
assertEquals("happy", metadataList.get(0).getKey());
}
/**
* Test metadata bound to task
*/
@Test
public void testMetadataConditions() {
// create "happy"
Metadata metadata = new Metadata();
metadata.setKey("with1");
metadata.setTask(1L);
assertTrue(metadataDao.persist(metadata));
metadata = new Metadata();
metadata.setKey("with2");
metadata.setTask(2L);
assertTrue(metadataDao.persist(metadata));
metadata = new Metadata();
metadata.setKey("with1");
metadata.setTask(1L);
assertTrue(metadataDao.persist(metadata));
List<Metadata> metadataList = metadataDao.toList(Query.select(KEYS).where(MetadataCriteria.byTask(1)));
assertEquals(2, metadataList.size());
assertEquals("with1", metadataList.get(0).getKey());
assertEquals("with1", metadataList.get(1).getKey());
assertTrue(metadataDao.toList(Query.select(KEYS).where(MetadataCriteria.byTask(3))).isEmpty());
assertEquals(2, metadataDao.deleteWhere(MetadataCriteria.byTask(1)));
assertEquals(1, metadataDao.toList(Query.select(KEYS)).size());
}
@Test
public void testDontSaveMetadataWithoutTaskId() {
try {
metadataDao.persist(metadata);
fail("expected exception");
} catch(IllegalArgumentException e) {
assertTrue(e.getMessage().startsWith("metadata needs to be attached to a task"));
}
}
@Test
public void testSaveMetadata() {
metadata.setTask(1L);
metadataDao.persist(metadata);
assertNotNull(metadataDao.fetch(metadata.getId()));
}
@Test
public void testDontDeleteValidMetadata() {
final Task task = new Task();
taskDao.save(task);
metadata.setTask(task.getId());
metadataDao.persist(metadata);
metadataDao.removeDanglingMetadata();
assertNotNull(metadataDao.fetch(metadata.getId()));
}
@Test
public void testDeleteDangling() {
metadata.setTask(1L);
metadataDao.persist(metadata);
metadataDao.removeDanglingMetadata();
assertNull(metadataDao.fetch(1));
}
}

@ -213,32 +213,32 @@ public class NewRepeatTests {
return new DateTime(computeNextDueDate(task, task.sanitizedRecurrence(), task.repeatAfterCompletion())); return new DateTime(computeNextDueDate(task, task.sanitizedRecurrence(), task.repeatAfterCompletion()));
} }
private Task newFromDue(Frequency frequency, int interval, DateTime dueDate) { private Task newFromDue(Frequency frequency, int interval, DateTime dueDateTime) {
return new Task() {{ return new Task() {{
setRecurrence(getRecurrenceRule(frequency, interval, false)); setRecurrence(getRecurrenceRule(frequency, interval, false));
setDueDate(dueDate.getMillis()); setDueDate(dueDateTime.getMillis());
}}; }};
} }
private Task newWeeklyFromDue(int interval, DateTime dueDate, WeekdayNum... weekdays) { private Task newWeeklyFromDue(int interval, DateTime dueDateTime, WeekdayNum... weekdays) {
return new Task() {{ return new Task() {{
setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, false, weekdays)); setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, false, weekdays));
setDueDate(dueDate.getMillis()); setDueDate(dueDateTime.getMillis());
}}; }};
} }
private Task newFromCompleted(Frequency frequency, int interval, DateTime dueDate, DateTime completionDate) { private Task newFromCompleted(Frequency frequency, int interval, DateTime dueDateTime, DateTime completionDate) {
return new Task() {{ return new Task() {{
setRecurrence(getRecurrenceRule(frequency, interval, true)); setRecurrence(getRecurrenceRule(frequency, interval, true));
setDueDate(dueDate.getMillis()); setDueDate(dueDateTime.getMillis());
setCompletionDate(completionDate.getMillis()); setCompletionDate(completionDate.getMillis());
}}; }};
} }
private Task newWeeklyFromCompleted(int interval, DateTime dueDate, DateTime completionDate, WeekdayNum... weekdays) { private Task newWeeklyFromCompleted(int interval, DateTime dueDateTime, DateTime completionDate, WeekdayNum... weekdays) {
return new Task() {{ return new Task() {{
setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, true, weekdays)); setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, true, weekdays));
setDueDate(dueDate.getMillis()); setDueDate(dueDateTime.getMillis());
setCompletionDate(completionDate.getMillis()); setCompletionDate(completionDate.getMillis());
}}; }};
} }

@ -9,7 +9,10 @@ import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskListMetadataDao; import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.dao.UserActivityDao; import com.todoroo.astrid.dao.UserActivityDao;
import org.tasks.db.Migrations; import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.LocationDao;
import org.tasks.data.TagDao;
import org.tasks.notifications.NotificationDao; import org.tasks.notifications.NotificationDao;
import org.tasks.preferences.PermissionChecker; import org.tasks.preferences.PermissionChecker;
import org.tasks.preferences.PermissivePermissionChecker; import org.tasks.preferences.PermissivePermissionChecker;
@ -30,7 +33,6 @@ public class TestModule {
public Database getDatabase() { public Database getDatabase() {
return Room.inMemoryDatabaseBuilder(context, Database.class) return Room.inMemoryDatabaseBuilder(context, Database.class)
.fallbackToDestructiveMigration() .fallbackToDestructiveMigration()
.addCallback(Migrations.ON_CREATE)
.build(); .build();
} }
@ -59,6 +61,26 @@ public class TestModule {
return database.getStoreObjectDao(); return database.getStoreObjectDao();
} }
@Provides
public AlarmDao getAlarmDao(Database database) {
return database.getAlarmDao();
}
@Provides
public GoogleTaskDao getGoogleTaskDao(Database database) {
return database.getGoogleTaskDao();
}
@Provides
public TagDao getTagDao(Database database) {
return database.getTagDao();
}
@Provides
public LocationDao getLocationDao(Database database) {
return database.getLocationDao();
}
@ApplicationScope @ApplicationScope
@Provides @Provides
@ForApplication @ForApplication

@ -8,13 +8,13 @@ package com.todoroo.astrid.gtasks;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
@ -32,9 +32,8 @@ public class GtasksIndentActionTest extends InjectingTestCase {
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject GtasksTaskListUpdater gtasksTaskListUpdater; @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
@Inject MetadataDao metadataDao;
@Inject GtasksMetadata gtasksMetadata;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject GoogleTaskDao googleTaskDao;
private Task task; private Task task;
private GtasksList storeList; private GtasksList storeList;
@ -176,12 +175,10 @@ public class GtasksIndentActionTest extends InjectingTestCase {
private Task taskWithMetadata(long order, int indentation) { private Task taskWithMetadata(long order, int indentation) {
Task newTask = new Task(); Task newTask = new Task();
taskDao.save(newTask); taskDao.save(newTask);
Metadata metadata = gtasksMetadata.createEmptyMetadata(newTask.getId()); GoogleTask metadata = new GoogleTask(newTask.getId(), "list");
metadata.setValue(GtasksMetadata.INDENT, indentation); metadata.setIndent(indentation);
metadata.setValue(GtasksMetadata.ORDER, order); metadata.setOrder(order);
metadata.setValue(GtasksMetadata.LIST_ID, "list"); googleTaskDao.insert(metadata);
metadata.setTask(newTask.getId());
metadataDao.persist(metadata);
return newTask; return newTask;
} }
@ -190,9 +187,9 @@ public class GtasksIndentActionTest extends InjectingTestCase {
} }
private void thenExpectIndentationLevel(Task targetTask, int expected) { private void thenExpectIndentationLevel(Task targetTask, int expected) {
Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(targetTask.getId(), GtasksMetadata.METADATA_KEY); GoogleTask metadata = googleTaskDao.getByTaskId(targetTask.getId());
assertNotNull("task has metadata", metadata); assertNotNull("task has metadata", metadata);
int indentation = metadata.getValue(GtasksMetadata.INDENT); int indentation = metadata.getIndent();
assertTrue("indentation: " + indentation, assertTrue("indentation: " + indentation,
indentation == expected); indentation == expected);
} }

@ -4,14 +4,13 @@ import android.support.test.runner.AndroidJUnit4;
import com.google.api.client.util.DateTime; import com.google.api.client.util.DateTime;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.service.TaskDeleter; import com.todoroo.astrid.service.TaskDeleter;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.TaskListDataProvider; import org.tasks.data.TaskListDataProvider;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
@ -35,11 +34,10 @@ import static org.tasks.time.DateTimeUtils.currentTimeMillis;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class GtasksListServiceTest extends InjectingTestCase { public class GtasksListServiceTest extends InjectingTestCase {
@Inject Database database;
@Inject TaskListDataProvider taskListDataProvider; @Inject TaskListDataProvider taskListDataProvider;
@Inject TaskDeleter taskDeleter; @Inject TaskDeleter taskDeleter;
@Inject MetadataDao metadataDao;
@Inject LocalBroadcastManager localBroadcastManager; @Inject LocalBroadcastManager localBroadcastManager;
@Inject GoogleTaskDao googleTaskDao;
@Inject StoreObjectDao storeObjectDao; @Inject StoreObjectDao storeObjectDao;
private GtasksListService gtasksListService; private GtasksListService gtasksListService;
@ -48,7 +46,7 @@ public class GtasksListServiceTest extends InjectingTestCase {
public void setUp() { public void setUp() {
super.setUp(); super.setUp();
gtasksListService = new GtasksListService(storeObjectDao, taskListDataProvider, taskDeleter, gtasksListService = new GtasksListService(storeObjectDao, taskListDataProvider, taskDeleter,
metadataDao, localBroadcastManager); localBroadcastManager, googleTaskDao);
} }
@Override @Override

@ -8,13 +8,13 @@ package com.todoroo.astrid.gtasks;
import android.content.Context; import android.content.Context;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
@ -58,12 +58,11 @@ public class GtasksMetadataServiceTest extends InjectingTestCase {
} }
@Inject GtasksTestPreferenceService preferences; @Inject GtasksTestPreferenceService preferences;
@Inject MetadataDao metadataDao;
@Inject GtasksMetadata gtasksMetadata;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject GoogleTaskDao googleTaskDao;
private Task task; private Task task;
private Metadata metadata; private GoogleTask metadata;
@Override @Override
public void setUp() { public void setUp() {
@ -110,18 +109,19 @@ public class GtasksMetadataServiceTest extends InjectingTestCase {
} }
private void whenSearchForMetadata() { private void whenSearchForMetadata() {
metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY); metadata = googleTaskDao.getByTaskId(task.getId());
} }
private Task taskWithMetadata(String id) { private Task taskWithMetadata(String id) {
Task task = new Task(); Task task = new Task();
task.setTitle("cats"); task.setTitle("cats");
taskDao.save(task); taskDao.save(task);
Metadata metadata = gtasksMetadata.createEmptyMetadata(task.getId()); GoogleTask metadata = new GoogleTask(task.getId(), "");
if (id != null) if (id != null) {
metadata.setValue(GtasksMetadata.ID, id); metadata.setRemoteId(id);
}
metadata.setTask(task.getId()); metadata.setTask(task.getId());
metadataDao.persist(metadata); googleTaskDao.insert(metadata);
return task; return task;
} }

@ -8,14 +8,14 @@ package com.todoroo.astrid.gtasks;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
@ -35,9 +35,8 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
@Inject GtasksTaskListUpdater gtasksTaskListUpdater; @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject MetadataDao metadataDao;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject GtasksMetadata gtasksMetadata; @Inject GoogleTaskDao googleTaskDao;
@Test @Test
public void testBasicParentComputation() { public void testBasicParentComputation() {
@ -102,15 +101,15 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
// --- helpers // --- helpers
private void thenExpectMetadataIndentAndOrder(Task task, long order, int indent) { private void thenExpectMetadataIndentAndOrder(Task task, long order, int indent) {
Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY); GoogleTask metadata = googleTaskDao.getByTaskId(task.getId());
assertNotNull("metadata was found", metadata); assertNotNull("metadata was found", metadata);
assertEquals("order", order, metadata.getValue(GtasksMetadata.ORDER).longValue()); assertEquals("order", order, metadata.getOrder());
assertEquals("indentation", indent, (int)metadata.getValue(GtasksMetadata.INDENT)); assertEquals("indentation", indent, metadata.getIndent());
} }
private void thenExpectMetadataParent(Task task, Task expectedParent) { private void thenExpectMetadataParent(Task task, Task expectedParent) {
Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY); GoogleTask metadata = googleTaskDao.getByTaskId(task.getId());
long parent = metadata.getValue(GtasksMetadata.PARENT_TASK); long parent = metadata.getParent();
if(expectedParent == null) if(expectedParent == null)
assertEquals("Task " + task.getTitle() + " parent none", 0, parent); assertEquals("Task " + task.getTitle() + " parent none", 0, parent);
else else
@ -185,13 +184,14 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase {
Task task = new Task(); Task task = new Task();
task.setTitle(title); task.setTitle(title);
taskDao.save(task); taskDao.save(task);
Metadata metadata = gtasksMetadata.createEmptyMetadata(task.getId()); GoogleTask metadata = new GoogleTask(task.getId(), "1");
metadata.setValue(GtasksMetadata.LIST_ID, "1"); if(order != VALUE_UNSET) {
if(order != VALUE_UNSET) metadata.setOrder(order);
metadata.setValue(GtasksMetadata.ORDER, order); }
if(indent != VALUE_UNSET) if(indent != VALUE_UNSET) {
metadata.setValue(GtasksMetadata.INDENT, indent); metadata.setIndent(indent);
metadataDao.persist(metadata); }
googleTaskDao.insert(metadata);
return task; return task;
} }
} }

@ -8,13 +8,13 @@ package com.todoroo.astrid.gtasks;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent; import org.tasks.injection.TestComponent;
@ -34,9 +34,8 @@ public class GtasksTaskMovingTest extends InjectingTestCase {
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject GtasksTaskListUpdater gtasksTaskListUpdater; @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
@Inject MetadataDao metadataDao;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject GtasksMetadata gtasksMetadata; @Inject GoogleTaskDao googleTaskDao;
private Task A, B, C, D, E, F; private Task A, B, C, D, E, F;
private GtasksList list; private GtasksList list;
@ -255,10 +254,10 @@ public class GtasksTaskMovingTest extends InjectingTestCase {
} }
private void thenExpectMetadataOrderAndIndent(Task task, long order, int indent) { private void thenExpectMetadataOrderAndIndent(Task task, long order, int indent) {
Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY); GoogleTask metadata = googleTaskDao.getByTaskId(task.getId());
assertNotNull("metadata was found", metadata); assertNotNull("metadata was found", metadata);
assertEquals("order", order, metadata.getValue(GtasksMetadata.ORDER).longValue()); assertEquals("order", order, metadata.getOrder());
assertEquals("indentation", indent, (int)metadata.getValue(GtasksMetadata.INDENT)); assertEquals("indentation", indent, metadata.getIndent());
} }
@Override @Override
@ -301,13 +300,14 @@ public class GtasksTaskMovingTest extends InjectingTestCase {
Task task = new Task(); Task task = new Task();
task.setTitle(title); task.setTitle(title);
taskDao.save(task); taskDao.save(task);
Metadata metadata = gtasksMetadata.createEmptyMetadata(task.getId()); GoogleTask metadata = new GoogleTask(task.getId(), "1");
metadata.setValue(GtasksMetadata.LIST_ID, "1"); if(order != VALUE_UNSET) {
if(order != VALUE_UNSET) metadata.setOrder(order);
metadata.setValue(GtasksMetadata.ORDER, order); }
if(indent != VALUE_UNSET) if(indent != VALUE_UNSET) {
metadata.setValue(GtasksMetadata.INDENT, indent); metadata.setIndent(indent);
metadataDao.persist(metadata); }
googleTaskDao.insert(metadata);
return task; return task;
} }
} }

@ -1,7 +1,6 @@
package org.tasks.injection; package org.tasks.injection;
import com.todoroo.astrid.alarms.AlarmJobServiceTest; import com.todoroo.astrid.alarms.AlarmJobServiceTest;
import com.todoroo.astrid.dao.MetadataDaoTests;
import com.todoroo.astrid.dao.TaskDaoTests; import com.todoroo.astrid.dao.TaskDaoTests;
import com.todoroo.astrid.gtasks.GtasksIndentActionTest; import com.todoroo.astrid.gtasks.GtasksIndentActionTest;
import com.todoroo.astrid.gtasks.GtasksListServiceTest; import com.todoroo.astrid.gtasks.GtasksListServiceTest;
@ -42,8 +41,6 @@ public interface TestComponent {
void inject(TaskDaoTests taskDaoTests); void inject(TaskDaoTests taskDaoTests);
void inject(MetadataDaoTests metadataDaoTests);
void inject(NewSyncTestCase newSyncTestCase); void inject(NewSyncTestCase newSyncTestCase);
void inject(SubtasksTestCase subtasksTestCase); void inject(SubtasksTestCase subtasksTestCase);

@ -1,5 +1,7 @@
package org.tasks.location; package org.tasks.location;
import org.tasks.data.Location;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -12,15 +14,15 @@ public class GeofenceApi {
} }
public void register(List<Geofence> activeGeofences) { public void register(List<Location> activeGeofences) {
} }
public void cancel(Geofence geofence) { public void cancel(Location geofence) {
} }
public void cancel(List<Geofence> geofences) { public void cancel(List<Location> geofences) {
} }
} }

@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import org.tasks.data.Location;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
public class PlacePicker { public class PlacePicker {
@ -11,7 +12,7 @@ public class PlacePicker {
return null; return null;
} }
public static Geofence getPlace(Context context, Intent data, Preferences preferences) { public static Location getPlace(Context context, Intent data, Preferences preferences) {
return null; return null;
} }
} }

@ -7,12 +7,12 @@ package com.todoroo.astrid.gtasks;
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.api.GtasksFilter;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskDeleter; import com.todoroo.astrid.service.TaskDeleter;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.TaskListDataProvider; import org.tasks.data.TaskListDataProvider;
import java.util.HashSet; import java.util.HashSet;
@ -32,18 +32,18 @@ public class GtasksListService {
private final StoreObjectDao storeObjectDao; private final StoreObjectDao storeObjectDao;
private final TaskListDataProvider taskListDataProvider; private final TaskListDataProvider taskListDataProvider;
private final TaskDeleter taskDeleter; private final TaskDeleter taskDeleter;
private final MetadataDao metadataDao;
private LocalBroadcastManager localBroadcastManager; private LocalBroadcastManager localBroadcastManager;
private final GoogleTaskDao googleTaskDao;
@Inject @Inject
public GtasksListService(StoreObjectDao storeObjectDao, TaskListDataProvider taskListDataProvider, public GtasksListService(StoreObjectDao storeObjectDao, TaskListDataProvider taskListDataProvider,
TaskDeleter taskDeleter, MetadataDao metadataDao, TaskDeleter taskDeleter, LocalBroadcastManager localBroadcastManager,
LocalBroadcastManager localBroadcastManager) { GoogleTaskDao googleTaskDao) {
this.storeObjectDao = storeObjectDao; this.storeObjectDao = storeObjectDao;
this.taskListDataProvider = taskListDataProvider; this.taskListDataProvider = taskListDataProvider;
this.taskDeleter = taskDeleter; this.taskDeleter = taskDeleter;
this.metadataDao = metadataDao;
this.localBroadcastManager = localBroadcastManager; this.localBroadcastManager = localBroadcastManager;
this.googleTaskDao = googleTaskDao;
} }
public List<GtasksList> getLists() { public List<GtasksList> getLists() {
@ -104,10 +104,9 @@ public class GtasksListService {
.constructCursor(new GtasksFilter(gtasksList), Task.PROPERTIES) .constructCursor(new GtasksFilter(gtasksList), Task.PROPERTIES)
.toList(); .toList();
for (Task task : tasks) { for (Task task : tasks) {
metadataDao.deleteWhere(MetadataDao.MetadataCriteria
.byTaskAndwithKey(task.getId(), GtasksMetadata.METADATA_KEY));
taskDeleter.delete(task); taskDeleter.delete(task);
} }
googleTaskDao.deleteList(gtasksList.getRemoteId());
storeObjectDao.delete(gtasksList.getId()); storeObjectDao.delete(gtasksList.getId());
} }

@ -12,13 +12,12 @@ import android.preference.Preference;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity;
import org.tasks.R; import org.tasks.R;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.analytics.Tracking; import org.tasks.analytics.Tracking;
import org.tasks.data.GoogleTaskDao;
import org.tasks.dialogs.DialogBuilder; import org.tasks.dialogs.DialogBuilder;
import org.tasks.gtasks.GoogleTaskListSelectionHandler; import org.tasks.gtasks.GoogleTaskListSelectionHandler;
import org.tasks.gtasks.PlayServicesAvailability; import org.tasks.gtasks.PlayServicesAvailability;
@ -46,7 +45,7 @@ public class GtasksPreferences extends InjectingPreferenceActivity implements Go
@Inject SyncAdapterHelper syncAdapterHelper; @Inject SyncAdapterHelper syncAdapterHelper;
@Inject PlayServicesAvailability playServicesAvailability; @Inject PlayServicesAvailability playServicesAvailability;
@Inject DialogBuilder dialogBuilder; @Inject DialogBuilder dialogBuilder;
@Inject MetadataDao metadataDao; @Inject GoogleTaskDao googleTaskDao;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -85,7 +84,7 @@ public class GtasksPreferences extends InjectingPreferenceActivity implements Go
.setPositiveButton(android.R.string.ok, (dialog, which) -> { .setPositiveButton(android.R.string.ok, (dialog, which) -> {
gtasksPreferenceService.clearLastSyncDate(); gtasksPreferenceService.clearLastSyncDate();
gtasksPreferenceService.setUserName(null); gtasksPreferenceService.setUserName(null);
metadataDao.deleteWhere(Metadata.KEY.eq(GtasksMetadata.METADATA_KEY)); googleTaskDao.deleteAll();
syncAdapterHelper.enableSynchronization(false); syncAdapterHelper.enableSynchronization(false);
tracker.reportEvent(Tracking.Events.GTASK_LOGOUT); tracker.reportEvent(Tracking.Events.GTASK_LOGOUT);
gtaskPreference.setChecked(false); gtaskPreference.setChecked(false);

@ -16,6 +16,7 @@ import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.api.GtasksFilter;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.data.GoogleTask;
import org.tasks.injection.ForApplication; 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;
@ -56,8 +57,8 @@ public class GtasksSubtaskListFragment extends GtasksListFragment {
public Property<?>[] taskProperties() { public Property<?>[] taskProperties() {
Property<?>[] baseProperties = TaskAdapter.PROPERTIES; Property<?>[] baseProperties = TaskAdapter.PROPERTIES;
ArrayList<Property<?>> properties = new ArrayList<>(Arrays.asList(baseProperties)); ArrayList<Property<?>> properties = new ArrayList<>(Arrays.asList(baseProperties));
properties.add(GtasksMetadata.INDENT); properties.add(GoogleTask.INDENT);
properties.add(GtasksMetadata.ORDER); properties.add(GoogleTask.ORDER);
return properties.toArray(new Property<?>[properties.size()]); return properties.toArray(new Property<?>[properties.size()]);
} }

@ -5,17 +5,13 @@
*/ */
package com.todoroo.astrid.gtasks; package com.todoroo.astrid.gtasks;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.api.GtasksFilter;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.sync.GtasksSyncService; import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.injection.ApplicationScope; import org.tasks.injection.ApplicationScope;
import java.util.ArrayList; import java.util.ArrayList;
@ -41,12 +37,12 @@ public class GtasksTaskListUpdater {
final HashMap<Long, Long> siblings = new HashMap<>(); final HashMap<Long, Long> siblings = new HashMap<>();
private final GtasksSyncService gtasksSyncService; private final GtasksSyncService gtasksSyncService;
private final MetadataDao metadataDao; private final GoogleTaskDao googleTaskDao;
@Inject @Inject
public GtasksTaskListUpdater(GtasksSyncService gtasksSyncService, MetadataDao metadataDao) { public GtasksTaskListUpdater(GtasksSyncService gtasksSyncService, GoogleTaskDao googleTaskDao) {
this.gtasksSyncService = gtasksSyncService; this.gtasksSyncService = gtasksSyncService;
this.metadataDao = metadataDao; this.googleTaskDao = googleTaskDao;
} }
public void initialize(Filter filter) { public void initialize(Filter filter) {
@ -56,14 +52,8 @@ public class GtasksTaskListUpdater {
// --- overrides // --- overrides
Metadata getTaskMetadata(long taskId) { GoogleTask getTaskMetadata(long taskId) {
return metadataDao.getFirstActiveByTaskAndKey(taskId, GtasksMetadata.METADATA_KEY); return googleTaskDao.getByTaskId(taskId);
}
private Metadata createEmptyMetadata(GtasksList list, long taskId) {
Metadata metadata = GtasksMetadata.createEmptyMetadataWithoutList(taskId);
metadata.setValue(GtasksMetadata.LIST_ID, list.getRemoteId());
return metadata;
} }
private void iterateThroughList(GtasksList list, OrderedListIterator iterator) { private void iterateThroughList(GtasksList list, OrderedListIterator iterator) {
@ -71,8 +61,8 @@ public class GtasksTaskListUpdater {
gtasksSyncService.iterateThroughList(listId, iterator, 0, false); gtasksSyncService.iterateThroughList(listId, iterator, 0, false);
} }
private void onMovedOrIndented(Metadata metadata) { private void onMovedOrIndented(GoogleTask googleTask) {
gtasksSyncService.triggerMoveForMetadata(metadata); gtasksSyncService.triggerMoveForMetadata(googleTask);
} }
// --- used during synchronization // --- used during synchronization
@ -83,16 +73,11 @@ public class GtasksTaskListUpdater {
} }
private void orderAndIndentHelper(final String listId, final AtomicLong order, final long parent, final int indentLevel, final Set<Long> alreadyChecked) { private void orderAndIndentHelper(final String listId, final AtomicLong order, final long parent, final int indentLevel, final Set<Long> alreadyChecked) {
Query query = Query.select(Metadata.PROPERTIES).where(Criterion.and( for (GoogleTask curr : googleTaskDao.byRemoteOrder(listId, parent)) {
Metadata.KEY.eq(GtasksMetadata.METADATA_KEY),
GtasksMetadata.LIST_ID.eq(listId),
GtasksMetadata.PARENT_TASK.eq(parent)))
.orderBy(Order.asc(Functions.cast(GtasksMetadata.GTASKS_ORDER, "INTEGER")));
for (Metadata curr : metadataDao.toList(query)) {
if (!alreadyChecked.contains(curr.getTask())) { if (!alreadyChecked.contains(curr.getTask())) {
curr.setValue(GtasksMetadata.INDENT, indentLevel); curr.setIndent(indentLevel);
curr.setValue(GtasksMetadata.ORDER, order.getAndIncrement()); curr.setOrder(order.getAndIncrement());
metadataDao.saveExisting(curr); googleTaskDao.update(curr);
alreadyChecked.add(curr.getTask()); alreadyChecked.add(curr.getTask());
orderAndIndentHelper(listId, order, curr.getTask(), indentLevel + 1, alreadyChecked); orderAndIndentHelper(listId, order, curr.getTask(), indentLevel + 1, alreadyChecked);
@ -105,7 +90,7 @@ public class GtasksTaskListUpdater {
final AtomicInteger previousIndent = new AtomicInteger(-1); final AtomicInteger previousIndent = new AtomicInteger(-1);
iterateThroughList(list, (taskId, metadata) -> { iterateThroughList(list, (taskId, metadata) -> {
int indent = metadata.getValue(GtasksMetadata.INDENT); int indent = metadata.getIndent();
try { try {
long parent, sibling; long parent, sibling;
@ -139,7 +124,7 @@ public class GtasksTaskListUpdater {
} }
public interface OrderedListIterator { public interface OrderedListIterator {
void processTask(long taskId, Metadata metadata); void processTask(long taskId, GoogleTask googleTask);
} }
/** /**
@ -157,49 +142,40 @@ public class GtasksTaskListUpdater {
final AtomicLong previousTask = new AtomicLong(Task.NO_ID); final AtomicLong previousTask = new AtomicLong(Task.NO_ID);
final AtomicLong globalOrder = new AtomicLong(-1); final AtomicLong globalOrder = new AtomicLong(-1);
iterateThroughList(list, (taskId, metadata) -> { iterateThroughList(list, (taskId, googleTask) -> {
if(!metadata.isSaved()) { int indent = googleTask.getIndent();
metadata = createEmptyMetadata(list, taskId);
}
int indent = metadata.containsNonNullValue(GtasksMetadata.INDENT) ?
metadata.getValue(GtasksMetadata.INDENT) : 0;
long order = globalOrder.incrementAndGet(); long order = globalOrder.incrementAndGet();
metadata.setValue(GtasksMetadata.ORDER, order); googleTask.setOrder(order);
if(targetTaskId == taskId) { if(targetTaskId == taskId) {
// if indenting is warranted, indent me and my children // if indenting is warranted, indent me and my children
if(indent + delta <= previousIndent.get() + 1 && indent + delta >= 0) { if(indent + delta <= previousIndent.get() + 1 && indent + delta >= 0) {
targetTaskIndent.set(indent); targetTaskIndent.set(indent);
metadata.setValue(GtasksMetadata.INDENT, indent + delta); googleTask.setIndent(indent + delta);
if(GtasksMetadata.PARENT_TASK != null) { long newParent = computeNewParent(list, taskId, indent + delta - 1);
long newParent = computeNewParent(list, if (newParent == taskId) {
taskId, indent + delta - 1); googleTask.setParent(Task.NO_ID);
if (newParent == taskId) { } else {
metadata.setValue(GtasksMetadata.PARENT_TASK, Task.NO_ID); googleTask.setParent(newParent);
} else {
metadata.setValue(GtasksMetadata.PARENT_TASK, newParent);
}
} }
saveAndUpdateModifiedDate(metadata); saveAndUpdateModifiedDate(googleTask);
} }
} else if(targetTaskIndent.get() > -1) { } else if(targetTaskIndent.get() > -1) {
// found first task that is not beneath target // found first task that is not beneath target
if(indent <= targetTaskIndent.get()) { if(indent <= targetTaskIndent.get()) {
targetTaskIndent.set(-1); targetTaskIndent.set(-1);
} else { } else {
metadata.setValue(GtasksMetadata.INDENT, indent + delta); googleTask.setIndent(indent + delta);
saveAndUpdateModifiedDate(metadata); saveAndUpdateModifiedDate(googleTask);
} }
} else { } else {
previousIndent.set(indent); previousIndent.set(indent);
previousTask.set(taskId); previousTask.set(taskId);
} }
if(!metadata.isSaved()) { saveAndUpdateModifiedDate(googleTask);
saveAndUpdateModifiedDate(metadata);
}
}); });
onMovedOrIndented(getTaskMetadata(targetTaskId)); onMovedOrIndented(getTaskMetadata(targetTaskId));
} }
@ -214,12 +190,12 @@ public class GtasksTaskListUpdater {
final AtomicLong lastPotentialParent = new AtomicLong(Task.NO_ID); final AtomicLong lastPotentialParent = new AtomicLong(Task.NO_ID);
final AtomicBoolean computedParent = new AtomicBoolean(false); final AtomicBoolean computedParent = new AtomicBoolean(false);
iterateThroughList(list, (taskId, metadata) -> { iterateThroughList(list, (taskId, googleTask) -> {
if (targetTask.get() == taskId) { if (targetTask.get() == taskId) {
computedParent.set(true); computedParent.set(true);
} }
int indent = metadata.getValue(GtasksMetadata.INDENT); int indent = googleTask.getIndent();
if (!computedParent.get() && indent == desiredParentIndent.get()) { if (!computedParent.get() && indent == desiredParentIndent.get()) {
lastPotentialParent.set(taskId); lastPotentialParent.set(taskId);
} }
@ -295,21 +271,20 @@ public class GtasksTaskListUpdater {
private void traverseTreeAndWriteValues(GtasksList list, Node node, AtomicLong order, int indent) { private void traverseTreeAndWriteValues(GtasksList list, Node node, AtomicLong order, int indent) {
if(node.taskId != Task.NO_ID) { if(node.taskId != Task.NO_ID) {
Metadata metadata = getTaskMetadata(node.taskId); GoogleTask googleTask = getTaskMetadata(node.taskId);
if(metadata == null) { if(googleTask == null) {
metadata = createEmptyMetadata(list, node.taskId); googleTask = new GoogleTask(node.taskId, list.getRemoteId());
} }
metadata.setValue(GtasksMetadata.ORDER, order.getAndIncrement()); googleTask.setOrder(order.getAndIncrement());
metadata.setValue(GtasksMetadata.INDENT, indent); googleTask.setIndent(indent);
boolean parentChanged = false; boolean parentChanged = false;
if(GtasksMetadata.PARENT_TASK != null && metadata.getValue(GtasksMetadata.PARENT_TASK) != if(googleTask.getParent() != node.parent.taskId) {
node.parent.taskId) {
parentChanged = true; parentChanged = true;
metadata.setValue(GtasksMetadata.PARENT_TASK, node.parent.taskId); googleTask.setParent(node.parent.taskId);
} }
saveAndUpdateModifiedDate(metadata); saveAndUpdateModifiedDate(googleTask);
if(parentChanged) { if(parentChanged) {
onMovedOrIndented(metadata); onMovedOrIndented(googleTask);
} }
} }
@ -336,8 +311,8 @@ public class GtasksTaskListUpdater {
final AtomicInteger previoustIndent = new AtomicInteger(-1); final AtomicInteger previoustIndent = new AtomicInteger(-1);
final AtomicReference<Node> currentNode = new AtomicReference<>(root); final AtomicReference<Node> currentNode = new AtomicReference<>(root);
iterateThroughList(list, (taskId, metadata) -> { iterateThroughList(list, (taskId, googleTask) -> {
int indent = metadata.getValue(GtasksMetadata.INDENT); int indent = googleTask.getIndent();
int previousIndentValue = previoustIndent.get(); int previousIndentValue = previoustIndent.get();
if(indent == previousIndentValue) { // sibling if(indent == previousIndentValue) { // sibling
@ -366,11 +341,8 @@ public class GtasksTaskListUpdater {
return root; return root;
} }
private void saveAndUpdateModifiedDate(Metadata metadata) { private void saveAndUpdateModifiedDate(GoogleTask googleTask) {
if(metadata.getSetValues().size() == 0) { googleTaskDao.update(googleTask);
return;
}
metadataDao.persist(metadata);
} }
// --- task cascading operations // --- task cascading operations

@ -14,11 +14,12 @@ import com.todoroo.andlib.utility.DateUtilities;
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.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -31,19 +32,19 @@ import timber.log.Timber;
class OrderedMetadataListFragmentHelper { class OrderedMetadataListFragmentHelper {
private final GtasksTaskListUpdater updater; private final GtasksTaskListUpdater updater;
private final GoogleTaskDao googleTaskDao;
private final TaskDao taskDao; private final TaskDao taskDao;
private final MetadataDao metadataDao;
private DraggableTaskAdapter taskAdapter; private DraggableTaskAdapter taskAdapter;
private TaskListFragment fragment; private TaskListFragment fragment;
private GtasksList list; private GtasksList list;
@Inject @Inject
OrderedMetadataListFragmentHelper(TaskDao taskDao, MetadataDao metadataDao, GtasksTaskListUpdater updater) { OrderedMetadataListFragmentHelper(TaskDao taskDao, GtasksTaskListUpdater updater, GoogleTaskDao googleTaskDao) {
this.taskDao = taskDao; this.taskDao = taskDao;
this.metadataDao = metadataDao;
this.updater = updater; this.updater = updater;
this.googleTaskDao = googleTaskDao;
} }
void setTaskListFragment(TaskListFragment fragment) { void setTaskListFragment(TaskListFragment fragment) {
@ -70,13 +71,13 @@ class OrderedMetadataListFragmentHelper {
@Override @Override
public int getIndent(Task task) { public int getIndent(Task task) {
return task.getValue(GtasksMetadata.INDENT); return task.getValue(GoogleTask.INDENT);
} }
@Override @Override
public boolean canIndent(int position, Task task) { public boolean canIndent(int position, Task task) {
Task parent = taskAdapter.getTask(position - 1); Task parent = taskAdapter.getTask(position - 1);
return parent != null && getIndent(task) <= parent.getValue(GtasksMetadata.INDENT); return parent != null && getIndent(task) <= parent.getValue(GoogleTask.INDENT);
} }
@Override @Override
@ -144,13 +145,13 @@ class OrderedMetadataListFragmentHelper {
} }
final ArrayList<Long> chained = new ArrayList<>(); final ArrayList<Long> chained = new ArrayList<>();
final int parentIndent = item.getValue(GtasksMetadata.INDENT); final int parentIndent = item.getValue(GoogleTask.INDENT);
updater.applyToChildren(list, itemId, node -> { updater.applyToChildren(list, itemId, node -> {
Task childTask = taskDao.fetch(node.taskId); Task childTask = taskDao.fetch(node.taskId);
if(!TextUtils.isEmpty(childTask.getRecurrence())) { if(!TextUtils.isEmpty(childTask.getRecurrence())) {
Metadata metadata = updater.getTaskMetadata(node.taskId); GoogleTask googleTask = updater.getTaskMetadata(node.taskId);
metadata.setValue(GtasksMetadata.INDENT, parentIndent); googleTask.setIndent(parentIndent);
metadataDao.persist(metadata); googleTaskDao.update(googleTask);
} }
model.setId(node.taskId); model.setId(node.taskId);

@ -8,28 +8,22 @@ package com.todoroo.astrid.gtasks.sync;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.GtasksTaskListUpdater; import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
import com.todoroo.astrid.gtasks.api.GtasksInvoker; import com.todoroo.astrid.gtasks.api.GtasksInvoker;
import com.todoroo.astrid.gtasks.api.MoveRequest; import com.todoroo.astrid.gtasks.api.MoveRequest;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.gtasks.SyncAdapterHelper; import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.injection.ApplicationScope; import org.tasks.injection.ApplicationScope;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@ -42,25 +36,26 @@ import timber.log.Timber;
@ApplicationScope @ApplicationScope
public class GtasksSyncService { public class GtasksSyncService {
private final MetadataDao metadataDao;
private final TaskDao taskDao; private final TaskDao taskDao;
private final GtasksPreferenceService gtasksPreferenceService; private final GtasksPreferenceService gtasksPreferenceService;
private final GtasksInvoker gtasksInvoker; private final GtasksInvoker gtasksInvoker;
private final LinkedBlockingQueue<SyncOnSaveOperation> operationQueue = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue<SyncOnSaveOperation> operationQueue = new LinkedBlockingQueue<>();
private final SyncAdapterHelper syncAdapterHelper; private final SyncAdapterHelper syncAdapterHelper;
private final Tracker tracker; private final Tracker tracker;
private final GoogleTaskDao googleTaskDao;
@Inject @Inject
public GtasksSyncService(MetadataDao metadataDao, TaskDao taskDao, public GtasksSyncService(TaskDao taskDao,
GtasksPreferenceService gtasksPreferenceService, GtasksPreferenceService gtasksPreferenceService,
GtasksInvoker gtasksInvoker, GtasksInvoker gtasksInvoker,
SyncAdapterHelper syncAdapterHelper, Tracker tracker) { SyncAdapterHelper syncAdapterHelper, Tracker tracker,
this.metadataDao = metadataDao; GoogleTaskDao googleTaskDao) {
this.taskDao = taskDao; this.taskDao = taskDao;
this.gtasksPreferenceService = gtasksPreferenceService; this.gtasksPreferenceService = gtasksPreferenceService;
this.gtasksInvoker = gtasksInvoker; this.gtasksInvoker = gtasksInvoker;
this.syncAdapterHelper = syncAdapterHelper; this.syncAdapterHelper = syncAdapterHelper;
this.tracker = tracker; this.tracker = tracker;
this.googleTaskDao = googleTaskDao;
new OperationPushThread(operationQueue).start(); new OperationPushThread(operationQueue).start();
} }
@ -69,15 +64,15 @@ public class GtasksSyncService {
} }
private class MoveOp implements SyncOnSaveOperation { private class MoveOp implements SyncOnSaveOperation {
final Metadata metadata; final GoogleTask googleTask;
public MoveOp(Metadata metadata) { public MoveOp(GoogleTask googleTask) {
this.metadata = metadata; this.googleTask = googleTask;
} }
@Override @Override
public void op(GtasksInvoker invoker) throws IOException { public void op(GtasksInvoker invoker) throws IOException {
pushMetadataOnSave(metadata, invoker); pushMetadataOnSave(googleTask, invoker);
} }
} }
@ -127,15 +122,12 @@ public class GtasksSyncService {
operationQueue.offer(new ClearOp(listId)); operationQueue.offer(new ClearOp(listId));
} }
public void triggerMoveForMetadata(final Metadata metadata) { public void triggerMoveForMetadata(final GoogleTask googleTask) {
if (metadata == null) { if (googleTask == null) {
return; return;
} }
if (metadata.checkAndClearTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC)) { if (googleTask.isSuppressSync()) {
return; googleTask.setSuppressSync(false);
}
if (!metadata.getKey().equals(GtasksMetadata.METADATA_KEY)) //Don't care about non-gtasks metadata
{
return; return;
} }
if (gtasksPreferenceService.isOngoing()) //Don't try and sync changes that occur during a normal sync if (gtasksPreferenceService.isOngoing()) //Don't try and sync changes that occur during a normal sync
@ -146,61 +138,47 @@ public class GtasksSyncService {
return; return;
} }
operationQueue.offer(new MoveOp(metadata)); operationQueue.offer(new MoveOp(googleTask));
} }
private void pushMetadataOnSave(Metadata model, GtasksInvoker invoker) throws IOException { private void pushMetadataOnSave(GoogleTask model, GtasksInvoker invoker) throws IOException {
AndroidUtilities.sleepDeep(1000L); AndroidUtilities.sleepDeep(1000L);
String taskId = model.getValue(GtasksMetadata.ID); String taskId = model.getRemoteId();
String listId = model.getValue(GtasksMetadata.LIST_ID); String listId = model.getListId();
String parent = getRemoteParentId(model); String parent = getRemoteParentId(model);
String priorSibling = getRemoteSiblingId(listId, model); String priorSibling = getRemoteSiblingId(listId, model);
MoveRequest move = new MoveRequest(invoker, taskId, listId, parent, priorSibling); MoveRequest move = new MoveRequest(invoker, taskId, listId, parent, priorSibling);
com.google.api.services.tasks.model.Task result = move.push(); com.google.api.services.tasks.model.Task result = move.push();
// Update order metadata from result // Update order googleTask from result
if (result != null) { if (result != null) {
model.setValue(GtasksMetadata.GTASKS_ORDER, Long.parseLong(result.getPosition())); model.setRemoteOrder(Long.parseLong(result.getPosition()));
model.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true); model.setSuppressSync(true);
metadataDao.saveExisting(model); googleTaskDao.update(model);
} }
} }
public void iterateThroughList(String listId, final GtasksTaskListUpdater.OrderedListIterator iterator, long startAtOrder, boolean reverse) { public void iterateThroughList(String listId, final GtasksTaskListUpdater.OrderedListIterator iterator, long startAtOrder, boolean reverse) {
Field orderField = Functions.cast(GtasksMetadata.ORDER, "LONG"); List<GoogleTask> tasks = reverse
Order order = reverse ? Order.desc(orderField) : Order.asc(orderField); ? googleTaskDao.getTasksFromReverse(listId, startAtOrder)
Criterion startAtCriterion = reverse ? Functions.cast(GtasksMetadata.ORDER, "LONG").lt(startAtOrder) : : googleTaskDao.getTasksFrom(listId, startAtOrder);
Functions.cast(GtasksMetadata.ORDER, "LONG").gt(startAtOrder - 1); for (GoogleTask entry : tasks) {
iterator.processTask(entry.getTask(), entry);
Query query = Query.select(Metadata.PROPERTIES).where(Criterion.and(
MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY),
GtasksMetadata.LIST_ID.eq(listId),
startAtCriterion)).
orderBy(order);
for (Metadata entry : metadataDao.toList(query)) {
long taskId = entry.getValue(Metadata.TASK);
Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(taskId, GtasksMetadata.METADATA_KEY);
if(metadata != null) {
iterator.processTask(taskId, metadata);
}
} }
} }
/** /**
* Gets the remote id string of the parent task * Gets the remote id string of the parent task
*/ */
public String getRemoteParentId(Metadata gtasksMetadata) { public String getRemoteParentId(GoogleTask googleTask) {
String parent = null; String parent = null;
if (gtasksMetadata.containsNonNullValue(GtasksMetadata.PARENT_TASK)) { long parentId = googleTask.getParent();
long parentId = gtasksMetadata.getValue(GtasksMetadata.PARENT_TASK); GoogleTask parentTask = googleTaskDao.getByTaskId(parentId);
Metadata parentMetadata = metadataDao.getFirstActiveByTaskAndKey(parentId, GtasksMetadata.METADATA_KEY); if (parentTask != null) {
if (parentMetadata != null && parentMetadata.containsNonNullValue(GtasksMetadata.ID)) { parent = parentTask.getRemoteId();
parent = parentMetadata.getValue(GtasksMetadata.ID); if (TextUtils.isEmpty(parent)) {
if (TextUtils.isEmpty(parent)) { parent = null;
parent = null;
}
} }
} }
return parent; return parent;
@ -209,26 +187,26 @@ public class GtasksSyncService {
/** /**
* Gets the remote id string of the previous sibling task * Gets the remote id string of the previous sibling task
*/ */
public String getRemoteSiblingId(String listId, Metadata gtasksMetadata) { public String getRemoteSiblingId(String listId, GoogleTask gtasksMetadata) {
final AtomicInteger indentToMatch = new AtomicInteger(gtasksMetadata.getValue(GtasksMetadata.INDENT)); final AtomicInteger indentToMatch = new AtomicInteger(gtasksMetadata.getIndent());
final AtomicLong parentToMatch = new AtomicLong(gtasksMetadata.getValue(GtasksMetadata.PARENT_TASK)); final AtomicLong parentToMatch = new AtomicLong(gtasksMetadata.getParent());
final AtomicReference<String> sibling = new AtomicReference<>(); final AtomicReference<String> sibling = new AtomicReference<>();
GtasksTaskListUpdater.OrderedListIterator iterator = (taskId, metadata) -> { GtasksTaskListUpdater.OrderedListIterator iterator = (taskId, googleTask) -> {
Task t = taskDao.fetch(taskId); Task t = taskDao.fetch(taskId);
if (t == null || t.isDeleted()) { if (t == null || t.isDeleted()) {
return; return;
} }
int currIndent = metadata.getValue(GtasksMetadata.INDENT); int currIndent = googleTask.getIndent();
long currParent = metadata.getValue(GtasksMetadata.PARENT_TASK); long currParent = googleTask.getParent();
if (currIndent == indentToMatch.get() && currParent == parentToMatch.get()) { if (currIndent == indentToMatch.get() && currParent == parentToMatch.get()) {
if (sibling.get() == null) { if (sibling.get() == null) {
sibling.set(metadata.getValue(GtasksMetadata.ID)); sibling.set(googleTask.getRemoteId());
} }
} }
}; };
iterateThroughList(listId, iterator, gtasksMetadata.getValue(GtasksMetadata.ORDER), true); iterateThroughList(listId, iterator, gtasksMetadata.getOrder(), true);
return sibling.get(); return sibling.get();
} }
} }

@ -7,22 +7,22 @@ package com.todoroo.astrid.gtasks.sync;
import com.google.api.client.util.DateTime; import com.google.api.client.util.DateTime;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities; import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
import org.tasks.data.GoogleTask;
import java.util.ArrayList; import java.util.ArrayList;
public class GtasksTaskContainer { public class GtasksTaskContainer {
public final Task task; public final Task task;
public final ArrayList<Metadata> metadata; public final ArrayList<GoogleTask> metadata;
public Metadata gtaskMetadata; public GoogleTask gtaskMetadata;
private final long updateTime; private final long updateTime;
public GtasksTaskContainer(com.google.api.services.tasks.model.Task remoteTask, String listId, Metadata metadata) { public GtasksTaskContainer(com.google.api.services.tasks.model.Task remoteTask, String listId, GoogleTask metadata) {
this.task = new Task(); this.task = new Task();
this.metadata = new ArrayList<>(); this.metadata = new ArrayList<>();
this.gtaskMetadata = metadata; this.gtaskMetadata = metadata;
@ -44,8 +44,8 @@ public class GtasksTaskContainer {
task.setDueDate(createdDate); task.setDueDate(createdDate);
task.setNotes(remoteTask.getNotes()); task.setNotes(remoteTask.getNotes());
gtaskMetadata.setValue(GtasksMetadata.ID, remoteTask.getId()); gtaskMetadata.setRemoteId(remoteTask.getId());
gtaskMetadata.setValue(GtasksMetadata.LIST_ID, listId); gtaskMetadata.setListId(listId);
DateTime updated = remoteTask.getUpdated(); DateTime updated = remoteTask.getUpdated();
updateTime = updated == null ? 0 : updated.getValue(); updateTime = updated == null ? 0 : updated.getValue();

@ -31,20 +31,19 @@ import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecovera
import com.google.api.services.tasks.model.TaskList; import com.google.api.services.tasks.model.TaskList;
import com.google.api.services.tasks.model.TaskLists; import com.google.api.services.tasks.model.TaskLists;
import com.google.api.services.tasks.model.Tasks; import com.google.api.services.tasks.model.Tasks;
import com.google.common.base.Strings;
import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList; import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksListService; import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.GtasksTaskListUpdater; import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities; import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
@ -57,6 +56,8 @@ import com.todoroo.astrid.utility.Constants;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.R; import org.tasks.R;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.injection.InjectingAbstractThreadedSyncAdapter; import org.tasks.injection.InjectingAbstractThreadedSyncAdapter;
import org.tasks.injection.SyncAdapterComponent; import org.tasks.injection.SyncAdapterComponent;
import org.tasks.notifications.NotificationManager; import org.tasks.notifications.NotificationManager;
@ -66,9 +67,7 @@ import org.tasks.time.DateTime;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
@ -98,10 +97,9 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
@Inject Preferences preferences; @Inject Preferences preferences;
@Inject GtasksInvoker gtasksInvoker; @Inject GtasksInvoker gtasksInvoker;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@Inject MetadataDao metadataDao;
@Inject GtasksMetadata gtasksMetadataFactory;
@Inject Tracker tracker; @Inject Tracker tracker;
@Inject NotificationManager notificationManager; @Inject NotificationManager notificationManager;
@Inject GoogleTaskDao googleTaskDao;
public GoogleTaskSyncAdapter(Context context, boolean autoInitialize) { public GoogleTaskSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize); super(context, autoInitialize);
@ -190,8 +188,11 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
private void pushLocalChanges() throws UserRecoverableAuthIOException { private void pushLocalChanges() throws UserRecoverableAuthIOException {
List<Task> tasks = taskDao.toList(Query.select(Task.PROPERTIES) List<Task> tasks = taskDao.toList(Query.select(Task.PROPERTIES)
.join(Join.left(Metadata.TABLE, Criterion.and(MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY), Task.ID.eq(Metadata.TASK)))) .join(Join.left(GoogleTask.TABLE.as("gt"), Task.ID.eq(Field.field("gt.task"))))
.where(Criterion.or(Task.MODIFICATION_DATE.gt(GtasksMetadata.LAST_SYNC), GtasksMetadata.ID.eq(""), Metadata.ID.isNull()))); .where(Criterion.or(
Task.MODIFICATION_DATE.gt(Field.field("gt.last_sync")),
Field.field("gt.remote_id").eq(""),
Field.field("gt.remote_id").isNull())));
for (Task task : tasks) { for (Task task : tasks) {
try { try {
pushTask(task, task.getMergedValues(), gtasksInvoker); pushTask(task, task.getMergedValues(), gtasksInvoker);
@ -207,12 +208,12 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
* Synchronize with server when data changes * Synchronize with server when data changes
*/ */
private void pushTask(Task task, ContentValues values, GtasksInvoker invoker) throws IOException { private void pushTask(Task task, ContentValues values, GtasksInvoker invoker) throws IOException {
for (Metadata deleted : getDeleted(task.getId())) { for (GoogleTask deleted : googleTaskDao.getDeletedByTaskId(task.getId())) {
gtasksInvoker.deleteGtask(deleted.getValue(GtasksMetadata.LIST_ID), deleted.getValue(GtasksMetadata.ID)); gtasksInvoker.deleteGtask(deleted.getListId(), deleted.getRemoteId());
metadataDao.delete(deleted.getId()); googleTaskDao.delete(deleted);
} }
Metadata gtasksMetadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY); GoogleTask gtasksMetadata = googleTaskDao.getByTaskId(task.getId());
com.google.api.services.tasks.model.Task remoteModel; com.google.api.services.tasks.model.Task remoteModel;
boolean newlyCreated = false; boolean newlyCreated = false;
@ -228,20 +229,16 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
} }
} }
if (gtasksMetadata == null || !gtasksMetadata.containsNonNullValue(GtasksMetadata.ID) || if (gtasksMetadata == null || Strings.isNullOrEmpty(gtasksMetadata.getRemoteId())) { //Create case
TextUtils.isEmpty(gtasksMetadata.getValue(GtasksMetadata.ID))) { //Create case
if (gtasksMetadata == null) { if (gtasksMetadata == null) {
gtasksMetadata = gtasksMetadataFactory.createEmptyMetadata(task.getId()); gtasksMetadata = new GoogleTask(task.getId(), listId);
} }
if (gtasksMetadata.containsNonNullValue(GtasksMetadata.LIST_ID)) { listId = gtasksMetadata.getListId();
listId = gtasksMetadata.getValue(GtasksMetadata.LIST_ID);
}
remoteModel = new com.google.api.services.tasks.model.Task(); remoteModel = new com.google.api.services.tasks.model.Task();
newlyCreated = true; newlyCreated = true;
} else { //update case } else { //update case
remoteId = gtasksMetadata.getValue(GtasksMetadata.ID); remoteId = gtasksMetadata.getRemoteId();
listId = gtasksMetadata.getValue(GtasksMetadata.LIST_ID); listId = gtasksMetadata.getListId();
remoteModel = new com.google.api.services.tasks.model.Task(); remoteModel = new com.google.api.services.tasks.model.Task();
remoteModel.setId(remoteId); remoteModel.setId(remoteId);
} }
@ -283,7 +280,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
invoker.updateGtask(listId, remoteModel); invoker.updateGtask(listId, remoteModel);
} catch(HttpNotFoundException e) { } catch(HttpNotFoundException e) {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
metadataDao.delete(gtasksMetadata.getId()); googleTaskDao.delete(gtasksMetadata);
return; return;
} }
} else { } else {
@ -294,26 +291,20 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
if (created != null) { if (created != null) {
//Update the metadata for the newly created task //Update the metadata for the newly created task
gtasksMetadata.setValue(GtasksMetadata.ID, created.getId()); gtasksMetadata.setRemoteId(created.getId());
gtasksMetadata.setValue(GtasksMetadata.LIST_ID, listId); gtasksMetadata.setListId(listId);
} else { } else {
return; return;
} }
} }
task.setModificationDate(DateUtilities.now()); task.setModificationDate(DateUtilities.now());
gtasksMetadata.setValue(GtasksMetadata.LAST_SYNC, DateUtilities.now() + 1000L); gtasksMetadata.setLastSync(DateUtilities.now() + 1000L);
metadataDao.persist(gtasksMetadata); googleTaskDao.update(gtasksMetadata);
task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true); task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
taskDao.saveExistingWithSqlConstraintCheck(task); taskDao.saveExistingWithSqlConstraintCheck(task);
} }
private List<Metadata> getDeleted(long taskId) {
return metadataDao.toList(Criterion.and(
MetadataDao.MetadataCriteria.byTaskAndwithKey(taskId, GtasksMetadata.METADATA_KEY),
MetadataDao.MetadataCriteria.isDeleted()));
}
private synchronized void fetchAndApplyRemoteChanges(GtasksList list) throws UserRecoverableAuthIOException { private synchronized void fetchAndApplyRemoteChanges(GtasksList list) throws UserRecoverableAuthIOException {
String listId = list.getRemoteId(); String listId = list.getRemoteId();
long lastSyncDate = list.getLastSync(); long lastSyncDate = list.getLastSync();
@ -337,11 +328,11 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
if (!tasks.isEmpty()) { if (!tasks.isEmpty()) {
for (com.google.api.services.tasks.model.Task t : tasks) { for (com.google.api.services.tasks.model.Task t : tasks) {
GtasksTaskContainer container = new GtasksTaskContainer(t, listId, GtasksMetadata.createEmptyMetadataWithoutList(AbstractModel.NO_ID)); GtasksTaskContainer container = new GtasksTaskContainer(t, listId, new GoogleTask(0, ""));
findLocalMatch(container); findLocalMatch(container);
container.gtaskMetadata.setValue(GtasksMetadata.GTASKS_ORDER, Long.parseLong(t.getPosition())); container.gtaskMetadata.setRemoteOrder(Long.parseLong(t.getPosition()));
container.gtaskMetadata.setValue(GtasksMetadata.PARENT_TASK, localIdForGtasksId(t.getParent())); container.gtaskMetadata.setParent(localIdForGtasksId(t.getParent()));
container.gtaskMetadata.setValue(GtasksMetadata.LAST_SYNC, DateUtilities.now() + 1000L); container.gtaskMetadata.setLastSync(DateUtilities.now() + 1000L);
write(container); write(container);
lastSyncDate = Math.max(lastSyncDate, container.getUpdateTime()); lastSyncDate = Math.max(lastSyncDate, container.getUpdateTime());
} }
@ -357,7 +348,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
} }
private long localIdForGtasksId(String gtasksId) { private long localIdForGtasksId(String gtasksId) {
Metadata metadata = getMetadataByGtaskId(gtasksId); GoogleTask metadata = getMetadataByGtaskId(gtasksId);
return metadata == null ? AbstractModel.NO_ID : metadata.getTask(); return metadata == null ? AbstractModel.NO_ID : metadata.getTask();
} }
@ -365,18 +356,16 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
if(remoteTask.task.getId() != Task.NO_ID) { if(remoteTask.task.getId() != Task.NO_ID) {
return; return;
} }
Metadata metadata = getMetadataByGtaskId(remoteTask.gtaskMetadata.getValue(GtasksMetadata.ID)); GoogleTask googleTask = getMetadataByGtaskId(remoteTask.gtaskMetadata.getRemoteId());
if (metadata != null) { if (googleTask != null) {
remoteTask.task.setId(metadata.getValue(Metadata.TASK)); remoteTask.task.setId(googleTask.getTask());
remoteTask.task.setUuid(taskDao.uuidFromLocalId(remoteTask.task.getId())); remoteTask.task.setUuid(taskDao.uuidFromLocalId(remoteTask.task.getId()));
remoteTask.gtaskMetadata = metadata; remoteTask.gtaskMetadata = googleTask;
} }
} }
private Metadata getMetadataByGtaskId(String gtaskId) { private GoogleTask getMetadataByGtaskId(String gtaskId) {
return metadataDao.getFirst(Query.select(Metadata.PROPERTIES).where(Criterion.and( return googleTaskDao.getByRemoteId(gtaskId);
Metadata.KEY.eq(GtasksMetadata.METADATA_KEY),
GtasksMetadata.ID.eq(gtaskId))));
} }
private void write(GtasksTaskContainer task) { private void write(GtasksTaskContainer task) {
@ -408,7 +397,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
private void saveTaskAndMetadata(GtasksTaskContainer task) { private void saveTaskAndMetadata(GtasksTaskContainer task) {
task.prepareForSaving(); task.prepareForSaving();
taskDao.save(task.task); taskDao.save(task.task);
synchronizeMetadata(task.task.getId(), task.metadata, GtasksMetadata.METADATA_KEY); synchronizeMetadata(task.task.getId(), task.metadata);
} }
/** /**
@ -418,35 +407,30 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
* *
* @param taskId id of task to perform synchronization on * @param taskId id of task to perform synchronization on
* @param metadata list of new metadata items to save * @param metadata list of new metadata items to save
* @param metadataKey metadata key
*/ */
private void synchronizeMetadata(long taskId, ArrayList<Metadata> metadata, String metadataKey) { private void synchronizeMetadata(long taskId, ArrayList<GoogleTask> metadata) {
final Set<ContentValues> newMetadataValues = new HashSet<>(); for(GoogleTask metadatum : metadata) {
for(Metadata metadatum : metadata) {
metadatum.setTask(taskId); metadatum.setTask(taskId);
metadatum.clearValue(Metadata.ID); metadatum.setId(0);
newMetadataValues.add(metadatum.getMergedValues());
} }
for (Metadata item : metadataDao.byTaskAndKey(taskId, metadataKey)) { for (GoogleTask item : googleTaskDao.getAllByTaskId(taskId)) {
long id = item.getId(); long id = item.getId();
// clear item id when matching with incoming values // clear item id when matching with incoming values
item.clearValue(Metadata.ID); item.setId(0);
ContentValues itemMergedValues = item.getMergedValues(); if(metadata.contains(item)) {
if(newMetadataValues.contains(itemMergedValues)) { metadata.remove(item);
newMetadataValues.remove(itemMergedValues);
} else { } else {
// not matched. cut it // not matched. cut it
metadataDao.delete(id); item.setId(id);
googleTaskDao.delete(item);
} }
} }
// everything that remains shall be written // everything that remains shall be written
for(ContentValues values : newMetadataValues) { for(GoogleTask values : metadata) {
Metadata item = new Metadata(); googleTaskDao.insert(values);
item.mergeWith(values);
metadataDao.persist(item);
} }
} }

@ -7,20 +7,18 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.StoreObject; import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList; import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksListService; import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import org.tasks.R; import org.tasks.R;
import org.tasks.activities.SupportGoogleTaskListPicker;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.analytics.Tracking; import org.tasks.analytics.Tracking;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.injection.FragmentComponent; import org.tasks.injection.FragmentComponent;
import javax.inject.Inject; import javax.inject.Inject;
@ -44,7 +42,7 @@ public class GoogleTaskListFragment extends TaskEditControlFragment {
@Inject GtasksPreferenceService gtasksPreferenceService; @Inject GtasksPreferenceService gtasksPreferenceService;
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject MetadataDao metadataDao; @Inject GoogleTaskDao googleTaskDao;
@Inject Tracker tracker; @Inject Tracker tracker;
private long taskId; private long taskId;
@ -67,9 +65,9 @@ public class GoogleTaskListFragment extends TaskEditControlFragment {
selectedList = new GtasksList(selectedStoreObject); selectedList = new GtasksList(selectedStoreObject);
} }
} else { } else {
Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(taskId, GtasksMetadata.METADATA_KEY); GoogleTask googleTask = googleTaskDao.getByTaskId(taskId);
if (metadata != null) { if (googleTask != null) {
originalList = gtasksListService.getList(metadata.getValue(GtasksMetadata.LIST_ID)); originalList = gtasksListService.getList(googleTask.getListId());
} }
if (originalList == null) { if (originalList == null) {
originalList = gtasksListService.getList(gtasksPreferenceService.getDefaultList()); originalList = gtasksListService.getList(gtasksPreferenceService.getDefaultList());
@ -126,18 +124,16 @@ public class GoogleTaskListFragment extends TaskEditControlFragment {
return; return;
} }
Metadata taskMetadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY); GoogleTask googleTask = googleTaskDao.getByTaskId(task.getId());
if (taskMetadata == null) { if (googleTask == null) {
taskMetadata = GtasksMetadata.createEmptyMetadataWithoutList(task.getId()); googleTaskDao.insert(new GoogleTask(task.getId(), selectedList.getRemoteId()));
} else if (!taskMetadata.getValue(GtasksMetadata.LIST_ID).equals(selectedList.getRemoteId())) { } else if (!googleTask.getListId().equals(selectedList.getRemoteId())) {
tracker.reportEvent(Tracking.Events.GTASK_MOVE); tracker.reportEvent(Tracking.Events.GTASK_MOVE);
task.putTransitory(SyncFlags.FORCE_SYNC, true); task.putTransitory(SyncFlags.FORCE_SYNC, true);
taskMetadata.setDeletionDate(now()); googleTask.setDeleted(now());
metadataDao.persist(taskMetadata); googleTaskDao.update(googleTask);
taskMetadata = GtasksMetadata.createEmptyMetadataWithoutList(task.getId()); googleTaskDao.insert(new GoogleTask(task.getId(), selectedList.getRemoteId()));
} }
taskMetadata.setValue(GtasksMetadata.LIST_ID, selectedList.getRemoteId());
metadataDao.persist(taskMetadata);
} }
@Override @Override

@ -1,28 +1,22 @@
package com.todoroo.astrid.api; package com.todoroo.astrid.api;
import android.content.ContentValues;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Functions; import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.QueryTemplate; import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList; import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.GoogleTask;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static com.todoroo.andlib.utility.AndroidUtilities.mapFromContentValues;
public class GtasksFilter extends Filter { public class GtasksFilter extends Filter {
private static final int CLOUD = R.drawable.ic_cloud_black_24dp; private static final int CLOUD = R.drawable.ic_cloud_black_24dp;
@ -42,7 +36,7 @@ public class GtasksFilter extends Filter {
public static String toManualOrder(String query) { public static String toManualOrder(String query) {
query = query.replaceAll("ORDER BY .*", ""); query = query.replaceAll("ORDER BY .*", "");
query = query + String.format(" ORDER BY %s", Order.asc(Functions.cast(GtasksMetadata.ORDER, "LONG"))); query = query + " ORDER BY `order` ASC";
return query.replace( return query.replace(
TaskDao.TaskCriteria.activeAndVisible().toString(), TaskDao.TaskCriteria.activeAndVisible().toString(),
TaskDao.TaskCriteria.notDeleted().toString()); TaskDao.TaskCriteria.notDeleted().toString());
@ -53,20 +47,16 @@ public class GtasksFilter extends Filter {
} }
private static QueryTemplate getQueryTemplate(GtasksList list) { private static QueryTemplate getQueryTemplate(GtasksList list) {
Criterion fullCriterion = Criterion.and( return new QueryTemplate()
MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY), .join(Join.left(GoogleTask.TABLE, Task.ID.eq(Field.field("google_tasks.task"))))
TaskDao.TaskCriteria.activeAndVisible(), .where(Criterion.and(
GtasksMetadata.LIST_ID.eq(list.getRemoteId())); TaskDao.TaskCriteria.activeAndVisible(),
return new QueryTemplate().join(Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK))) Field.field("list_id").eq(list.getRemoteId())));
.where(fullCriterion);
} }
private static Map<String, Object> getValuesForNewTasks(GtasksList list) { private static Map<String, Object> getValuesForNewTasks(GtasksList list) {
ContentValues contentValues = GtasksMetadata.createEmptyMetadataWithoutList(AbstractModel.NO_ID).getMergedValues(); Map<String, Object> values = new HashMap<>();
Map<String, Object> values = mapFromContentValues(contentValues); values.put(GoogleTask.KEY, list.getRemoteId());
values.remove(Metadata.TASK.name);
values.put(GtasksMetadata.LIST_ID.name, list.getRemoteId());
values.put(GtasksMetadata.ORDER.name, PermaSql.VALUE_NOW);
return values; return values;
} }

@ -43,6 +43,8 @@ class BackupConstants {
public static final String TAG_TAG = "tag"; public static final String TAG_TAG = "tag";
public static final String GOOGLE_TASKS_TAG = "googletasks";
/** Tag containing a tagdata item */ /** Tag containing a tagdata item */
public static final String TAGDATA_TAG = "tagdata"; public static final String TAGDATA_TAG = "tagdata";

@ -20,11 +20,9 @@ import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.UserActivityDao; import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.UserActivity; import com.todoroo.astrid.data.UserActivity;
@ -33,6 +31,8 @@ import org.tasks.R;
import org.tasks.backup.XmlWriter; import org.tasks.backup.XmlWriter;
import org.tasks.data.Alarm; import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao; import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.data.LocationDao; import org.tasks.data.LocationDao;
import org.tasks.data.Tag; import org.tasks.data.Tag;
@ -66,10 +66,10 @@ public class TasksXmlExporter {
// --- implementation // --- implementation
private final TagDataDao tagDataDao; private final TagDataDao tagDataDao;
private final MetadataDao metadataDao;
private final AlarmDao alarmDao; private final AlarmDao alarmDao;
private final LocationDao locationDao; private final LocationDao locationDao;
private final TagDao tagDao; private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final TaskDao taskDao; private final TaskDao taskDao;
private UserActivityDao userActivityDao; private UserActivityDao userActivityDao;
private final Preferences preferences; private final Preferences preferences;
@ -98,16 +98,17 @@ public class TasksXmlExporter {
} }
@Inject @Inject
public TasksXmlExporter(TagDataDao tagDataDao, MetadataDao metadataDao, TaskDao taskDao, UserActivityDao userActivityDao, public TasksXmlExporter(TagDataDao tagDataDao, TaskDao taskDao, UserActivityDao userActivityDao,
Preferences preferences, AlarmDao alarmDao, LocationDao locationDao, TagDao tagDao) { Preferences preferences, AlarmDao alarmDao, LocationDao locationDao,
TagDao tagDao, GoogleTaskDao googleTaskDao) {
this.tagDataDao = tagDataDao; this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.taskDao = taskDao; this.taskDao = taskDao;
this.userActivityDao = userActivityDao; this.userActivityDao = userActivityDao;
this.preferences = preferences; this.preferences = preferences;
this.alarmDao = alarmDao; this.alarmDao = alarmDao;
this.locationDao = locationDao; this.locationDao = locationDao;
this.tagDao = tagDao; this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
} }
public void exportTasks(final Context context, final ExportType exportType, @Nullable final ProgressDialog progressDialog) { public void exportTasks(final Context context, final ExportType exportType, @Nullable final ProgressDialog progressDialog) {
@ -218,15 +219,6 @@ public class TasksXmlExporter {
} }
private synchronized void serializeMetadata(Task task) { private synchronized void serializeMetadata(Task task) {
for (Metadata metadata : metadataDao.byTask(task.getId())) {
try {
xml.startTag(null, BackupConstants.METADATA_TAG);
serializeModel(metadata, Metadata.PROPERTIES, Metadata.ID, Metadata.TASK);
xml.endTag(null, BackupConstants.METADATA_TAG);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
XmlWriter writer = new XmlWriter(xml); XmlWriter writer = new XmlWriter(xml);
for (Alarm alarm : alarmDao.getAlarms(task.getId())) { for (Alarm alarm : alarmDao.getAlarms(task.getId())) {
try { try {
@ -255,6 +247,15 @@ public class TasksXmlExporter {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
for (GoogleTask googleTask : googleTaskDao.getAllByTaskId(task.getId())) {
try {
xml.startTag(null, BackupConstants.GOOGLE_TASKS_TAG);
googleTask.writeToXml(writer);
xml.endTag(null, BackupConstants.GOOGLE_TASKS_TAG);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} }
/** /**

@ -17,11 +17,9 @@ import com.todoroo.andlib.data.Property.PropertyVisitor;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.UserActivityDao; import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.UserActivity; import com.todoroo.astrid.data.UserActivity;
@ -31,6 +29,8 @@ import org.tasks.R;
import org.tasks.backup.XmlReader; import org.tasks.backup.XmlReader;
import org.tasks.data.Alarm; import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao; import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.data.LocationDao; import org.tasks.data.LocationDao;
import org.tasks.data.Tag; import org.tasks.data.Tag;
@ -50,13 +50,13 @@ import timber.log.Timber;
public class TasksXmlImporter { public class TasksXmlImporter {
private final TagDataDao tagDataDao; private final TagDataDao tagDataDao;
private final MetadataDao metadataDao;
private final UserActivityDao userActivityDao; private final UserActivityDao userActivityDao;
private final DialogBuilder dialogBuilder; private final DialogBuilder dialogBuilder;
private final TaskDao taskDao; private final TaskDao taskDao;
private LocalBroadcastManager localBroadcastManager; private final LocalBroadcastManager localBroadcastManager;
private final AlarmDao alarmDao; private final AlarmDao alarmDao;
private final TagDao tagDao; private final TagDao tagDao;
private GoogleTaskDao googleTaskDao;
private final LocationDao locationDao; private final LocationDao locationDao;
private Activity activity; private Activity activity;
@ -73,11 +73,11 @@ public class TasksXmlImporter {
} }
@Inject @Inject
public TasksXmlImporter(TagDataDao tagDataDao, MetadataDao metadataDao, UserActivityDao userActivityDao, public TasksXmlImporter(TagDataDao tagDataDao, UserActivityDao userActivityDao,
DialogBuilder dialogBuilder, TaskDao taskDao, LocationDao locationDao, DialogBuilder dialogBuilder, TaskDao taskDao, LocationDao locationDao,
LocalBroadcastManager localBroadcastManager, AlarmDao alarmDao, TagDao tagDao) { LocalBroadcastManager localBroadcastManager, AlarmDao alarmDao,
TagDao tagDao, GoogleTaskDao googleTaskDao) {
this.tagDataDao = tagDataDao; this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.userActivityDao = userActivityDao; this.userActivityDao = userActivityDao;
this.dialogBuilder = dialogBuilder; this.dialogBuilder = dialogBuilder;
this.taskDao = taskDao; this.taskDao = taskDao;
@ -85,6 +85,7 @@ public class TasksXmlImporter {
this.localBroadcastManager = localBroadcastManager; this.localBroadcastManager = localBroadcastManager;
this.alarmDao = alarmDao; this.alarmDao = alarmDao;
this.tagDao = tagDao; this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
} }
public void importTasks(Activity activity, String input, ProgressDialog progressDialog) { public void importTasks(Activity activity, String input, ProgressDialog progressDialog) {
@ -165,7 +166,6 @@ public class TasksXmlImporter {
XmlPullParser xpp; XmlPullParser xpp;
final Task currentTask = new Task(); final Task currentTask = new Task();
final Metadata metadata = new Metadata();
public Format2TaskImporter() { } public Format2TaskImporter() { }
public Format2TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException { public Format2TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException {
@ -235,7 +235,6 @@ public class TasksXmlImporter {
} }
UserActivity userActivity = new UserActivity(new XmlReader(xpp)); UserActivity userActivity = new UserActivity(new XmlReader(xpp));
userActivityDao.createNew(userActivity); userActivityDao.createNew(userActivity);
} }
@ -245,7 +244,7 @@ public class TasksXmlImporter {
} }
Alarm alarm = new Alarm(new XmlReader(xpp)); Alarm alarm = new Alarm(new XmlReader(xpp));
alarm.setTask(currentTask.getId());
alarmDao.insert(alarm); alarmDao.insert(alarm);
} }
@ -255,7 +254,7 @@ public class TasksXmlImporter {
} }
Location location = new Location(new XmlReader(xpp)); Location location = new Location(new XmlReader(xpp));
location.setTask(currentTask.getId());
locationDao.insert(location); locationDao.insert(location);
} }
@ -265,32 +264,42 @@ public class TasksXmlImporter {
} }
Tag tag = new Tag(new XmlReader(xpp)); Tag tag = new Tag(new XmlReader(xpp));
tag.setTask(currentTask.getId());
tagDao.insert(tag); tagDao.insert(tag);
} }
void parseGoogleTask() {
if (!currentTask.isSaved()) {
return;
}
GoogleTask googleTask = new GoogleTask(new XmlReader(xpp));
googleTask.setTask(currentTask.getId());
googleTaskDao.insert(googleTask);
}
void parseMetadata(int format) { void parseMetadata(int format) {
if(!currentTask.isSaved()) { if(!currentTask.isSaved()) {
return; return;
} }
metadata.clear(); XmlReader xml = new XmlReader(xpp);
deserializeModel(metadata, Metadata.PROPERTIES); String key = xml.readString("key");
if (metadata.getKey().equals("alarm")) { if ("alarm".equals(key)) {
Alarm alarm = new Alarm(); Alarm alarm = new Alarm();
alarm.setTask(currentTask.getId()); alarm.setTask(currentTask.getId());
alarm.setTime(Long.valueOf(metadata.getValue(Metadata.VALUE1))); alarm.setTime(xml.readLong("value"));
alarmDao.insert(alarm); alarmDao.insert(alarm);
} else if (metadata.getKey().equals("geofence")) { } else if ("geofence".equals(key)) {
Location location = new Location(); Location location = new Location();
location.setTask(currentTask.getId()); location.setTask(currentTask.getId());
location.setName(metadata.getValue(Metadata.VALUE1)); location.setName(xml.readString("value"));
location.setLatitude(Double.valueOf(metadata.getValue(Metadata.VALUE2))); location.setLatitude(xml.readDouble("value2"));
location.setLongitude(Double.valueOf(metadata.getValue(Metadata.VALUE3))); location.setLongitude(xml.readDouble("value3"));
location.setRadius(Integer.valueOf(metadata.getValue(Metadata.VALUE4))); location.setRadius(xml.readInteger("value4"));
locationDao.insert(location); locationDao.insert(location);
} else if (metadata.getKey().equals("tags-tag")) { } else if ("tags-tag".equals(key)) {
String tagUid = metadata.getValue(Metadata.VALUE2); String name = xml.readString("value");
String name = metadata.getValue(Metadata.VALUE1); String tagUid = xml.readString("value2");
if (tagDao.getTagByTaskAndTagUid(currentTask.getId(), tagUid) == null) { if (tagDao.getTagByTaskAndTagUid(currentTask.getId(), tagUid) == null) {
tagDao.insert(new Tag(currentTask.getId(), currentTask.getUuid(), name, tagUid)); tagDao.insert(new Tag(currentTask.getId(), currentTask.getUuid(), name, tagUid));
} }
@ -305,10 +314,18 @@ public class TasksXmlImporter {
tagDataDao.insert(tagData); tagDataDao.insert(tagData);
} }
} }
} else { } else if ("gtasks".equals(key)) {
metadata.setId(Metadata.NO_ID); GoogleTask googleTask = new GoogleTask();
metadata.setTask(currentTask.getId()); googleTask.setTask(currentTask.getId());
metadataDao.persist(metadata); googleTask.setRemoteId(xml.readString("value"));
googleTask.setListId(xml.readString("value2"));
googleTask.setParent(xml.readLong("value3"));
googleTask.setIndent(xml.readInteger("value4"));
googleTask.setOrder(xml.readLong("value5"));
googleTask.setRemoteOrder(xml.readLong("value6"));
googleTask.setLastSync(xml.readLong("value7"));
googleTask.setDeleted(xml.readLong("deleted"));
googleTaskDao.insert(googleTask);
} }
} }
@ -410,6 +427,9 @@ public class TasksXmlImporter {
case BackupConstants.TAG_TAG: case BackupConstants.TAG_TAG:
parseTag(); parseTag();
break; break;
case BackupConstants.GOOGLE_TASKS_TAG:
parseGoogleTask();
break;
} }
} catch (Exception e) { } catch (Exception e) {
errorCount++; errorCount++;

@ -10,7 +10,6 @@ import android.os.Bundle;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
@ -29,7 +28,6 @@ import javax.inject.Inject;
public class OldTaskPreferences extends InjectingPreferenceActivity { public class OldTaskPreferences extends InjectingPreferenceActivity {
@Inject DialogBuilder dialogBuilder; @Inject DialogBuilder dialogBuilder;
@Inject MetadataDao metadataDao;
@Inject Preferences preferences; @Inject Preferences preferences;
@Inject Database database; @Inject Database database;
@Inject TaskDao taskDao; @Inject TaskDao taskDao;
@ -76,10 +74,9 @@ public class OldTaskPreferences extends InjectingPreferenceActivity {
.where(Criterion.and(Task.DELETION_DATE.gt(0))); .where(Criterion.and(Task.DELETION_DATE.gt(0)));
for (Task task : taskDao.toList(query)) { for (Task task : taskDao.toList(query)) {
calendarEventProvider.deleteEvent(task); calendarEventProvider.deleteEvent(task);
taskDao.delete(task.getId());
} }
int result = taskDao.deleteWhere(Task.DELETION_DATE.gt(0)); return taskDao.deleteWhere(Task.DELETION_DATE.gt(0));
metadataDao.removeDanglingMetadata();
return result;
} }
@Override @Override

@ -15,7 +15,6 @@ import android.database.sqlite.SQLiteDatabase;
import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Table; import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.StoreObject; import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
@ -25,6 +24,8 @@ import com.todoroo.astrid.data.UserActivity;
import org.tasks.data.Alarm; import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao; import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Location; import org.tasks.data.Location;
import org.tasks.data.LocationDao; import org.tasks.data.LocationDao;
import org.tasks.data.Tag; import org.tasks.data.Tag;
@ -51,12 +52,12 @@ import timber.log.Timber;
TaskListMetadata.class, TaskListMetadata.class,
StoreObject.class, StoreObject.class,
Task.class, Task.class,
Metadata.class,
Alarm.class, Alarm.class,
Location.class, Location.class,
Tag.class Tag.class,
GoogleTask.class
}, },
version = 49) version = 50)
public abstract class Database extends RoomDatabase { public abstract class Database extends RoomDatabase {
public abstract NotificationDao notificationDao(); public abstract NotificationDao notificationDao();
@ -66,14 +67,14 @@ public abstract class Database extends RoomDatabase {
public abstract TaskListMetadataDao getTaskListMetadataDao(); public abstract TaskListMetadataDao getTaskListMetadataDao();
public abstract StoreObjectDao getStoreObjectDao(); public abstract StoreObjectDao getStoreObjectDao();
public abstract AlarmDao getAlarmDao(); public abstract AlarmDao getAlarmDao();
public abstract LocationDao getGeofenceDao(); public abstract LocationDao getLocationDao();
public abstract TagDao getTagDao(); public abstract TagDao getTagDao();
public abstract GoogleTaskDao getGoogleTaskDao();
public static final String NAME = "database"; public static final String NAME = "database";
public static final Table[] TABLES = new Table[] { public static final Table[] TABLES = new Table[] {
Task.TABLE, Task.TABLE
Metadata.TABLE
}; };
private SupportSQLiteDatabase database; private SupportSQLiteDatabase database;

@ -1,139 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.dao;
import com.todoroo.andlib.data.DatabaseDao;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import org.tasks.injection.ApplicationScope;
import java.util.List;
import javax.inject.Inject;
/**
* Data Access layer for {@link Metadata}-related operations.
*
* @author Tim Su <tim@todoroo.com>
*
*/
@ApplicationScope
public class MetadataDao {
private final DatabaseDao<Metadata> dao;
@Inject
public MetadataDao(Database database) {
dao = new DatabaseDao<>(database, Metadata.class);
}
public Metadata getFirst(Query query) {
return dao.getFirst(query);
}
public Metadata getFirstActiveByTaskAndKey(long taskId, String key) {
return getFirst(Query.select(Metadata.PROPERTIES).where(Criterion.and(
MetadataCriteria.byTaskAndwithKey(taskId, key),
MetadataCriteria.isActive())));
}
public int update(Criterion where, Metadata template) {
return dao.update(where, template);
}
public void createNew(Metadata metadata) {
dao.createNew(metadata);
}
public List<Metadata> toList(Criterion criterion) {
return toList(Query.select(Metadata.PROPERTIES).where(criterion));
}
public List<Metadata> toList(Query where) {
return dao.toList(where);
}
public int deleteWhere(Criterion criterion) {
return dao.deleteWhere(criterion);
}
public boolean delete(long id) {
return dao.delete(id);
}
public void saveExisting(Metadata metadata) {
dao.saveExisting(metadata);
}
public Metadata fetch(long id) {
return dao.fetch(id, Metadata.PROPERTIES);
}
// --- SQL clause generators
/**
* Generates SQL clauses
*/
public static class MetadataCriteria {
/** Returns all metadata associated with a given task */
public static Criterion byTask(long taskId) {
return Metadata.TASK.eq(taskId);
}
/** Returns all metadata associated with a given key */
public static Criterion withKey(String key) {
return Metadata.KEY.eq(key);
}
/** Returns all metadata associated with a given key */
public static Criterion byTaskAndwithKey(long taskId, String key) {
return Criterion.and(withKey(key), byTask(taskId));
}
public static Criterion isActive() {
return Metadata.DELETION_DATE.eq(0);
}
public static Criterion isDeleted() {
return Metadata.DELETION_DATE.gt(0);
}
}
public boolean persist(Metadata item) {
if(!item.containsNonNullValue(Metadata.TASK)) {
throw new IllegalArgumentException("metadata needs to be attached to a task: " + item.getMergedValues()); //$NON-NLS-1$
}
if(!item.containsValue(Metadata.CREATION_DATE)) {
item.setCreationDate(DateUtilities.now());
}
return dao.persist(item);
}
/**
* Clean up metadata. Typically called on startup
*/
public void removeDanglingMetadata() {
dao.deleteWhere(Metadata.ID.in(Query.select(Metadata.ID).from(Metadata.TABLE).join(Join.left(Task.TABLE,
Metadata.TASK.eq(Task.ID))).where(Task.TITLE.isNull())));
}
public List<Metadata> byTask(long taskId) {
return toList(MetadataCriteria.byTask(taskId));
}
public List<Metadata> byTaskAndKey(long taskId, String key) {
return dao.toList(Query.select(Metadata.PROPERTIES).where(
Criterion.and(Metadata.TASK.eq(taskId), Metadata.KEY.eq(key))));
}
}

@ -18,7 +18,6 @@ import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
@ -26,6 +25,10 @@ import com.todoroo.astrid.data.TaskApiDao;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.LocationDao;
import org.tasks.data.TagDao;
import org.tasks.injection.ApplicationScope; import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.jobs.AfterSaveIntentService; import org.tasks.jobs.AfterSaveIntentService;
@ -52,16 +55,25 @@ public class TaskDao {
private final RemoteModelDao<Task> dao; private final RemoteModelDao<Task> dao;
private final LocalBroadcastManager localBroadcastManager; private final LocalBroadcastManager localBroadcastManager;
private final MetadataDao metadataDao; private final Database database;
private final Preferences preferences; private final Preferences preferences;
private final AlarmDao alarmDao;
private final TagDao tagDao;
private final LocationDao locationDao;
private final GoogleTaskDao googleTaskDao;
private final Context context; private final Context context;
@Inject @Inject
public TaskDao(@ForApplication Context context, Database database, MetadataDao metadataDao, public TaskDao(@ForApplication Context context, Database database,
Preferences preferences, LocalBroadcastManager localBroadcastManager) { Preferences preferences, LocalBroadcastManager localBroadcastManager,
AlarmDao alarmDao, TagDao tagDao, LocationDao locationDao, GoogleTaskDao googleTaskDao) {
this.context = context; this.context = context;
this.database = database;
this.preferences = preferences; this.preferences = preferences;
this.metadataDao = metadataDao; this.alarmDao = alarmDao;
this.tagDao = tagDao;
this.locationDao = locationDao;
this.googleTaskDao = googleTaskDao;
this.localBroadcastManager = localBroadcastManager; this.localBroadcastManager = localBroadcastManager;
dao = new RemoteModelDao<>(database, Task.class); dao = new RemoteModelDao<>(database, Task.class);
} }
@ -188,7 +200,10 @@ public class TaskDao {
} }
// delete all metadata // delete all metadata
metadataDao.deleteWhere(MetadataCriteria.byTask(id)); alarmDao.deleteByTaskId(id);
locationDao.deleteByTaskId(id);
tagDao.deleteByTaskId(id);
googleTaskDao.deleteByTaskId(id);
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();

@ -1,179 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.data;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import android.content.ContentValues;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.data.Table;
/**
* Data Model which represents a piece of metadata associated with a task
*
* @author Tim Su <tim@todoroo.com>
*
*/
@Entity(tableName = "metadata",
indices = {
@Index(name = "md_tid", value = "task"),
@Index(name = "md_tkid", value = {"task", "key"})
})
public class Metadata extends AbstractModel {
// --- table
/** table for this model */
public static final Table TABLE = new Table("metadata", Metadata.class);
// --- properties
/** ID */
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id")
public Long id;
public static final LongProperty ID = new LongProperty(
TABLE, ID_PROPERTY_NAME);
/** Associated Task */
@ColumnInfo(name = "task")
public Long task;
public static final LongProperty TASK = new LongProperty(
TABLE, "task");
/** Metadata Key */
@ColumnInfo(name = "key")
public String key;
public static final StringProperty KEY = new StringProperty(
TABLE, "key");
/** Metadata Text Value Column 1 */
@ColumnInfo(name = "value")
public String value1;
public static final StringProperty VALUE1 = new StringProperty(
TABLE, "value");
/** Metadata Text Value Column 2 */
@ColumnInfo(name = "value2")
public String value2;
public static final StringProperty VALUE2 = new StringProperty(
TABLE, "value2");
/** Metadata Text Value Column 3 */
@ColumnInfo(name = "value3")
public String value3;
public static final StringProperty VALUE3 = new StringProperty(
TABLE, "value3");
/** Metadata Text Value Column 4 */
@ColumnInfo(name = "value4")
public String value4;
public static final StringProperty VALUE4 = new StringProperty(
TABLE, "value4");
/** Metadata Text Value Column 5 */
@ColumnInfo(name = "value5")
public String value5;
public static final StringProperty VALUE5 = new StringProperty(
TABLE, "value5");
@ColumnInfo(name = "value6")
public String value6;
public static final StringProperty VALUE6 = new StringProperty(
TABLE, "value6");
@ColumnInfo(name = "value7")
public String value7;
public static final StringProperty VALUE7 = new StringProperty(
TABLE, "value7");
/** Unixtime Metadata was created */
@ColumnInfo(name = "created")
public Long created;
public static final LongProperty CREATION_DATE = new LongProperty(
TABLE, "created");
/** Unixtime metadata was deleted/tombstoned */
@ColumnInfo(name = "deleted")
public Long deleted = 0L;
public static final LongProperty DELETION_DATE = new LongProperty(
TABLE, "deleted");
/** List of all properties for this model */
public static final Property<?>[] PROPERTIES = generateProperties(Metadata.class);
// --- defaults
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
static {
defaultValues.put(DELETION_DATE.name, 0L);
}
public Metadata() {
super();
}
@Ignore
public Metadata(Metadata metadata) {
super(metadata);
}
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
@Override
public long getId() {
return getIdHelper(ID);
}
// --- parcelable helpers
private static final Creator<Metadata> CREATOR = new ModelCreator<>(Metadata.class);
public Long getDeletionDate() {
return getValue(DELETION_DATE);
}
public void setDeletionDate(Long deletionDate) {
setValue(DELETION_DATE, deletionDate);
}
public Long getTask() {
return getValue(TASK);
}
public void setTask(Long task) {
setValue(TASK, task);
}
public Long getCreationDate() {
return getValue(CREATION_DATE);
}
public void setCreationDate(Long creationDate) {
setValue(CREATION_DATE, creationDate);
}
public String getKey() {
return getValue(KEY);
}
public void setKey(String key) {
setValue(KEY, key);
}
}

@ -13,7 +13,7 @@ import org.tasks.backup.XmlWriter;
import java.io.Serializable; import java.io.Serializable;
@Entity(tableName = "tagdata") @Entity(tableName = "tagdata")
public final class TagData implements Parcelable, Serializable { public final class TagData implements Parcelable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id") @ColumnInfo(name = "_id")

@ -1,82 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.gtasks;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Metadata;
import javax.inject.Inject;
/**
* Metadata entries for a GTasks Task
* @author Tim Su <tim@todoroo.com>
*
*/
public class GtasksMetadata {
/** metadata key */
public static final String METADATA_KEY = "gtasks"; //$NON-NLS-1$
/** task id in google */
public static final StringProperty ID = new StringProperty(Metadata.TABLE,
Metadata.VALUE1.name);
public static final StringProperty LIST_ID = new StringProperty(Metadata.TABLE,
Metadata.VALUE2.name);
/** parent task id, or 0 if top level task */
public static final LongProperty PARENT_TASK = new LongProperty(Metadata.TABLE,
Metadata.VALUE3.name);
public static final IntegerProperty INDENT = new IntegerProperty(Metadata.TABLE,
Metadata.VALUE4.name);
public static final LongProperty ORDER = new LongProperty(Metadata.TABLE,
Metadata.VALUE5.name);
public static final LongProperty GTASKS_ORDER = new LongProperty(Metadata.TABLE,
Metadata.VALUE6.name);
public static final LongProperty LAST_SYNC = new LongProperty(Metadata.TABLE,
Metadata.VALUE7.name);
private final GtasksPreferenceService gtasksPreferenceService;
@Inject
public GtasksMetadata(GtasksPreferenceService gtasksPreferenceService) {
this.gtasksPreferenceService = gtasksPreferenceService;
}
/**
* Creates default GTasks metadata item
* @param taskId if > 0, will set metadata task field
*/
public Metadata createEmptyMetadata(long taskId) {
Metadata metadata = createEmptyMetadataWithoutList(taskId);
String defaultList = gtasksPreferenceService.getDefaultList();
if(defaultList == null) {
defaultList = "@default"; //$NON-NLS-1$
}
metadata.setValue(LIST_ID, defaultList);
return metadata;
}
public static Metadata createEmptyMetadataWithoutList(long taskId) {
Metadata metadata = new Metadata();
metadata.setKey(GtasksMetadata.METADATA_KEY);
metadata.setValue(ID, ""); //$NON-NLS-1$
metadata.setValue(PARENT_TASK, AbstractModel.NO_ID);
metadata.setValue(INDENT, 0);
metadata.setValue(ORDER, DateUtilities.now());
if(taskId > AbstractModel.NO_ID) {
metadata.setTask(taskId);
}
return metadata;
}
}

@ -14,7 +14,6 @@ import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps; import com.google.common.collect.Multimaps;
import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService;
@ -48,7 +47,6 @@ public class StartupService {
private final Tracker tracker; private final Tracker tracker;
private final TagDataDao tagDataDao; private final TagDataDao tagDataDao;
private final TagService tagService; private final TagService tagService;
private final MetadataDao metadataDao;
private final LocalBroadcastManager localBroadcastManager; private final LocalBroadcastManager localBroadcastManager;
private final Context context; private final Context context;
private final TagDao tagDao; private final TagDao tagDao;
@ -56,7 +54,7 @@ public class StartupService {
@Inject @Inject
public StartupService(Database database, Preferences preferences, TaskDeleter taskDeleter, public StartupService(Database database, Preferences preferences, TaskDeleter taskDeleter,
Tracker tracker, TagDataDao tagDataDao, TagService tagService, Tracker tracker, TagDataDao tagDataDao, TagService tagService,
MetadataDao metadataDao, LocalBroadcastManager localBroadcastManager, LocalBroadcastManager localBroadcastManager,
@ForApplication Context context, TagDao tagDao) { @ForApplication Context context, TagDao tagDao) {
this.database = database; this.database = database;
this.preferences = preferences; this.preferences = preferences;
@ -64,7 +62,6 @@ public class StartupService {
this.tracker = tracker; this.tracker = tracker;
this.tagDataDao = tagDataDao; this.tagDataDao = tagDataDao;
this.tagService = tagService; this.tagService = tagService;
this.metadataDao = metadataDao;
this.localBroadcastManager = localBroadcastManager; this.localBroadcastManager = localBroadcastManager;
this.context = context; this.context = context;
this.tagDao = tagDao; this.tagDao = tagDao;
@ -158,7 +155,7 @@ public class StartupService {
for (Long key : metadataByTask.keySet()) { for (Long key : metadataByTask.keySet()) {
ImmutableList<Tag> tagData = metadataByTask.get(key); ImmutableList<Tag> tagData = metadataByTask.get(key);
for (int i = 1 ; i < tagData.size() ; i++) { for (int i = 1 ; i < tagData.size() ; i++) {
metadataDao.delete(tagData.get(i).getId()); tagDao.deleteById(tagData.get(i).getId());
} }
} }
} }

@ -4,13 +4,10 @@ import android.content.ContentValues;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
@ -18,6 +15,8 @@ import com.todoroo.astrid.gcal.GCalHelper;
import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.TitleParser; import com.todoroo.astrid.utility.TitleParser;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Tag; import org.tasks.data.Tag;
import org.tasks.data.TagDao; import org.tasks.data.TagDao;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
@ -33,22 +32,22 @@ public class TaskCreator {
private final GCalHelper gcalHelper; private final GCalHelper gcalHelper;
private final Preferences preferences; private final Preferences preferences;
private final MetadataDao metadataDao;
private final TagDao tagDao; private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final TagDataDao tagDataDao; private final TagDataDao tagDataDao;
private final TaskDao taskDao; private final TaskDao taskDao;
private final TagService tagService; private final TagService tagService;
@Inject @Inject
public TaskCreator(GCalHelper gcalHelper, Preferences preferences, MetadataDao metadataDao, public TaskCreator(GCalHelper gcalHelper, Preferences preferences, TagDataDao tagDataDao,
TagDataDao tagDataDao, TaskDao taskDao, TagService tagService, TagDao tagDao) { TaskDao taskDao, TagService tagService, TagDao tagDao, GoogleTaskDao googleTaskDao) {
this.gcalHelper = gcalHelper; this.gcalHelper = gcalHelper;
this.preferences = preferences; this.preferences = preferences;
this.metadataDao = metadataDao;
this.tagDataDao = tagDataDao; this.tagDataDao = tagDataDao;
this.taskDao = taskDao; this.taskDao = taskDao;
this.tagService = tagService; this.tagService = tagService;
this.tagDao = tagDao; this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
} }
public Task basicQuickAddTask(String title) { public Task basicQuickAddTask(String title) {
@ -90,14 +89,12 @@ public class TaskCreator {
Timber.e(e, e.getMessage()); Timber.e(e, e.getMessage());
} }
ContentValues forMetadata = null;
if (values != null && values.size() > 0) { if (values != null && values.size() > 0) {
ContentValues forTask = new ContentValues(); ContentValues forTask = new ContentValues();
forMetadata = new ContentValues(); for (Map.Entry<String, Object> item : values.entrySet()) {
outer: for (Map.Entry<String, Object> item : values.entrySet()) {
String key = item.getKey(); String key = item.getKey();
Object value = item.getValue(); Object value = item.getValue();
if (key.equals(Tag.KEY)) { if (key.equals(Tag.KEY) || key.equals(GoogleTask.KEY)) {
continue; continue;
} }
@ -105,13 +102,6 @@ public class TaskCreator {
value = PermaSql.replacePlaceholders((String) value); value = PermaSql.replacePlaceholders((String) value);
} }
for (Property<?> property : Metadata.PROPERTIES) {
if (property.name.equals(key)) {
AndroidUtilities.putInto(forMetadata, key, value);
continue outer;
}
}
AndroidUtilities.putInto(forTask, key, value); AndroidUtilities.putInto(forTask, key, value);
} }
task.mergeWithoutReplacement(forTask); task.mergeWithoutReplacement(forTask);
@ -119,21 +109,20 @@ public class TaskCreator {
saveWithoutPublishingFilterUpdate(task); saveWithoutPublishingFilterUpdate(task);
if (values != null && values.containsKey(Tag.KEY)) { if (values != null) {
createLink(task, (String) values.get(Tag.KEY)); if (values.containsKey(Tag.KEY)) {
createLink(task, (String) values.get(Tag.KEY));
}
if (values.containsKey(GoogleTask.KEY)) {
GoogleTask googleTask = new GoogleTask(task.getId(), (String) values.get(GoogleTask.KEY));
googleTaskDao.insert(googleTask);
}
} }
for(String tag : tags) { for(String tag : tags) {
createLink(task, tag); createLink(task, tag);
} }
if (forMetadata != null && forMetadata.size() > 0) {
Metadata metadata = new Metadata();
metadata.setTask(task.getId());
metadata.mergeWith(forMetadata);
metadataDao.persist(metadata);
}
return task; return task;
} }

@ -2,15 +2,14 @@ package com.todoroo.astrid.service;
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.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gcal.GCalHelper; import com.todoroo.astrid.gcal.GCalHelper;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import org.tasks.LocalBroadcastManager; import org.tasks.LocalBroadcastManager;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Tag; import org.tasks.data.Tag;
import org.tasks.data.TagDao; import org.tasks.data.TagDao;
@ -19,36 +18,34 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import timber.log.Timber;
public class TaskDuplicator { public class TaskDuplicator {
private final GCalHelper gcalHelper; private final GCalHelper gcalHelper;
private final MetadataDao metadataDao;
private final TaskDao taskDao; private final TaskDao taskDao;
private final TagDao tagDao; private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final LocalBroadcastManager localBroadcastManager; private final LocalBroadcastManager localBroadcastManager;
@Inject @Inject
public TaskDuplicator(GCalHelper gcalHelper, MetadataDao metadataDao, TaskDao taskDao, public TaskDuplicator(GCalHelper gcalHelper, TaskDao taskDao, LocalBroadcastManager localBroadcastManager,
LocalBroadcastManager localBroadcastManager, TagDao tagDao) { TagDao tagDao, GoogleTaskDao googleTaskDao) {
this.gcalHelper = gcalHelper; this.gcalHelper = gcalHelper;
this.metadataDao = metadataDao;
this.taskDao = taskDao; this.taskDao = taskDao;
this.localBroadcastManager = localBroadcastManager; this.localBroadcastManager = localBroadcastManager;
this.tagDao = tagDao; this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
} }
public List<Task> duplicate(List<Task> tasks) { public List<Task> duplicate(List<Task> tasks) {
List<Task> result = new ArrayList<>(); List<Task> result = new ArrayList<>();
for (Task task : tasks) { for (Task task : tasks) {
result.add(clone(taskDao.fetch(task.getId()), true)); result.add(clone(taskDao.fetch(task.getId())));
} }
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();
return result; return result;
} }
private Task clone(Task original, boolean suppressRefresh) { private Task clone(Task original) {
Task clone = new Task(original); Task clone = new Task(original);
clone.setCreationDate(DateUtilities.now()); clone.setCreationDate(DateUtilities.now());
clone.setCompletionDate(0L); clone.setCompletionDate(0L);
@ -57,13 +54,11 @@ public class TaskDuplicator {
clone.clearValue(Task.ID); clone.clearValue(Task.ID);
clone.clearValue(Task.UUID); clone.clearValue(Task.UUID);
List<Metadata> metadataList = metadataDao.byTask(original.getId()); GoogleTask googleTask = googleTaskDao.getByTaskId(original.getId());
if (!metadataList.isEmpty()) { if (googleTask != null) {
clone.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true); clone.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
} }
if (suppressRefresh) { clone.putTransitory(TaskDao.TRANS_SUPPRESS_REFRESH, true);
clone.putTransitory(TaskDao.TRANS_SUPPRESS_REFRESH, true);
}
taskDao.save(clone); taskDao.save(clone);
@ -71,16 +66,8 @@ public class TaskDuplicator {
tagDao.getTagsForTask(original.getId()), tagDao.getTagsForTask(original.getId()),
tag -> new Tag(clone.getId(), clone.getUuid(), tag.getName(), tag.getTagUid()))); tag -> new Tag(clone.getId(), clone.getUuid(), tag.getName(), tag.getTagUid())));
for (Metadata oldMetadata : metadataList) { if (googleTask != null) {
if(!oldMetadata.containsNonNullValue(Metadata.KEY)) { googleTaskDao.insert(new GoogleTask(clone.getId(), googleTask.getListId()));
continue;
}
Timber.d("Cloning %s", oldMetadata);
if(GtasksMetadata.METADATA_KEY.equals(oldMetadata.getKey())) {
Metadata gtaskMetadata = GtasksMetadata.createEmptyMetadataWithoutList(clone.getId());
gtaskMetadata.setValue(GtasksMetadata.LIST_ID, oldMetadata.getValue(GtasksMetadata.LIST_ID));
metadataDao.createNew(gtaskMetadata);
}
} }
gcalHelper.createTaskEventIfEnabled(clone); gcalHelper.createTaskEventIfEnabled(clone);

@ -40,7 +40,6 @@ import com.google.common.collect.Ordering;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
@ -410,9 +409,6 @@ public final class TagsControlSet extends TaskEditControlFragment {
* Delete all links between the specified task and the list of tags * Delete all links between the specified task and the list of tags
*/ */
private void deleteLinks(long taskId, Iterable<TagData> tags) { private void deleteLinks(long taskId, Iterable<TagData> tags) {
Metadata deleteTemplate = new Metadata();
deleteTemplate.setTask(taskId); // Need this for recording changes in outstanding table
deleteTemplate.setDeletionDate(DateUtilities.now());
for (TagData tag : tags) { for (TagData tag : tags) {
// TODO: Right now this is in a loop because each deleteTemplate needs the individual tagUuid in order to record // TODO: Right now this is in a loop because each deleteTemplate needs the individual tagUuid in order to record
// the outstanding entry correctly. If possible, this should be improved to a single query // the outstanding entry correctly. If possible, this should be improved to a single query

@ -4,6 +4,8 @@ import com.todoroo.astrid.backup.TasksXmlExporter;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import static com.todoroo.astrid.backup.TasksXmlExporter.XML_NULL;
public class XmlReader { public class XmlReader {
public interface ValueWriter<T> { public interface ValueWriter<T> {
@ -16,34 +18,50 @@ public class XmlReader {
this.xpp = xpp; this.xpp = xpp;
} }
public void readLong(String name, ValueWriter<Long> writer) { public Long readLong(String name) {
String value = xpp.getAttributeValue(null, name); String value = xpp.getAttributeValue(null, name);
return value == null || XML_NULL.equals(value) ? null : Long.parseLong(value);
}
public void readLong(String name, ValueWriter<Long> writer) {
Long value = readLong(name);
if(value != null) { if(value != null) {
writer.write(TasksXmlExporter.XML_NULL.equals(value) ? writer.write(value);
null : Long.parseLong(value));
} }
} }
public void readInteger(String name, ValueWriter<Integer> writer) { public Integer readInteger(String name) {
String value = xpp.getAttributeValue(null, name); String value = xpp.getAttributeValue(null, name);
return value == null || XML_NULL.equals(value) ? null : Integer.parseInt(value);
}
public void readInteger(String name, ValueWriter<Integer> writer) {
Integer value = readInteger(name);
if(value != null) { if(value != null) {
writer.write(TasksXmlExporter.XML_NULL.equals(value) ? writer.write(value);
null : Integer.parseInt(value));
} }
} }
public String readString(String name) {
return xpp.getAttributeValue(null, name);
}
public void readString(String name, ValueWriter<String> writer) { public void readString(String name, ValueWriter<String> writer) {
String value = xpp.getAttributeValue(null, name); String value = readString(name);
if (value != null) { if (value != null) {
writer.write(value); writer.write(value);
} }
} }
public void readDouble(String name, ValueWriter<Double> writer) { public Double readDouble(String name) {
String value = xpp.getAttributeValue(null, name); String value = xpp.getAttributeValue(null, name);
return value == null || XML_NULL.equals(value) ? null : Double.parseDouble(value);
}
public void readDouble(String name, ValueWriter<Double> writer) {
Double value = readDouble(name);
if (value != null) { if (value != null) {
writer.write(TasksXmlExporter.XML_NULL.equals(value) ? writer.write(value);
null : Double.parseDouble(value));
} }
} }
} }

@ -25,14 +25,18 @@ public class Alarm {
} }
@Ignore
public Alarm(long task, long time) {
this.task = task;
this.time = time;
}
@Ignore @Ignore
public Alarm(XmlReader xml) { public Alarm(XmlReader xml) {
xml.readLong("task", this::setTask);
xml.readLong("time", this::setTime); xml.readLong("time", this::setTime);
} }
public void writeToXml(XmlWriter writer) { public void writeToXml(XmlWriter writer) {
writer.writeLong("task", task);
writer.writeLong("time", time); writer.writeLong("time", time);
} }

@ -26,5 +26,8 @@ public interface AlarmDao {
void delete(Alarm alarm); void delete(Alarm alarm);
@Insert @Insert
void insert(Alarm alarm); long insert(Alarm alarm);
@Query("DELETE FROM alarms WHERE task = :taskId")
void deleteByTaskId(long taskId);
} }

@ -0,0 +1,200 @@
package org.tasks.data;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.PrimaryKey;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.utility.DateUtilities;
import org.tasks.backup.XmlReader;
import org.tasks.backup.XmlWriter;
@Entity(tableName = "google_tasks")
public class GoogleTask {
public static final String KEY = "gtasks"; //$NON-NLS-1$
@Deprecated
public static final Table TABLE = new Table("google_tasks", null);
@Deprecated
public static final Property.IntegerProperty INDENT = new Property.IntegerProperty(GoogleTask.TABLE, "indent");
@Deprecated
public static final Property.LongProperty ORDER = new Property.LongProperty(GoogleTask.TABLE, "`order`");
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id")
private long id;
@ColumnInfo(name = "task")
private long task;
@ColumnInfo(name = "remote_id")
private String remoteId = "";
@ColumnInfo(name = "list_id")
private String listId = "";
@ColumnInfo(name = "parent")
private long parent;
@ColumnInfo(name = "indent")
private int indent;
@ColumnInfo(name = "order")
private long order;
@ColumnInfo(name = "remote_order")
private long remoteOrder;
@ColumnInfo(name = "last_sync")
private long lastSync;
@ColumnInfo(name = "deleted")
private long deleted;
@Ignore
private boolean suppressSync;
public GoogleTask() {
}
@Ignore
public GoogleTask(long task, String listId) {
this.task = task;
this.order = DateUtilities.now();
this.listId = listId;
}
@Ignore
public GoogleTask(XmlReader xml) {
remoteId = xml.readString("remote_id");
listId = xml.readString("list_id");
parent = xml.readLong("parent");
indent = xml.readInteger("indent");
order = xml.readLong("order");
remoteOrder = xml.readLong("remote_order");
lastSync = xml.readLong("last_sync");
deleted = xml.readLong("deleted");
}
public void writeToXml(XmlWriter xml) {
xml.writeString("remote_id", remoteId);
xml.writeString("list_id", listId);
xml.writeLong("parent", parent);
xml.writeInteger("indent", indent);
xml.writeLong("order", order);
xml.writeLong("remote_order", remoteOrder);
xml.writeLong("last_sync", lastSync);
xml.writeLong("deleted", deleted);
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getTask() {
return task;
}
public void setTask(long task) {
this.task = task;
}
public String getRemoteId() {
return remoteId;
}
public void setRemoteId(String remoteId) {
this.remoteId = remoteId;
}
public String getListId() {
return listId;
}
public void setListId(String listId) {
this.listId = listId;
}
public long getParent() {
return parent;
}
public void setParent(long parent) {
this.parent = parent;
}
public int getIndent() {
return indent;
}
public void setIndent(int indent) {
this.indent = indent;
}
public long getOrder() {
return order;
}
public void setOrder(long order) {
this.order = order;
}
public long getRemoteOrder() {
return remoteOrder;
}
public void setRemoteOrder(long remoteOrder) {
this.remoteOrder = remoteOrder;
}
public long getLastSync() {
return lastSync;
}
public void setLastSync(long lastSync) {
this.lastSync = lastSync;
}
public long getDeleted() {
return deleted;
}
public void setDeleted(long deleted) {
this.deleted = deleted;
}
public boolean isSuppressSync() {
return suppressSync;
}
public void setSuppressSync(boolean suppressSync) {
this.suppressSync = suppressSync;
}
@Override
public String toString() {
return "GoogleTask{" +
"id=" + id +
", task=" + task +
", remoteId='" + remoteId + '\'' +
", listId='" + listId + '\'' +
", parent=" + parent +
", indent=" + indent +
", order=" + order +
", remoteOrder=" + remoteOrder +
", lastSync=" + lastSync +
", deleted=" + deleted +
'}';
}
}

@ -0,0 +1,51 @@
package org.tasks.data;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Update;
import java.util.List;
@Dao
public interface GoogleTaskDao {
@Query("DELETE FROM google_tasks WHERE list_id = :remoteId")
void deleteList(String remoteId);
@Insert
void insert(GoogleTask task);
@Query("SELECT * FROM google_tasks WHERE task = :taskId AND deleted = 0 LIMIT 1")
GoogleTask getByTaskId(long taskId);
@Update
void update(GoogleTask googleTask);
@Query("SELECT * FROM google_tasks WHERE list_id = :listId AND parent = :parent ORDER BY remote_order ASC")
List<GoogleTask> byRemoteOrder(String listId, long parent);
@Query("SELECT * FROM google_tasks WHERE list_id = :listId AND `order` > :startAtOrder - 1 ORDER BY `order` ASC ")
List<GoogleTask> getTasksFrom(String listId, long startAtOrder);
@Query("SELECT * FROM google_tasks WHERE list_id = :listId AND `order` < :startAtOrder ORDER BY `order` DESC")
List<GoogleTask> getTasksFromReverse(String listId, long startAtOrder);
@Query("DELETE FROM google_tasks WHERE task = :taskId")
void deleteByTaskId(long taskId);
@Delete
void delete(GoogleTask deleted);
@Query("SELECT * FROM google_tasks WHERE remote_id = :remoteId LIMIT 1")
GoogleTask getByRemoteId(String remoteId);
@Query("SELECT * FROM google_tasks WHERE task = :taskId AND deleted > 0")
List<GoogleTask> getDeletedByTaskId(long taskId);
@Query("SELECT * FROM google_tasks WHERE task = :taskId")
List<GoogleTask> getAllByTaskId(long taskId);
@Query("DELETE FROM google_tasks")
void deleteAll();
}

@ -49,7 +49,6 @@ public class Location implements Serializable, Parcelable {
@Ignore @Ignore
public Location(XmlReader xml) { public Location(XmlReader xml) {
xml.readLong("task", this::setTask);
xml.readString("name", this::setName); xml.readString("name", this::setName);
xml.readDouble("latitude", this::setLatitude); xml.readDouble("latitude", this::setLatitude);
xml.readDouble("longitude", this::setLongitude); xml.readDouble("longitude", this::setLongitude);
@ -57,7 +56,6 @@ public class Location implements Serializable, Parcelable {
} }
public void writeToXml(XmlWriter xmlWriter) { public void writeToXml(XmlWriter xmlWriter) {
xmlWriter.writeLong("task", task);
xmlWriter.writeString("name", name); xmlWriter.writeString("name", name);
xmlWriter.writeDouble("latitude", latitude); xmlWriter.writeDouble("latitude", latitude);
xmlWriter.writeDouble("longitude", longitude); xmlWriter.writeDouble("longitude", longitude);

@ -27,4 +27,7 @@ public interface LocationDao {
@Insert @Insert
void insert(Location location); void insert(Location location);
@Query("DELETE FROM locations WHERE task = :taskId")
void deleteByTaskId(long taskId);
} }

@ -49,14 +49,12 @@ public class Tag {
@Ignore @Ignore
public Tag(XmlReader xmlReader) { public Tag(XmlReader xmlReader) {
xmlReader.readLong("task", this::setTask);
xmlReader.readString("name", this::setName); xmlReader.readString("name", this::setName);
xmlReader.readString("tag_uid", this::setTagUid); xmlReader.readString("tag_uid", this::setTagUid);
xmlReader.readString("task_uid", this::setTaskUid); xmlReader.readString("task_uid", this::setTaskUid);
} }
public void writeToXml(XmlWriter xmlWriter) { public void writeToXml(XmlWriter xmlWriter) {
xmlWriter.writeLong("task", task);
xmlWriter.writeString("name", name); xmlWriter.writeString("name", name);
xmlWriter.writeString("tag_uid", tagUid); xmlWriter.writeString("tag_uid", tagUid);
xmlWriter.writeString("task_uid", taskUid); xmlWriter.writeString("task_uid", taskUid);

@ -40,4 +40,10 @@ public interface TagDao {
@Query("SELECT * FROM tags WHERE task = :taskId AND tag_uid = :tagUid") @Query("SELECT * FROM tags WHERE task = :taskId AND tag_uid = :tagUid")
Tag getTagByTaskAndTagUid(long taskId, String tagUid); Tag getTagByTaskAndTagUid(long taskId, String tagUid);
@Query("DELETE FROM tags WHERE task = :taskId")
void deleteByTaskId(long taskId);
@Query("DELETE FROM tags WHERE _id = :id")
void deleteById(long id);
} }

@ -63,6 +63,16 @@ public class Migrations {
} }
}; };
private static final Migration MIGRATION_49_50 = new Migration(49, 50) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `google_tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `remote_id` TEXT, `list_id` TEXT, `parent` INTEGER NOT NULL, `indent` INTEGER NOT NULL, `order` INTEGER NOT NULL, `remote_order` INTEGER NOT NULL, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)");
database.execSQL("INSERT INTO `google_tasks` (`task`, `remote_id`, `list_id`, `parent`, `indent`, `order`, `remote_order`, `last_sync`, `deleted`) " +
"SELECT `task`, `value`, `value2`, `value3`, `value4`, `value5`, `value6`, `value7`, `deleted` FROM `metadata` WHERE `key` = 'gtasks'");
database.execSQL("DROP TABLE IF EXISTS `metadata`");
}
};
private static Migration NOOP(int from, int to) { private static Migration NOOP(int from, int to) {
return new Migration(from, to) { return new Migration(from, to) {
@Override @Override
@ -86,6 +96,7 @@ public class Migrations {
NOOP(45, 46), NOOP(45, 46),
MIGRATION_46_47, MIGRATION_46_47,
MIGRATION_47_48, MIGRATION_47_48,
MIGRATION_48_49 MIGRATION_48_49,
MIGRATION_49_50
}; };
} }

@ -1,10 +1,8 @@
package org.tasks.filters; package org.tasks.filters;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Join;
@ -13,17 +11,15 @@ import com.todoroo.astrid.api.CustomFilterCriterion;
import com.todoroo.astrid.api.MultipleSelectCriterion; import com.todoroo.astrid.api.MultipleSelectCriterion;
import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.api.TextInputCriterion; import com.todoroo.astrid.api.TextInputCriterion;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList; import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksListService; import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.GoogleTask;
import org.tasks.data.Tag; import org.tasks.data.Tag;
import org.tasks.gtasks.SyncAdapterHelper; import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
@ -37,7 +33,6 @@ import javax.inject.Inject;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newLinkedHashSet; import static com.google.common.collect.Sets.newLinkedHashSet;
import static com.todoroo.andlib.utility.AndroidUtilities.mapFromContentValues;
public class FilterCriteriaProvider { public class FilterCriteriaProvider {
@ -51,18 +46,15 @@ public class FilterCriteriaProvider {
private final Context context; private final Context context;
private final TagService tagService; private final TagService tagService;
private final GtasksListService gtasksListService; private final GtasksListService gtasksListService;
private final GtasksMetadata gtasksMetadata;
private final Resources r; private final Resources r;
private final SyncAdapterHelper syncAdapterHelper; private final SyncAdapterHelper syncAdapterHelper;
@Inject @Inject
public FilterCriteriaProvider(@ForApplication Context context, TagService tagService, public FilterCriteriaProvider(@ForApplication Context context, TagService tagService,
GtasksListService gtasksListService, GtasksListService gtasksListService, SyncAdapterHelper syncAdapterHelper) {
GtasksMetadata gtasksMetadata, SyncAdapterHelper syncAdapterHelper) {
this.context = context; this.context = context;
this.tagService = tagService; this.tagService = tagService;
this.gtasksListService = gtasksListService; this.gtasksListService = gtasksListService;
this.gtasksMetadata = gtasksMetadata;
this.syncAdapterHelper = syncAdapterHelper; this.syncAdapterHelper = syncAdapterHelper;
r = context.getResources(); r = context.getResources();
@ -186,21 +178,17 @@ public class FilterCriteriaProvider {
listIds[i] = lists.get(i).getRemoteId(); listIds[i] = lists.get(i).getRemoteId();
} }
ContentValues contentValues = gtasksMetadata.createEmptyMetadata(AbstractModel.NO_ID).getMergedValues(); Map<String, Object> values = new HashMap<>();
Map<String, Object> values = mapFromContentValues(contentValues); values.put(GoogleTask.KEY, "?");
values.remove(Metadata.TASK.name);
values.put(GtasksMetadata.LIST_ID.name, "?");
return new MultipleSelectCriterion( return new MultipleSelectCriterion(
IDENTIFIER_GTASKS, IDENTIFIER_GTASKS,
context.getString(R.string.CFC_gtasks_list_text), context.getString(R.string.CFC_gtasks_list_text),
Query.select(Field.field("task")).from(GoogleTask.TABLE)
Query.select(Metadata.TASK).from(Metadata.TABLE).join(Join.inner( .join(Join.inner(Task.TABLE, Field.field("task").eq(Task.ID)))
Task.TABLE, Metadata.TASK.eq(Task.ID))).where(Criterion.and( .where(Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(), TaskDao.TaskCriteria.activeAndVisible(),
MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY), Field.field("list_id").eq("?"))).toString(),
GtasksMetadata.LIST_ID.eq("?"))).toString(),
values, values,
listNames, listNames,
listIds, listIds,

@ -9,12 +9,12 @@ import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskAttachmentDao;
import com.todoroo.astrid.dao.TaskListMetadataDao; import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.dao.UserActivityDao; import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.provider.Astrid2TaskProvider; import com.todoroo.astrid.provider.Astrid2TaskProvider;
import org.tasks.ErrorReportingSingleThreadExecutor; import org.tasks.ErrorReportingSingleThreadExecutor;
import org.tasks.analytics.Tracker; import org.tasks.analytics.Tracker;
import org.tasks.data.AlarmDao; import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.LocationDao; import org.tasks.data.LocationDao;
import org.tasks.data.TagDao; import org.tasks.data.TagDao;
import org.tasks.db.Migrations; import org.tasks.db.Migrations;
@ -95,6 +95,11 @@ public class ApplicationModule {
return database.getStoreObjectDao(); return database.getStoreObjectDao();
} }
@Provides
public GoogleTaskDao getGoogleTaskDao(Database database) {
return database.getGoogleTaskDao();
}
@Provides @Provides
public AlarmDao getAlarmDao(Database database) { public AlarmDao getAlarmDao(Database database) {
return database.getAlarmDao(); return database.getAlarmDao();
@ -102,7 +107,7 @@ public class ApplicationModule {
@Provides @Provides
public LocationDao getGeofenceDao(Database database) { public LocationDao getGeofenceDao(Database database) {
return database.getGeofenceDao(); return database.getLocationDao();
} }
@Provides @Provides

@ -3,7 +3,6 @@ package org.tasks.tasklist;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.MenuItem; import android.view.MenuItem;
@ -52,7 +51,7 @@ public class TagListFragment extends TaskListFragment {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_tag_settings: case R.id.menu_tag_settings:
Intent intent = new Intent(getActivity(), TagSettingsActivity.class); Intent intent = new Intent(getActivity(), TagSettingsActivity.class);
intent.putExtra(TagSettingsActivity.EXTRA_TAG_DATA, (Parcelable) tagData); intent.putExtra(TagSettingsActivity.EXTRA_TAG_DATA, tagData);
startActivityForResult(intent, REQUEST_EDIT_TAG); startActivityForResult(intent, REQUEST_EDIT_TAG);
return true; return true;
default: default:

Loading…
Cancel
Save