Add 'google_tasks' table

pull/618/head
Alex Baker 6 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;
import org.tasks.data.Location;
import java.util.List;
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.Intent;
import org.tasks.data.Location;
import org.tasks.preferences.Preferences;
public class PlacePicker {
@ -11,7 +12,7 @@ public class PlacePicker {
return null;
}
public static Geofence getPlace(Context context, Intent data, Preferences preferences) {
public static Location getPlace(Context context, Intent data, Preferences preferences) {
return null;
}
}

@ -2,9 +2,7 @@ package com.todoroo.astrid.alarms;
import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import org.junit.After;
@ -12,6 +10,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.injection.InjectingTestCase;
import org.tasks.injection.TestComponent;
import org.tasks.jobs.AlarmJob;
@ -30,7 +30,7 @@ import static org.tasks.makers.TaskMaker.newTask;
@RunWith(AndroidJUnit4.class)
public class AlarmJobServiceTest extends InjectingTestCase {
@Inject MetadataDao metadataDao;
@Inject AlarmDao alarmDao;
@Inject TaskDao taskDao;
private AlarmService alarmService;
@ -39,7 +39,7 @@ public class AlarmJobServiceTest extends InjectingTestCase {
@Before
public void before() {
jobs = mock(JobQueue.class);
alarmService = new AlarmService(metadataDao, jobs);
alarmService = new AlarmService(alarmDao, jobs);
}
@After
@ -54,12 +54,8 @@ public class AlarmJobServiceTest extends InjectingTestCase {
taskDao.persist(task);
DateTime alarmTime = new DateTime(2017, 9, 24, 19, 57);
Metadata alarm = new Metadata();
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);
Alarm alarm = new Alarm(task.getId(), alarmTime.getMillis());
alarm.setId(alarmDao.insert(alarm));
alarmService.scheduleAllAlarms();
@ -75,12 +71,7 @@ public class AlarmJobServiceTest extends InjectingTestCase {
taskDao.persist(task);
Metadata alarm = new Metadata();
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);
alarmDao.insert(new Alarm(task.getId(), alarmTime.getMillis()));
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()));
}
private Task newFromDue(Frequency frequency, int interval, DateTime dueDate) {
private Task newFromDue(Frequency frequency, int interval, DateTime dueDateTime) {
return new Task() {{
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() {{
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() {{
setRecurrence(getRecurrenceRule(frequency, interval, true));
setDueDate(dueDate.getMillis());
setDueDate(dueDateTime.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() {{
setRecurrence(getRecurrenceRule(Frequency.WEEKLY, interval, true, weekdays));
setDueDate(dueDate.getMillis());
setDueDate(dueDateTime.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.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.preferences.PermissionChecker;
import org.tasks.preferences.PermissivePermissionChecker;
@ -30,7 +33,6 @@ public class TestModule {
public Database getDatabase() {
return Room.inMemoryDatabaseBuilder(context, Database.class)
.fallbackToDestructiveMigration()
.addCallback(Migrations.ON_CREATE)
.build();
}
@ -59,6 +61,26 @@ public class TestModule {
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
@Provides
@ForApplication

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

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

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

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

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

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

@ -1,5 +1,7 @@
package org.tasks.location;
import org.tasks.data.Location;
import java.util.List;
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.Intent;
import org.tasks.data.Location;
import org.tasks.preferences.Preferences;
public class PlacePicker {
@ -11,7 +12,7 @@ public class PlacePicker {
return null;
}
public static Geofence getPlace(Context context, Intent data, Preferences preferences) {
public static Location getPlace(Context context, Intent data, Preferences preferences) {
return null;
}
}

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

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

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

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

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

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

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

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

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

@ -43,6 +43,8 @@ class BackupConstants {
public static final String TAG_TAG = "tag";
public static final String GOOGLE_TASKS_TAG = "googletasks";
/** Tag containing a tagdata item */
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.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.UserActivity;
@ -33,6 +31,8 @@ import org.tasks.R;
import org.tasks.backup.XmlWriter;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.data.Tag;
@ -66,10 +66,10 @@ public class TasksXmlExporter {
// --- implementation
private final TagDataDao tagDataDao;
private final MetadataDao metadataDao;
private final AlarmDao alarmDao;
private final LocationDao locationDao;
private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final TaskDao taskDao;
private UserActivityDao userActivityDao;
private final Preferences preferences;
@ -98,16 +98,17 @@ public class TasksXmlExporter {
}
@Inject
public TasksXmlExporter(TagDataDao tagDataDao, MetadataDao metadataDao, TaskDao taskDao, UserActivityDao userActivityDao,
Preferences preferences, AlarmDao alarmDao, LocationDao locationDao, TagDao tagDao) {
public TasksXmlExporter(TagDataDao tagDataDao, TaskDao taskDao, UserActivityDao userActivityDao,
Preferences preferences, AlarmDao alarmDao, LocationDao locationDao,
TagDao tagDao, GoogleTaskDao googleTaskDao) {
this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.taskDao = taskDao;
this.userActivityDao = userActivityDao;
this.preferences = preferences;
this.alarmDao = alarmDao;
this.locationDao = locationDao;
this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
}
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) {
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);
for (Alarm alarm : alarmDao.getAlarms(task.getId())) {
try {
@ -255,6 +247,15 @@ public class TasksXmlExporter {
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.Query;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.UserActivity;
@ -31,6 +29,8 @@ import org.tasks.R;
import org.tasks.backup.XmlReader;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.data.Tag;
@ -50,13 +50,13 @@ import timber.log.Timber;
public class TasksXmlImporter {
private final TagDataDao tagDataDao;
private final MetadataDao metadataDao;
private final UserActivityDao userActivityDao;
private final DialogBuilder dialogBuilder;
private final TaskDao taskDao;
private LocalBroadcastManager localBroadcastManager;
private final LocalBroadcastManager localBroadcastManager;
private final AlarmDao alarmDao;
private final TagDao tagDao;
private GoogleTaskDao googleTaskDao;
private final LocationDao locationDao;
private Activity activity;
@ -73,11 +73,11 @@ public class TasksXmlImporter {
}
@Inject
public TasksXmlImporter(TagDataDao tagDataDao, MetadataDao metadataDao, UserActivityDao userActivityDao,
public TasksXmlImporter(TagDataDao tagDataDao, UserActivityDao userActivityDao,
DialogBuilder dialogBuilder, TaskDao taskDao, LocationDao locationDao,
LocalBroadcastManager localBroadcastManager, AlarmDao alarmDao, TagDao tagDao) {
LocalBroadcastManager localBroadcastManager, AlarmDao alarmDao,
TagDao tagDao, GoogleTaskDao googleTaskDao) {
this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.userActivityDao = userActivityDao;
this.dialogBuilder = dialogBuilder;
this.taskDao = taskDao;
@ -85,6 +85,7 @@ public class TasksXmlImporter {
this.localBroadcastManager = localBroadcastManager;
this.alarmDao = alarmDao;
this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
}
public void importTasks(Activity activity, String input, ProgressDialog progressDialog) {
@ -165,7 +166,6 @@ public class TasksXmlImporter {
XmlPullParser xpp;
final Task currentTask = new Task();
final Metadata metadata = new Metadata();
public Format2TaskImporter() { }
public Format2TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException {
@ -235,7 +235,6 @@ public class TasksXmlImporter {
}
UserActivity userActivity = new UserActivity(new XmlReader(xpp));
userActivityDao.createNew(userActivity);
}
@ -245,7 +244,7 @@ public class TasksXmlImporter {
}
Alarm alarm = new Alarm(new XmlReader(xpp));
alarm.setTask(currentTask.getId());
alarmDao.insert(alarm);
}
@ -255,7 +254,7 @@ public class TasksXmlImporter {
}
Location location = new Location(new XmlReader(xpp));
location.setTask(currentTask.getId());
locationDao.insert(location);
}
@ -265,32 +264,42 @@ public class TasksXmlImporter {
}
Tag tag = new Tag(new XmlReader(xpp));
tag.setTask(currentTask.getId());
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) {
if(!currentTask.isSaved()) {
return;
}
metadata.clear();
deserializeModel(metadata, Metadata.PROPERTIES);
if (metadata.getKey().equals("alarm")) {
XmlReader xml = new XmlReader(xpp);
String key = xml.readString("key");
if ("alarm".equals(key)) {
Alarm alarm = new Alarm();
alarm.setTask(currentTask.getId());
alarm.setTime(Long.valueOf(metadata.getValue(Metadata.VALUE1)));
alarm.setTime(xml.readLong("value"));
alarmDao.insert(alarm);
} else if (metadata.getKey().equals("geofence")) {
} else if ("geofence".equals(key)) {
Location location = new Location();
location.setTask(currentTask.getId());
location.setName(metadata.getValue(Metadata.VALUE1));
location.setLatitude(Double.valueOf(metadata.getValue(Metadata.VALUE2)));
location.setLongitude(Double.valueOf(metadata.getValue(Metadata.VALUE3)));
location.setRadius(Integer.valueOf(metadata.getValue(Metadata.VALUE4)));
location.setName(xml.readString("value"));
location.setLatitude(xml.readDouble("value2"));
location.setLongitude(xml.readDouble("value3"));
location.setRadius(xml.readInteger("value4"));
locationDao.insert(location);
} else if (metadata.getKey().equals("tags-tag")) {
String tagUid = metadata.getValue(Metadata.VALUE2);
String name = metadata.getValue(Metadata.VALUE1);
} else if ("tags-tag".equals(key)) {
String name = xml.readString("value");
String tagUid = xml.readString("value2");
if (tagDao.getTagByTaskAndTagUid(currentTask.getId(), tagUid) == null) {
tagDao.insert(new Tag(currentTask.getId(), currentTask.getUuid(), name, tagUid));
}
@ -305,10 +314,18 @@ public class TasksXmlImporter {
tagDataDao.insert(tagData);
}
}
} else {
metadata.setId(Metadata.NO_ID);
metadata.setTask(currentTask.getId());
metadataDao.persist(metadata);
} else if ("gtasks".equals(key)) {
GoogleTask googleTask = new GoogleTask();
googleTask.setTask(currentTask.getId());
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:
parseTag();
break;
case BackupConstants.GOOGLE_TASKS_TAG:
parseGoogleTask();
break;
}
} catch (Exception e) {
errorCount++;

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

@ -15,7 +15,6 @@ import android.database.sqlite.SQLiteDatabase;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.TagData;
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.AlarmDao;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.data.Tag;
@ -51,12 +52,12 @@ import timber.log.Timber;
TaskListMetadata.class,
StoreObject.class,
Task.class,
Metadata.class,
Alarm.class,
Location.class,
Tag.class
Tag.class,
GoogleTask.class
},
version = 49)
version = 50)
public abstract class Database extends RoomDatabase {
public abstract NotificationDao notificationDao();
@ -66,14 +67,14 @@ public abstract class Database extends RoomDatabase {
public abstract TaskListMetadataDao getTaskListMetadataDao();
public abstract StoreObjectDao getStoreObjectDao();
public abstract AlarmDao getAlarmDao();
public abstract LocationDao getGeofenceDao();
public abstract LocationDao getLocationDao();
public abstract TagDao getTagDao();
public abstract GoogleTaskDao getGoogleTaskDao();
public static final String NAME = "database";
public static final Table[] TABLES = new Table[] {
Task.TABLE,
Metadata.TABLE
Task.TABLE
};
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.astrid.api.Filter;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task;
@ -26,6 +25,10 @@ import com.todoroo.astrid.data.TaskApiDao;
import org.tasks.LocalBroadcastManager;
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.ForApplication;
import org.tasks.jobs.AfterSaveIntentService;
@ -52,16 +55,25 @@ public class TaskDao {
private final RemoteModelDao<Task> dao;
private final LocalBroadcastManager localBroadcastManager;
private final MetadataDao metadataDao;
private final Database database;
private final Preferences preferences;
private final AlarmDao alarmDao;
private final TagDao tagDao;
private final LocationDao locationDao;
private final GoogleTaskDao googleTaskDao;
private final Context context;
@Inject
public TaskDao(@ForApplication Context context, Database database, MetadataDao metadataDao,
Preferences preferences, LocalBroadcastManager localBroadcastManager) {
public TaskDao(@ForApplication Context context, Database database,
Preferences preferences, LocalBroadcastManager localBroadcastManager,
AlarmDao alarmDao, TagDao tagDao, LocationDao locationDao, GoogleTaskDao googleTaskDao) {
this.context = context;
this.database = database;
this.preferences = preferences;
this.metadataDao = metadataDao;
this.alarmDao = alarmDao;
this.tagDao = tagDao;
this.locationDao = locationDao;
this.googleTaskDao = googleTaskDao;
this.localBroadcastManager = localBroadcastManager;
dao = new RemoteModelDao<>(database, Task.class);
}
@ -188,7 +200,10 @@ public class TaskDao {
}
// delete all metadata
metadataDao.deleteWhere(MetadataCriteria.byTask(id));
alarmDao.deleteByTaskId(id);
locationDao.deleteByTaskId(id);
tagDao.deleteByTaskId(id);
googleTaskDao.deleteByTaskId(id);
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;
@Entity(tableName = "tagdata")
public final class TagData implements Parcelable, Serializable {
public final class TagData implements Parcelable {
@PrimaryKey(autoGenerate = true)
@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.Multimaps;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.tags.TagService;
@ -48,7 +47,6 @@ public class StartupService {
private final Tracker tracker;
private final TagDataDao tagDataDao;
private final TagService tagService;
private final MetadataDao metadataDao;
private final LocalBroadcastManager localBroadcastManager;
private final Context context;
private final TagDao tagDao;
@ -56,7 +54,7 @@ public class StartupService {
@Inject
public StartupService(Database database, Preferences preferences, TaskDeleter taskDeleter,
Tracker tracker, TagDataDao tagDataDao, TagService tagService,
MetadataDao metadataDao, LocalBroadcastManager localBroadcastManager,
LocalBroadcastManager localBroadcastManager,
@ForApplication Context context, TagDao tagDao) {
this.database = database;
this.preferences = preferences;
@ -64,7 +62,6 @@ public class StartupService {
this.tracker = tracker;
this.tagDataDao = tagDataDao;
this.tagService = tagService;
this.metadataDao = metadataDao;
this.localBroadcastManager = localBroadcastManager;
this.context = context;
this.tagDao = tagDao;
@ -158,7 +155,7 @@ public class StartupService {
for (Long key : metadataByTask.keySet()) {
ImmutableList<Tag> tagData = metadataByTask.get(key);
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.text.TextUtils;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData;
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.utility.TitleParser;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.Tag;
import org.tasks.data.TagDao;
import org.tasks.preferences.Preferences;
@ -33,22 +32,22 @@ public class TaskCreator {
private final GCalHelper gcalHelper;
private final Preferences preferences;
private final MetadataDao metadataDao;
private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final TagDataDao tagDataDao;
private final TaskDao taskDao;
private final TagService tagService;
@Inject
public TaskCreator(GCalHelper gcalHelper, Preferences preferences, MetadataDao metadataDao,
TagDataDao tagDataDao, TaskDao taskDao, TagService tagService, TagDao tagDao) {
public TaskCreator(GCalHelper gcalHelper, Preferences preferences, TagDataDao tagDataDao,
TaskDao taskDao, TagService tagService, TagDao tagDao, GoogleTaskDao googleTaskDao) {
this.gcalHelper = gcalHelper;
this.preferences = preferences;
this.metadataDao = metadataDao;
this.tagDataDao = tagDataDao;
this.taskDao = taskDao;
this.tagService = tagService;
this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
}
public Task basicQuickAddTask(String title) {
@ -90,14 +89,12 @@ public class TaskCreator {
Timber.e(e, e.getMessage());
}
ContentValues forMetadata = null;
if (values != null && values.size() > 0) {
ContentValues forTask = new ContentValues();
forMetadata = new ContentValues();
outer: for (Map.Entry<String, Object> item : values.entrySet()) {
for (Map.Entry<String, Object> item : values.entrySet()) {
String key = item.getKey();
Object value = item.getValue();
if (key.equals(Tag.KEY)) {
if (key.equals(Tag.KEY) || key.equals(GoogleTask.KEY)) {
continue;
}
@ -105,13 +102,6 @@ public class TaskCreator {
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);
}
task.mergeWithoutReplacement(forTask);
@ -119,21 +109,20 @@ public class TaskCreator {
saveWithoutPublishingFilterUpdate(task);
if (values != null && values.containsKey(Tag.KEY)) {
createLink(task, (String) values.get(Tag.KEY));
if (values != null) {
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) {
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;
}

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

@ -40,7 +40,6 @@ import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
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
*/
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) {
// 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

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

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

@ -26,5 +26,8 @@ public interface AlarmDao {
void delete(Alarm alarm);
@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
public Location(XmlReader xml) {
xml.readLong("task", this::setTask);
xml.readString("name", this::setName);
xml.readDouble("latitude", this::setLatitude);
xml.readDouble("longitude", this::setLongitude);
@ -57,7 +56,6 @@ public class Location implements Serializable, Parcelable {
}
public void writeToXml(XmlWriter xmlWriter) {
xmlWriter.writeLong("task", task);
xmlWriter.writeString("name", name);
xmlWriter.writeDouble("latitude", latitude);
xmlWriter.writeDouble("longitude", longitude);

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

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

@ -40,4 +40,10 @@ public interface TagDao {
@Query("SELECT * FROM tags WHERE task = :taskId AND tag_uid = :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) {
return new Migration(from, to) {
@Override
@ -86,6 +96,7 @@ public class Migrations {
NOOP(45, 46),
MIGRATION_46_47,
MIGRATION_47_48,
MIGRATION_48_49
MIGRATION_48_49,
MIGRATION_49_50
};
}

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

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

@ -3,7 +3,6 @@ package org.tasks.tasklist;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
@ -52,7 +51,7 @@ public class TagListFragment extends TaskListFragment {
switch (item.getItemId()) {
case R.id.menu_tag_settings:
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);
return true;
default:

Loading…
Cancel
Save