diff --git a/app/schemas/com.todoroo.astrid.dao.Database/88.json b/app/schemas/com.todoroo.astrid.dao.Database/88.json new file mode 100644 index 000000000..d6a553397 --- /dev/null +++ b/app/schemas/com.todoroo.astrid.dao.Database/88.json @@ -0,0 +1,1459 @@ +{ + "formatVersion": 1, + "database": { + "version": 88, + "identityHash": "e6a358a252e68fc5fe426504801c1d0c", + "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, `location` INTEGER, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "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 + }, + { + "fieldPath": "location", + "columnName": "location", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_notification_task", + "unique": true, + "columnNames": [ + "task" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_notification_task` ON `${TABLE_NAME}` (`task`)" + } + ], + "foreignKeys": [ + { + "table": "tasks", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "task" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "tagdata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `name` TEXT, `color` INTEGER, `tagOrdering` TEXT, `td_icon` INTEGER, `td_order` INTEGER NOT NULL)", + "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": "icon", + "columnName": "td_icon", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "td_order", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "userActivity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `message` TEXT, `picture` TEXT, `target_id` TEXT, `created_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "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 + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attachment_file", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`file_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_uuid` TEXT NOT NULL, `filename` TEXT NOT NULL, `uri` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "file_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "file_uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "filename", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "uri", + "columnName": "uri", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "file_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "task_list_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "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": "tasks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `importance` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `hideUntil` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `completed` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `notes` TEXT, `estimatedSeconds` INTEGER NOT NULL, `elapsedSeconds` INTEGER NOT NULL, `timerStart` INTEGER NOT NULL, `notificationFlags` INTEGER NOT NULL, `lastNotified` INTEGER NOT NULL, `recurrence` TEXT, `repeat_from` INTEGER NOT NULL DEFAULT 0, `calendarUri` TEXT, `remoteId` TEXT, `collapsed` INTEGER NOT NULL, `parent` INTEGER NOT NULL, `read_only` INTEGER NOT NULL DEFAULT 0)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "priority", + "columnName": "importance", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dueDate", + "columnName": "dueDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hideUntil", + "columnName": "hideUntil", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "creationDate", + "columnName": "created", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "modificationDate", + "columnName": "modified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "completionDate", + "columnName": "completed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deletionDate", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notes", + "columnName": "notes", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "estimatedSeconds", + "columnName": "estimatedSeconds", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "elapsedSeconds", + "columnName": "elapsedSeconds", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timerStart", + "columnName": "timerStart", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ringFlags", + "columnName": "notificationFlags", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reminderLast", + "columnName": "lastNotified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recurrence", + "columnName": "recurrence", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "repeatFrom", + "columnName": "repeat_from", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "calendarURI", + "columnName": "calendarUri", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isCollapsed", + "columnName": "collapsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readOnly", + "columnName": "read_only", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "t_rid", + "unique": true, + "columnNames": [ + "remoteId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `t_rid` ON `${TABLE_NAME}` (`remoteId`)" + }, + { + "name": "active_and_visible", + "unique": false, + "columnNames": [ + "completed", + "deleted", + "hideUntil" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `active_and_visible` ON `${TABLE_NAME}` (`completed`, `deleted`, `hideUntil`)" + } + ], + "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, `type` INTEGER NOT NULL DEFAULT 0, `repeat` INTEGER NOT NULL DEFAULT 0, `interval` INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "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 + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "repeat", + "columnName": "repeat", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "interval", + "columnName": "interval", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_alarms_task", + "unique": false, + "columnNames": [ + "task" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_alarms_task` ON `${TABLE_NAME}` (`task`)" + } + ], + "foreignKeys": [ + { + "table": "tasks", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "task" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "places", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`place_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uid` TEXT, `name` TEXT, `address` TEXT, `phone` TEXT, `url` TEXT, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `place_color` INTEGER NOT NULL, `place_icon` INTEGER NOT NULL, `place_order` INTEGER NOT NULL, `radius` INTEGER NOT NULL DEFAULT 250)", + "fields": [ + { + "fieldPath": "id", + "columnName": "place_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "phone", + "columnName": "phone", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "latitude", + "columnName": "latitude", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "longitude", + "columnName": "longitude", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "place_color", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "icon", + "columnName": "place_icon", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "place_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "radius", + "columnName": "radius", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "250" + } + ], + "primaryKey": { + "columnNames": [ + "place_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "place_uid", + "unique": true, + "columnNames": [ + "uid" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `place_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "geofences", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`geofence_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `place` TEXT, `arrival` INTEGER NOT NULL, `departure` INTEGER NOT NULL, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "geofence_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "task", + "columnName": "task", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "place", + "columnName": "place", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isArrival", + "columnName": "arrival", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDeparture", + "columnName": "departure", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "geofence_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_geofences_task", + "unique": false, + "columnNames": [ + "task" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_geofences_task` ON `${TABLE_NAME}` (`task`)" + } + ], + "foreignKeys": [ + { + "table": "tasks", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "task" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "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, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "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": [ + { + "name": "index_tags_task", + "unique": false, + "columnNames": [ + "task" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tags_task` ON `${TABLE_NAME}` (`task`)" + } + ], + "foreignKeys": [ + { + "table": "tasks", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "task" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "google_tasks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`gt_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gt_task` INTEGER NOT NULL, `gt_remote_id` TEXT, `gt_list_id` TEXT, `gt_parent` INTEGER NOT NULL, `gt_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_order` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, `gt_last_sync` INTEGER NOT NULL, `gt_deleted` INTEGER NOT NULL, FOREIGN KEY(`gt_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "gt_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "task", + "columnName": "gt_task", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "gt_remote_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "listId", + "columnName": "gt_list_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "parent", + "columnName": "gt_parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteParent", + "columnName": "gt_remote_parent", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isMoved", + "columnName": "gt_moved", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "gt_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteOrder", + "columnName": "gt_remote_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastSync", + "columnName": "gt_last_sync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "gt_deleted", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "gt_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "gt_list_parent", + "unique": false, + "columnNames": [ + "gt_list_id", + "gt_parent" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `gt_list_parent` ON `${TABLE_NAME}` (`gt_list_id`, `gt_parent`)" + }, + { + "name": "index_google_tasks_gt_task", + "unique": false, + "columnNames": [ + "gt_task" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_google_tasks_gt_task` ON `${TABLE_NAME}` (`gt_task`)" + } + ], + "foreignKeys": [ + { + "table": "tasks", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "gt_task" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "filters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `sql` TEXT, `values` TEXT, `criterion` TEXT, `f_color` INTEGER, `f_icon` INTEGER, `f_order` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sql", + "columnName": "sql", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "values", + "columnName": "values", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "criterion", + "columnName": "criterion", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "f_color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "icon", + "columnName": "f_icon", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "f_order", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "google_task_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`gtl_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gtl_account` TEXT, `gtl_remote_id` TEXT, `gtl_title` TEXT, `gtl_remote_order` INTEGER NOT NULL, `gtl_last_sync` INTEGER NOT NULL, `gtl_color` INTEGER, `gtl_icon` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "gtl_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "account", + "columnName": "gtl_account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "gtl_remote_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "gtl_title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "gtl_remote_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastSync", + "columnName": "gtl_last_sync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "gtl_color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "icon", + "columnName": "gtl_icon", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "gtl_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "caldav_lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cdl_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cdl_account` TEXT, `cdl_uuid` TEXT, `cdl_name` TEXT, `cdl_color` INTEGER NOT NULL, `cdl_ctag` TEXT, `cdl_url` TEXT, `cdl_icon` INTEGER, `cdl_order` INTEGER NOT NULL, `cdl_access` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "cdl_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "account", + "columnName": "cdl_account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "cdl_uuid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "cdl_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "cdl_color", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ctag", + "columnName": "cdl_ctag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "cdl_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "icon", + "columnName": "cdl_icon", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "cdl_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "access", + "columnName": "cdl_access", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "cdl_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "caldav_tasks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `cd_order` INTEGER, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "cd_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "task", + "columnName": "cd_task", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "calendar", + "columnName": "cd_calendar", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "object", + "columnName": "cd_object", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "cd_remote_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "etag", + "columnName": "cd_etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastSync", + "columnName": "cd_last_sync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "cd_deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteParent", + "columnName": "cd_remote_parent", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "cd_order", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "cd_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_caldav_tasks_cd_task", + "unique": false, + "columnNames": [ + "cd_task" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_caldav_tasks_cd_task` ON `${TABLE_NAME}` (`cd_task`)" + } + ], + "foreignKeys": [ + { + "table": "tasks", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "cd_task" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "caldav_accounts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cda_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cda_uuid` TEXT, `cda_name` TEXT, `cda_url` TEXT, `cda_username` TEXT, `cda_password` TEXT, `cda_error` TEXT, `cda_account_type` INTEGER NOT NULL, `cda_collapsed` INTEGER NOT NULL, `cda_server_type` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "cda_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "cda_uuid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "cda_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "cda_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "username", + "columnName": "cda_username", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "password", + "columnName": "cda_password", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "error", + "columnName": "cda_error", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "accountType", + "columnName": "cda_account_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCollapsed", + "columnName": "cda_collapsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "serverType", + "columnName": "cda_server_type", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "cda_id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "principals", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` INTEGER NOT NULL, `href` TEXT NOT NULL, `email` TEXT, `display_name` TEXT, FOREIGN KEY(`account`) REFERENCES `caldav_accounts`(`cda_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "account", + "columnName": "account", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "href", + "columnName": "href", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayName", + "columnName": "display_name", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_principals_account_href", + "unique": true, + "columnNames": [ + "account", + "href" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_principals_account_href` ON `${TABLE_NAME}` (`account`, `href`)" + } + ], + "foreignKeys": [ + { + "table": "caldav_accounts", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "account" + ], + "referencedColumns": [ + "cda_id" + ] + } + ] + }, + { + "tableName": "principal_access", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `principal` INTEGER NOT NULL, `list` INTEGER NOT NULL, `invite` INTEGER NOT NULL, `access` INTEGER NOT NULL, FOREIGN KEY(`principal`) REFERENCES `principals`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`list`) REFERENCES `caldav_lists`(`cdl_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "principal", + "columnName": "principal", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "list", + "columnName": "list", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "invite", + "columnName": "invite", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "access", + "columnName": "access", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_principal_access_list_principal", + "unique": true, + "columnNames": [ + "list", + "principal" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_access_list_principal` ON `${TABLE_NAME}` (`list`, `principal`)" + }, + { + "name": "index_principal_access_principal", + "unique": false, + "columnNames": [ + "principal" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_principal_access_principal` ON `${TABLE_NAME}` (`principal`)" + } + ], + "foreignKeys": [ + { + "table": "principals", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "principal" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "caldav_lists", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "list" + ], + "referencedColumns": [ + "cdl_id" + ] + } + ] + }, + { + "tableName": "attachment", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`attachment_id` INTEGER PRIMARY KEY AUTOINCREMENT, `task` INTEGER NOT NULL, `file` INTEGER NOT NULL, `file_uuid` TEXT NOT NULL, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`file`) REFERENCES `attachment_file`(`file_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "attachment_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "task", + "columnName": "task", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fileId", + "columnName": "file", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attachmentUid", + "columnName": "file_uuid", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "attachment_id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_attachment_task_file", + "unique": true, + "columnNames": [ + "task", + "file" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_attachment_task_file` ON `${TABLE_NAME}` (`task`, `file`)" + }, + { + "name": "index_attachment_task", + "unique": false, + "columnNames": [ + "task" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_attachment_task` ON `${TABLE_NAME}` (`task`)" + }, + { + "name": "index_attachment_file", + "unique": false, + "columnNames": [ + "file" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_attachment_file` ON `${TABLE_NAME}` (`file`)" + } + ], + "foreignKeys": [ + { + "table": "tasks", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "task" + ], + "referencedColumns": [ + "_id" + ] + }, + { + "table": "attachment_file", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "file" + ], + "referencedColumns": [ + "file_id" + ] + } + ] + } + ], + "views": [], + "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, 'e6a358a252e68fc5fe426504801c1d0c')" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.kt b/app/src/androidTest/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.kt index 18ed57651..c0f300508 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.kt +++ b/app/src/androidTest/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.kt @@ -11,7 +11,8 @@ import org.junit.Assert.assertNull import org.junit.Before import org.junit.Test import org.tasks.LocalBroadcastManager -import org.tasks.data.GoogleTaskAccount +import org.tasks.data.CaldavAccount +import org.tasks.data.CaldavDao import org.tasks.data.GoogleTaskListDao import org.tasks.injection.InjectingTestCase import org.tasks.injection.ProductionModule @@ -29,6 +30,7 @@ class GtasksListServiceTest : InjectingTestCase() { @Inject lateinit var taskDeleter: TaskDeleter @Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var googleTaskListDao: GoogleTaskListDao + @Inject lateinit var caldavDao: CaldavDao private lateinit var gtasksListService: GtasksListService @@ -87,8 +89,11 @@ class GtasksListServiceTest : InjectingTestCase() { } private suspend fun setLists(vararg list: TaskList) { - val account = GoogleTaskAccount("account") - googleTaskListDao.insert(account) + val account = CaldavAccount().apply { + username = "account" + uuid = "account" + } + caldavDao.insert(account) gtasksListService.updateLists(account, listOf(*list)) } } \ No newline at end of file diff --git a/app/src/androidTest/java/org/tasks/data/GoogleTaskListDaoTest.kt b/app/src/androidTest/java/org/tasks/data/GoogleTaskListDaoTest.kt index dcb717b1b..aaeffbff8 100644 --- a/app/src/androidTest/java/org/tasks/data/GoogleTaskListDaoTest.kt +++ b/app/src/androidTest/java/org/tasks/data/GoogleTaskListDaoTest.kt @@ -17,14 +17,17 @@ import javax.inject.Inject @HiltAndroidTest class GoogleTaskListDaoTest : InjectingTestCase() { @Inject lateinit var googleTaskListDao: GoogleTaskListDao + @Inject lateinit var caldavDao: CaldavDao @Test fun noResultsForEmptyAccount() = runBlocking { - val account = GoogleTaskAccount() - account.account = "user@gmail.com" - googleTaskListDao.insert(account) + val account = CaldavAccount().apply { + uuid = "user@gmail.com" + username = "user@gmail.com" + } + caldavDao.insert(account) - assertTrue(googleTaskListDao.getGoogleTaskFilters(account.account!!).isEmpty()) + assertTrue(googleTaskListDao.getGoogleTaskFilters(account.username!!).isEmpty()) } @Test diff --git a/app/src/main/java/com/todoroo/astrid/adapter/SubheaderClickHandler.kt b/app/src/main/java/com/todoroo/astrid/adapter/SubheaderClickHandler.kt index f2dd014e9..59f05377e 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/SubheaderClickHandler.kt +++ b/app/src/main/java/com/todoroo/astrid/adapter/SubheaderClickHandler.kt @@ -7,7 +7,6 @@ import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager import org.tasks.data.CaldavDao -import org.tasks.data.GoogleTaskDao import org.tasks.dialogs.NewFilterDialog import org.tasks.filters.NavigationDrawerSubheader import org.tasks.filters.NavigationDrawerSubheader.SubheaderType.* @@ -19,7 +18,6 @@ import javax.inject.Inject class SubheaderClickHandler @Inject constructor( private val activity: Activity, private val preferences: Preferences, - private val googleTaskDao: GoogleTaskDao, private val caldavDao: CaldavDao, private val localBroadcastManager: LocalBroadcastManager, ): SubheaderViewHolder.ClickHandler { @@ -28,8 +26,10 @@ class SubheaderClickHandler @Inject constructor( val collapsed = !subheader.isCollapsed when (subheader.subheaderType) { PREFERENCE -> preferences.setBoolean(subheader.id.toInt(), collapsed) - GOOGLE_TASKS -> googleTaskDao.setCollapsed(subheader.id, collapsed) - CALDAV, TASKS, ETESYNC -> caldavDao.setCollapsed(subheader.id, collapsed) + GOOGLE_TASKS, + CALDAV, + TASKS, + ETESYNC -> caldavDao.setCollapsed(subheader.id, collapsed) } localBroadcastManager.broadcastRefreshList() } diff --git a/app/src/main/java/com/todoroo/astrid/core/BuiltInFilterExposer.kt b/app/src/main/java/com/todoroo/astrid/core/BuiltInFilterExposer.kt index 8ab12a976..917e91ce3 100644 --- a/app/src/main/java/com/todoroo/astrid/core/BuiltInFilterExposer.kt +++ b/app/src/main/java/com/todoroo/astrid/core/BuiltInFilterExposer.kt @@ -135,10 +135,9 @@ class BuiltInFilterExposer @Inject constructor( .join(Join.left(CaldavTask.TABLE, and(CaldavTask.TASK.eq(Task.ID)))) .join(Join.left(GoogleTaskList.TABLE, GoogleTaskList.REMOTE_ID.eq(GoogleTask.LIST))) .join(Join.left(CaldavCalendar.TABLE, CaldavCalendar.UUID.eq(CaldavTask.CALENDAR))) - .join(Join.left(GoogleTaskAccount.TABLE, GoogleTaskAccount.ACCOUNT.eq(GoogleTaskList.ACCOUNT))) .join(Join.left(CaldavAccount.TABLE, CaldavAccount.UUID.eq(CaldavCalendar.ACCOUNT))) .where(or( - and(GoogleTask.ID.gt(0), GoogleTaskAccount.ACCOUNT.eq(null)), + and(GoogleTask.ID.gt(0), CaldavAccount.UUID.eq(null)), and(CaldavTask.ID.gt(0), CaldavAccount.UUID.eq(null)))) ).apply { icon = R.drawable.ic_outline_cloud_off_24px diff --git a/app/src/main/java/com/todoroo/astrid/dao/Database.kt b/app/src/main/java/com/todoroo/astrid/dao/Database.kt index cd20c7ae9..bae3e287f 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/Database.kt +++ b/app/src/main/java/com/todoroo/astrid/dao/Database.kt @@ -28,7 +28,6 @@ import org.tasks.notifications.NotificationDao CaldavCalendar::class, CaldavTask::class, CaldavAccount::class, - GoogleTaskAccount::class, Principal::class, PrincipalAccess::class, Attachment::class, @@ -36,7 +35,7 @@ import org.tasks.notifications.NotificationDao autoMigrations = [ AutoMigration(from = 83, to = 84, spec = Migrations.AutoMigrate83to84::class), ], - version = 87 + version = 88 ) abstract class Database : RoomDatabase() { abstract fun notificationDao(): NotificationDao diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.kt b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.kt index ab6d288da..79872443e 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.kt +++ b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.kt @@ -8,11 +8,10 @@ package com.todoroo.astrid.gtasks import com.google.api.services.tasks.model.TaskList import com.todoroo.astrid.service.TaskDeleter import org.tasks.LocalBroadcastManager -import org.tasks.data.GoogleTaskAccount +import org.tasks.data.CaldavAccount import org.tasks.data.GoogleTaskList import org.tasks.data.GoogleTaskListDao import timber.log.Timber -import java.util.* import javax.inject.Inject class GtasksListService @Inject constructor( @@ -25,8 +24,8 @@ class GtasksListService @Inject constructor( * * @param remoteLists remote information about your lists */ - suspend fun updateLists(account: GoogleTaskAccount, remoteLists: List) { - val lists = googleTaskListDao.getLists(account.account!!) + suspend fun updateLists(account: CaldavAccount, remoteLists: List) { + val lists = googleTaskListDao.getLists(account.uuid!!) val previousLists: MutableSet = HashSet() for (list in lists) { previousLists.add(list.id) @@ -45,12 +44,12 @@ class GtasksListService @Inject constructor( if (local == null) { val byRemoteId = googleTaskListDao.findExistingList(id) if (byRemoteId != null) { - byRemoteId.account = account.account + byRemoteId.account = account.uuid local = byRemoteId } else { Timber.d("Adding new gtask list %s", title) local = GoogleTaskList() - local.account = account.account + local.account = account.uuid local.remoteId = id } } diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.kt b/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.kt index fe3e74d48..2ac9fdba2 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.kt +++ b/app/src/main/java/com/todoroo/astrid/gtasks/auth/GtasksLoginActivity.kt @@ -20,7 +20,9 @@ import org.tasks.PermissionUtil.verifyPermissions import org.tasks.R import org.tasks.analytics.Constants import org.tasks.analytics.Firebase -import org.tasks.data.GoogleTaskAccount +import org.tasks.data.CaldavAccount +import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS +import org.tasks.data.CaldavDao import org.tasks.data.GoogleTaskListDao import org.tasks.dialogs.DialogBuilder import org.tasks.gtasks.GoogleAccountManager @@ -39,6 +41,7 @@ import javax.inject.Inject class GtasksLoginActivity : InjectingAppCompatActivity() { @Inject lateinit var dialogBuilder: DialogBuilder @Inject lateinit var googleAccountManager: GoogleAccountManager + @Inject lateinit var caldavDao: CaldavDao @Inject lateinit var googleTaskListDao: GoogleTaskListDao @Inject lateinit var permissionRequestor: ActivityPermissionRequestor @Inject lateinit var firebase: Firebase @@ -71,18 +74,21 @@ class GtasksLoginActivity : InjectingAppCompatActivity() { startActivity(intent) } else { withContext(NonCancellable) { - var account = googleTaskListDao.getAccount(accountName) + var account = caldavDao.getAccount(TYPE_GOOGLE_TASKS, accountName) if (account == null) { - account = GoogleTaskAccount() - account.account = accountName - googleTaskListDao.insert(account) + account = CaldavAccount() + account.accountType = TYPE_GOOGLE_TASKS + account.uuid = accountName + account.name = accountName + account.username = accountName + caldavDao.insert(account) firebase.logEvent( R.string.event_sync_add_account, R.string.param_type to Constants.SYNC_TYPE_GOOGLE_TASKS ) } else { account.error = "" - googleTaskListDao.update(account) + caldavDao.update(account) googleTaskListDao.resetLastSync(accountName) } } diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt index 9e04be686..31039ecf4 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt @@ -72,12 +72,6 @@ class TaskDeleter @Inject constructor( localBroadcastManager.broadcastRefreshList() } - suspend fun delete(list: GoogleTaskAccount) { - val tasks = deletionDao.delete(list) - delete(tasks) - localBroadcastManager.broadcastRefreshList() - } - suspend fun delete(list: CaldavCalendar) { vtodoCache.delete(list) val tasks = deletionDao.delete(list) diff --git a/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt b/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt index 737dff0ba..cabcfa7c2 100644 --- a/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt +++ b/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt @@ -250,9 +250,11 @@ class Upgrader @Inject constructor( private suspend fun migrateGoogleTaskAccount() { val account = preferences.getStringValue("gtasks_user") if (!isNullOrEmpty(account)) { - val googleTaskAccount = GoogleTaskAccount() - googleTaskAccount.account = account - googleTaskListDao.insert(googleTaskAccount) + val caldavAccount = CaldavAccount() + caldavAccount.uuid = account + caldavAccount.name = account + caldavAccount.username = account + caldavDao.insert(caldavAccount) for (list in googleTaskListDao.getAllLists()) { list.account = account googleTaskListDao.insertOrReplace(list) diff --git a/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.kt b/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.kt index 0b741b0d0..2d8d06df6 100644 --- a/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.kt +++ b/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.kt @@ -17,7 +17,7 @@ import com.todoroo.astrid.service.TaskDeleter import dagger.hilt.android.AndroidEntryPoint import org.tasks.R import org.tasks.Strings.isNullOrEmpty -import org.tasks.data.GoogleTaskAccount +import org.tasks.data.CaldavAccount import org.tasks.data.GoogleTaskList import org.tasks.data.GoogleTaskListDao import org.tasks.databinding.ActivityGoogleTaskListSettingsBinding @@ -43,7 +43,7 @@ class GoogleTaskListSettingsActivity : BaseListSettingsActivity() { gtasksList = intent.getParcelableExtra(EXTRA_STORE_DATA) ?: GoogleTaskList().apply { isNewList = true - account = intent.getParcelableExtra(EXTRA_ACCOUNT)!!.account + account = intent.getParcelableExtra(EXTRA_ACCOUNT)!!.username } super.onCreate(savedInstanceState) if (savedInstanceState == null) { diff --git a/app/src/main/java/org/tasks/backup/BackupContainer.kt b/app/src/main/java/org/tasks/backup/BackupContainer.kt index b1bbe6889..178df086f 100644 --- a/app/src/main/java/org/tasks/backup/BackupContainer.kt +++ b/app/src/main/java/org/tasks/backup/BackupContainer.kt @@ -9,7 +9,6 @@ class BackupContainer( val places: List?, val tags: List?, val filters: List?, - val googleTaskAccounts: List?, val googleTaskLists: List?, val caldavAccounts: List?, val caldavCalendars: List?, @@ -20,6 +19,7 @@ class BackupContainer( val stringPrefs: Map?, val boolPrefs: Map?, val setPrefs: Map>?, + val googleTaskAccounts: List? = emptyList(), ) { class TaskBackup( val task: Task, diff --git a/app/src/main/java/org/tasks/backup/TasksJsonExporter.kt b/app/src/main/java/org/tasks/backup/TasksJsonExporter.kt index e0dc173cc..192b7e16f 100755 --- a/app/src/main/java/org/tasks/backup/TasksJsonExporter.kt +++ b/app/src/main/java/org/tasks/backup/TasksJsonExporter.kt @@ -132,7 +132,6 @@ class TasksJsonExporter @Inject constructor( locationDao.getPlaces(), tagDataDao.getAll(), filterDao.getFilters(), - googleTaskListDao.getAccounts(), googleTaskListDao.getAllLists(), caldavDao.getAccounts(), caldavDao.getCalendars(), diff --git a/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt b/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt index f5f597005..f46877968 100644 --- a/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt +++ b/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt @@ -19,6 +19,7 @@ import org.tasks.LocalBroadcastManager import org.tasks.R import org.tasks.caldav.VtodoCache import org.tasks.data.* +import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS import org.tasks.data.Place.Companion.newPlace import org.tasks.db.Migrations.repeatFrom import org.tasks.db.Migrations.withoutFrom @@ -81,8 +82,15 @@ class TasksJsonImporter @Inject constructor( tagDataDao.createNew(tagData) } backupContainer.googleTaskAccounts?.forEach { googleTaskAccount -> - if (googleTaskListDao.getAccount(googleTaskAccount.account!!) == null) { - googleTaskListDao.insert(googleTaskAccount) + if (caldavDao.getAccount(TYPE_GOOGLE_TASKS, googleTaskAccount.account!!) == null) { + caldavDao.insert( + CaldavAccount().apply { + accountType = TYPE_GOOGLE_TASKS + uuid = googleTaskAccount.account + name = googleTaskAccount.account + username = googleTaskAccount.account + } + ) } } backupContainer.places?.forEach { place -> diff --git a/app/src/main/java/org/tasks/data/CaldavAccount.kt b/app/src/main/java/org/tasks/data/CaldavAccount.kt index 8e24083d7..e5fe0e021 100644 --- a/app/src/main/java/org/tasks/data/CaldavAccount.kt +++ b/app/src/main/java/org/tasks/data/CaldavAccount.kt @@ -103,6 +103,9 @@ class CaldavAccount : Parcelable { val isMicrosoft: Boolean get() = accountType == TYPE_MICROSOFT + val isGoogleTasks: Boolean + get() = accountType == TYPE_GOOGLE_TASKS + fun listSettingsClass(): Class = when(accountType) { TYPE_LOCAL -> LocalListSettingsActivity::class.java TYPE_ETESYNC, TYPE_OPENTASKS -> OpenTasksListSettingsActivity::class.java @@ -208,6 +211,7 @@ class CaldavAccount : Parcelable { uuid.isDavx5() -> R.string.davx5 uuid.isDecSync() -> R.string.decsync isMicrosoft -> R.string.microsoft + isGoogleTasks -> R.string.gtasks_GPr_header else -> 0 } @@ -219,6 +223,7 @@ class CaldavAccount : Parcelable { uuid.isDavx5() -> R.drawable.ic_davx5_icon_green_bg uuid.isDecSync() -> R.drawable.ic_decsync isMicrosoft -> R.drawable.ic_microsoft_tasks + isGoogleTasks -> R.drawable.ic_google else -> 0 } @@ -233,6 +238,7 @@ class CaldavAccount : Parcelable { const val TYPE_TASKS = 4 const val TYPE_ETEBASE = 5 const val TYPE_MICROSOFT = 6 + const val TYPE_GOOGLE_TASKS = 7 const val SERVER_UNKNOWN = -1 const val SERVER_TASKS = 0 diff --git a/app/src/main/java/org/tasks/data/DeletionDao.kt b/app/src/main/java/org/tasks/data/DeletionDao.kt index 393f66ac4..5e7a6d3fa 100644 --- a/app/src/main/java/org/tasks/data/DeletionDao.kt +++ b/app/src/main/java/org/tasks/data/DeletionDao.kt @@ -69,22 +69,9 @@ WHERE recurring = 1 return tasks } - @Delete - internal abstract suspend fun deleteGoogleTaskAccount(googleTaskAccount: GoogleTaskAccount) - @Query("SELECT * FROM google_task_lists WHERE gtl_account = :account ORDER BY gtl_title ASC") abstract suspend fun getLists(account: String): List - @Transaction - open suspend fun delete(googleTaskAccount: GoogleTaskAccount): List { - val deleted = ArrayList() - for (list in getLists(googleTaskAccount.account!!)) { - deleted.addAll(delete(list)) - } - deleteGoogleTaskAccount(googleTaskAccount) - return deleted - } - @Query("SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :calendar AND cd_deleted = 0") internal abstract suspend fun getActiveCaldavTasks(calendar: String): List @@ -111,8 +98,14 @@ WHERE recurring = 1 @Transaction open suspend fun delete(caldavAccount: CaldavAccount): List { val deleted = ArrayList() - for (calendar in getCalendars(caldavAccount.uuid!!)) { - deleted.addAll(delete(calendar)) + if (caldavAccount.isGoogleTasks) { + for (list in getLists(caldavAccount.uuid!!)) { + deleted.addAll(delete(list)) + } + } else { + for (calendar in getCalendars(caldavAccount.uuid!!)) { + deleted.addAll(delete(calendar)) + } } deleteCaldavAccount(caldavAccount) return deleted diff --git a/app/src/main/java/org/tasks/data/GoogleTaskAccount.kt b/app/src/main/java/org/tasks/data/GoogleTaskAccount.kt index 3527ce8ce..1946961a9 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskAccount.kt +++ b/app/src/main/java/org/tasks/data/GoogleTaskAccount.kt @@ -1,98 +1,8 @@ package org.tasks.data -import android.os.Parcel -import android.os.Parcelable -import androidx.core.os.ParcelCompat -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.Ignore -import androidx.room.PrimaryKey -import com.todoroo.andlib.data.Table - -@Entity(tableName = "google_task_accounts") -class GoogleTaskAccount : Parcelable { - @PrimaryKey(autoGenerate = true) - @ColumnInfo(name = "gta_id") - @Transient - var id: Long = 0 - - @ColumnInfo(name = "gta_account") - var account: String? = null - - @ColumnInfo(name = "gta_error") - @Transient - var error: String? = "" - - @ColumnInfo(name = "gta_etag") - var etag: String? = null - - @ColumnInfo(name = "gta_collapsed") - var isCollapsed = false - - constructor() - - @Ignore - constructor(source: Parcel) { - id = source.readLong() - account = source.readString() - error = source.readString() - etag = source.readString() - isCollapsed = ParcelCompat.readBoolean(source) - } - - @Ignore - constructor(account: String?) { - this.account = account - } - - override fun describeContents() = 0 - - override fun writeToParcel(dest: Parcel, flags: Int) { - with(dest) { - writeLong(id) - writeString(account) - writeString(error) - writeString(etag) - ParcelCompat.writeBoolean(this, isCollapsed) - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is GoogleTaskAccount) return false - - if (id != other.id) return false - if (account != other.account) return false - if (error != other.error) return false - if (etag != other.etag) return false - if (isCollapsed != other.isCollapsed) return false - - return true - } - - override fun hashCode(): Int { - var result = id.hashCode() - result = 31 * result + (account?.hashCode() ?: 0) - result = 31 * result + (error?.hashCode() ?: 0) - result = 31 * result + (etag?.hashCode() ?: 0) - result = 31 * result + isCollapsed.hashCode() - return result - } - - override fun toString(): String = - "GoogleTaskAccount(id=$id, account=$account, error=$error, etag=$etag, isCollapsed=$isCollapsed)" - - val hasError: Boolean - get() = !error.isNullOrBlank() - - companion object { - val TABLE = Table("google_task_accounts") - val ACCOUNT = TABLE.column("gta_account") - - @JvmField val CREATOR: Parcelable.Creator = object : Parcelable.Creator { - override fun createFromParcel(source: Parcel): GoogleTaskAccount = GoogleTaskAccount(source) - - override fun newArray(size: Int): Array = arrayOfNulls(size) - } - } -} \ No newline at end of file +@Deprecated("Only used for backup migration") +data class GoogleTaskAccount( + var account: String? = null, + var etag: String? = null, + var isCollapsed: Boolean = false, +) diff --git a/app/src/main/java/org/tasks/data/GoogleTaskDao.kt b/app/src/main/java/org/tasks/data/GoogleTaskDao.kt index 66a6fb78f..794b87e98 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskDao.kt +++ b/app/src/main/java/org/tasks/data/GoogleTaskDao.kt @@ -56,9 +56,6 @@ abstract class GoogleTaskDao { update(task) } - @Query("UPDATE google_task_accounts SET gta_collapsed = :collapsed WHERE gta_id = :id") - abstract suspend fun setCollapsed(id: Long, collapsed: Boolean) - @Query("SELECT * FROM google_tasks WHERE gt_task = :taskId AND gt_deleted = 0 LIMIT 1") abstract suspend fun getByTaskId(taskId: Long): GoogleTask? diff --git a/app/src/main/java/org/tasks/data/GoogleTaskListDao.kt b/app/src/main/java/org/tasks/data/GoogleTaskListDao.kt index a238c5cf7..7ae97837f 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskListDao.kt +++ b/app/src/main/java/org/tasks/data/GoogleTaskListDao.kt @@ -3,25 +3,14 @@ package org.tasks.data import androidx.lifecycle.LiveData import androidx.room.* import com.todoroo.astrid.api.FilterListItem.NO_ORDER +import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS import org.tasks.filters.GoogleTaskFilters import org.tasks.time.DateTimeUtils.currentTimeMillis @Dao interface GoogleTaskListDao { - @Query("SELECT * FROM google_task_accounts WHERE gta_id = :id") - fun watchAccount(id: Long): LiveData - - @Query("SELECT COUNT(*) FROM google_task_accounts") - suspend fun accountCount(): Int - - @Query("SELECT * FROM google_task_accounts") - suspend fun getAccounts(): List - - @Query("SELECT * FROM google_task_accounts") - fun watchAccounts(): LiveData> - - @Query("SELECT * FROM google_task_accounts WHERE gta_account = :account COLLATE NOCASE LIMIT 1") - suspend fun getAccount(account: String): GoogleTaskAccount? + @Query("SELECT * FROM caldav_accounts WHERE cda_account_type = $TYPE_GOOGLE_TASKS") + suspend fun getAccounts(): List @Query("SELECT * FROM google_task_lists WHERE gtl_id = :id") suspend fun getById(id: Long): GoogleTaskList? @@ -53,12 +42,6 @@ interface GoogleTaskListDao { @Insert suspend fun insert(googleTaskList: GoogleTaskList): Long - @Insert - suspend fun insert(googleTaskAccount: GoogleTaskAccount) - - @Update - suspend fun update(account: GoogleTaskAccount) - @Update suspend fun update(list: GoogleTaskList) diff --git a/app/src/main/java/org/tasks/db/Migrations.kt b/app/src/main/java/org/tasks/db/Migrations.kt index 99e48302a..e777aee0d 100644 --- a/app/src/main/java/org/tasks/db/Migrations.kt +++ b/app/src/main/java/org/tasks/db/Migrations.kt @@ -16,6 +16,7 @@ import org.tasks.data.Alarm.Companion.TYPE_REL_END import org.tasks.data.Alarm.Companion.TYPE_REL_START import org.tasks.data.Alarm.Companion.TYPE_SNOOZE import org.tasks.data.CaldavAccount.Companion.SERVER_UNKNOWN +import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS import org.tasks.data.CaldavCalendar.Companion.ACCESS_READ_ONLY import org.tasks.data.OpenTaskDao.Companion.getLong import org.tasks.extensions.getLongOrNull @@ -588,6 +589,13 @@ object Migrations { } } + private val MIGRATION_87_88 = object : Migration(87, 88) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("INSERT INTO `caldav_accounts` (`cda_account_type`, `cda_server_type`, `cda_uuid`, `cda_name`, `cda_username`, `cda_collapsed`) SELECT $TYPE_GOOGLE_TASKS, $SERVER_UNKNOWN, `gta_account`, `gta_account`, `gta_account`, `gta_collapsed` FROM `google_task_accounts`") + database.execSQL("DROP TABLE `google_task_accounts`") + } + } + fun migrations(fileStorage: FileStorage) = arrayOf( MIGRATION_35_36, MIGRATION_36_37, @@ -631,6 +639,7 @@ object Migrations { MIGRATION_84_85, MIGRATION_85_86, MIGRATION_86_87, + MIGRATION_87_88, ) private fun noop(from: Int, to: Int): Migration = object : Migration(from, to) { diff --git a/app/src/main/java/org/tasks/dialogs/FilterPickerViewModel.kt b/app/src/main/java/org/tasks/dialogs/FilterPickerViewModel.kt index 3997b0d79..b838977dc 100644 --- a/app/src/main/java/org/tasks/dialogs/FilterPickerViewModel.kt +++ b/app/src/main/java/org/tasks/dialogs/FilterPickerViewModel.kt @@ -19,7 +19,6 @@ import org.tasks.LocalBroadcastManager import org.tasks.R import org.tasks.billing.Inventory import org.tasks.data.CaldavDao -import org.tasks.data.GoogleTaskDao import org.tasks.dialogs.FilterPicker.Companion.EXTRA_LISTS_ONLY import org.tasks.filters.FilterProvider import org.tasks.filters.NavigationDrawerSubheader @@ -37,7 +36,6 @@ class FilterPickerViewModel @Inject constructor( private val inventory: Inventory, private val colorProvider: ColorProvider, private val preferences: Preferences, - private val googleTaskDao: GoogleTaskDao, private val caldavDao: CaldavDao, ) : ViewModel() { private val listsOnly = savedStateHandle[EXTRA_LISTS_ONLY] ?: false @@ -70,8 +68,7 @@ class FilterPickerViewModel @Inject constructor( when (subheader.subheaderType) { NavigationDrawerSubheader.SubheaderType.PREFERENCE -> preferences.setBoolean(subheader.id.toInt(), collapsed) - NavigationDrawerSubheader.SubheaderType.GOOGLE_TASKS -> - googleTaskDao.setCollapsed(subheader.id, collapsed) + NavigationDrawerSubheader.SubheaderType.GOOGLE_TASKS, NavigationDrawerSubheader.SubheaderType.CALDAV, NavigationDrawerSubheader.SubheaderType.TASKS, NavigationDrawerSubheader.SubheaderType.ETESYNC -> diff --git a/app/src/main/java/org/tasks/filters/FilterProvider.kt b/app/src/main/java/org/tasks/filters/FilterProvider.kt index 4d531a74e..5e485f4f5 100644 --- a/app/src/main/java/org/tasks/filters/FilterProvider.kt +++ b/app/src/main/java/org/tasks/filters/FilterProvider.kt @@ -39,7 +39,7 @@ class FilterProvider @Inject constructor( private val locationDao: LocationDao) { suspend fun listPickerItems(): List = - googleTaskFilters(false).plus(caldavFilters(false)) + caldavFilters(false) suspend fun navDrawerItems(): List = getAllFilters(hideUnused = true).plus(navDrawerFooter) @@ -166,7 +166,6 @@ class FilterProvider @Inject constructor( .plus(addFilters(showCreate, showBuiltIn)) .plus(addTags(showCreate, hideUnused)) .plus(addPlaces(showCreate, hideUnused)) - .plus(googleTaskFilters(showCreate)) .plus(caldavFilters(showCreate)) .toList() .plusAllIf(BuildConfig.DEBUG) { getDebugFilters() } @@ -201,13 +200,10 @@ class FilterProvider @Inject constructor( Intent(context, HelpAndFeedback::class.java), 0)) - private suspend fun googleTaskFilters(showCreate: Boolean = true): List = - googleTaskListDao.getAccounts().flatMap { googleTaskFilter(it, showCreate) } - - private suspend fun googleTaskFilter(account: GoogleTaskAccount, showCreate: Boolean): List = + private suspend fun googleTaskFilter(account: CaldavAccount, showCreate: Boolean): List = listOf( NavigationDrawerSubheader( - account.account, + account.username, account.error?.isNotBlank() ?: false, account.isCollapsed, SubheaderType.GOOGLE_TASKS, @@ -221,7 +217,7 @@ class FilterProvider @Inject constructor( })) .apply { if (account.isCollapsed) return this } .plus(googleTaskListDao - .getGoogleTaskFilters(account.account!!) + .getGoogleTaskFilters(account.username!!) .map(GoogleTaskFilters::toGtasksFilter) .sort()) @@ -229,7 +225,16 @@ class FilterProvider @Inject constructor( caldavDao.getAccounts() .ifEmpty { listOf(caldavDao.setupLocalAccount(context)) } .filter { it.accountType != TYPE_LOCAL || preferences.getBoolean(R.string.p_lists_enabled, true) } - .flatMap { caldavFilter(it, showCreate && it.accountType != TYPE_OPENTASKS && it.accountType != TYPE_ETESYNC) } + .flatMap { + if (it.isGoogleTasks) { + googleTaskFilter(it, showCreate) + } else { + caldavFilter( + it, + showCreate && it.accountType != TYPE_OPENTASKS && it.accountType != TYPE_ETESYNC + ) + } + } private suspend fun caldavFilter(account: CaldavAccount, showCreate: Boolean): List = listOf( diff --git a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt index a73fbf7ab..49f9d2fbb 100644 --- a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt +++ b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt @@ -43,6 +43,7 @@ import kotlin.math.max class GoogleTaskSynchronizer @Inject constructor( @param:ApplicationContext private val context: Context, private val googleTaskListDao: GoogleTaskListDao, + private val caldavDao: CaldavDao, private val gtasksListService: GtasksListService, private val preferences: Preferences, private val taskDao: TaskDao, @@ -58,7 +59,7 @@ class GoogleTaskSynchronizer @Inject constructor( private val invokers: InvokerFactory, private val alarmDao: AlarmDao, ) { - suspend fun sync(account: GoogleTaskAccount, i: Int) { + suspend fun sync(account: CaldavAccount, i: Int) { Timber.d("%s: start sync", account) try { if (i == 0 || inventory.hasPro) { @@ -94,20 +95,20 @@ class GoogleTaskSynchronizer @Inject constructor( account.error = e.message firebase.reportException(e) } finally { - googleTaskListDao.update(account) + caldavDao.update(account) localBroadcastManager.broadcastRefreshList() Timber.d("%s: end sync", account) } } @Throws(IOException::class) - private suspend fun synchronize(account: GoogleTaskAccount) { + private suspend fun synchronize(account: CaldavAccount) { if (!permissionChecker.canAccessAccounts() - || googleAccountManager.getAccount(account.account) == null) { + || googleAccountManager.getAccount(account.username) == null) { account.error = context.getString(R.string.cannot_access_account) return } - val gtasksInvoker = invokers.getGtasksInvoker(account.account!!) + val gtasksInvoker = invokers.getGtasksInvoker(account.username!!) pushLocalChanges(account, gtasksInvoker) val gtaskLists: MutableList = ArrayList() var nextPageToken: String? = null @@ -148,7 +149,7 @@ class GoogleTaskSynchronizer @Inject constructor( googleTaskDao.reposition(list.id) } } - account.etag = eTag +// account.etag = eTag account.error = "" } @@ -168,8 +169,8 @@ class GoogleTaskSynchronizer @Inject constructor( } @Throws(IOException::class) - private suspend fun pushLocalChanges(account: GoogleTaskAccount, gtasksInvoker: GtasksInvoker) { - val tasks = taskDao.getGoogleTasksToPush(account.account!!) + private suspend fun pushLocalChanges(account: CaldavAccount, gtasksInvoker: GtasksInvoker) { + val tasks = taskDao.getGoogleTasksToPush(account.username!!) for (task in tasks) { pushTask(task, gtasksInvoker) } diff --git a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt index 87e22ca1b..bbbf439d9 100644 --- a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt +++ b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt @@ -19,6 +19,7 @@ import org.tasks.R import org.tasks.data.* import org.tasks.data.CaldavAccount.Companion.TYPE_CALDAV import org.tasks.data.CaldavAccount.Companion.TYPE_ETEBASE +import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS import org.tasks.data.CaldavAccount.Companion.TYPE_TASKS import org.tasks.date.DateTimeUtils.midnight import org.tasks.date.DateTimeUtils.newDateTime @@ -122,8 +123,8 @@ class WorkManagerImpl constructor( override fun updateBackgroundSync() { throttle.run { - val enabled = googleTaskListDao.accountCount() > 0 || - caldavDao.getAccounts(TYPE_CALDAV, TYPE_TASKS, TYPE_ETEBASE).isNotEmpty() || + val enabled = + caldavDao.getAccounts(TYPE_GOOGLE_TASKS, TYPE_CALDAV, TYPE_TASKS, TYPE_ETEBASE).isNotEmpty() || openTaskDao.shouldSync() if (enabled) { Timber.d("Enabling background sync") diff --git a/app/src/main/java/org/tasks/preferences/PreferencesViewModel.kt b/app/src/main/java/org/tasks/preferences/PreferencesViewModel.kt index 3b3b1024f..a00d38c82 100644 --- a/app/src/main/java/org/tasks/preferences/PreferencesViewModel.kt +++ b/app/src/main/java/org/tasks/preferences/PreferencesViewModel.kt @@ -14,7 +14,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.tasks.R import org.tasks.backup.BackupConstants -import org.tasks.data.* +import org.tasks.data.CaldavAccount +import org.tasks.data.CaldavDao import org.tasks.date.DateTimeUtils.newDateTime import org.tasks.googleapis.InvokerFactory import org.tasks.gtasks.GoogleAccountManager @@ -29,13 +30,11 @@ class PreferencesViewModel @Inject constructor( invokers: InvokerFactory, private val googleAccountManager: GoogleAccountManager, caldavDao: CaldavDao, - googleTaskListDao: GoogleTaskListDao, ) : ViewModel() { private val driveInvoker = invokers.getDriveInvoker() val lastBackup = MutableLiveData() val lastDriveBackup = MutableLiveData() val lastAndroidBackup = MutableLiveData() - var googleTaskAccounts = googleTaskListDao.watchAccounts() var caldavAccounts = caldavDao.watchAccounts() private fun isStale(timestamp: Long?) = diff --git a/app/src/main/java/org/tasks/preferences/fragments/GoogleTasksAccount.kt b/app/src/main/java/org/tasks/preferences/fragments/GoogleTasksAccount.kt index 6d58f077b..520de4998 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/GoogleTasksAccount.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/GoogleTasksAccount.kt @@ -1,6 +1,8 @@ package org.tasks.preferences.fragments -import android.content.* +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent import android.os.Bundle import androidx.lifecycle.LiveData import androidx.lifecycle.lifecycleScope @@ -11,9 +13,9 @@ import kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager import org.tasks.R import org.tasks.billing.Inventory +import org.tasks.data.CaldavAccount import org.tasks.data.CaldavAccount.Companion.isPaymentRequired -import org.tasks.data.GoogleTaskAccount -import org.tasks.data.GoogleTaskListDao +import org.tasks.data.CaldavDao import org.tasks.preferences.IconPreference import javax.inject.Inject @@ -23,11 +25,11 @@ class GoogleTasksAccount : BaseAccountPreference() { @Inject lateinit var taskDeleter: TaskDeleter @Inject lateinit var inventory: Inventory @Inject lateinit var localBroadcastManager: LocalBroadcastManager - @Inject lateinit var googleTaskListDao: GoogleTaskListDao + @Inject lateinit var caldavDao: CaldavDao - private lateinit var googleTaskAccountLiveData: LiveData + private lateinit var googleTaskAccountLiveData: LiveData - val googleTaskAccount: GoogleTaskAccount + val googleTaskAccount: CaldavAccount get() = googleTaskAccountLiveData.value ?: requireArguments().getParcelable(EXTRA_ACCOUNT)!! private val purchaseReceiver = object : BroadcastReceiver() { @@ -36,7 +38,7 @@ class GoogleTasksAccount : BaseAccountPreference() { googleTaskAccount.let { if (inventory.subscription.value != null && it.error.isPaymentRequired()) { it.error = null - googleTaskListDao.update(it) + caldavDao.update(it) } refreshUi(it) } @@ -49,8 +51,8 @@ class GoogleTasksAccount : BaseAccountPreference() { override suspend fun setupPreferences(savedInstanceState: Bundle?) { super.setupPreferences(savedInstanceState) - googleTaskAccountLiveData = googleTaskListDao.watchAccount( - arguments?.getParcelable(EXTRA_ACCOUNT)?.id ?: 0 + googleTaskAccountLiveData = caldavDao.watchAccount( + arguments?.getParcelable(EXTRA_ACCOUNT)?.id ?: 0 ) googleTaskAccountLiveData.observe(this) { refreshUi(it) } @@ -74,7 +76,7 @@ class GoogleTasksAccount : BaseAccountPreference() { localBroadcastManager.unregisterReceiver(purchaseReceiver) } - private fun refreshUi(account: GoogleTaskAccount?) { + private fun refreshUi(account: CaldavAccount?) { if (account == null) { return } @@ -119,7 +121,7 @@ class GoogleTasksAccount : BaseAccountPreference() { fun String?.isUnauthorized(): Boolean = this?.startsWith("401 Unauthorized", ignoreCase = true) == true - fun newGoogleTasksAccountPreference(account: GoogleTaskAccount) = + fun newGoogleTasksAccountPreference(account: CaldavAccount) = GoogleTasksAccount().apply { arguments = Bundle().apply { putParcelable(EXTRA_ACCOUNT, account) diff --git a/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt b/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt index addb6cd23..f0d941e7e 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt @@ -22,7 +22,6 @@ import org.tasks.billing.PurchaseActivity import org.tasks.caldav.BaseCaldavAccountSettingsActivity import org.tasks.caldav.CaldavAccountSettingsActivity import org.tasks.data.CaldavAccount -import org.tasks.data.GoogleTaskAccount import org.tasks.etebase.EtebaseAccountSettingsActivity import org.tasks.extensions.Context.openUri import org.tasks.extensions.Context.toast @@ -87,7 +86,6 @@ class MainSettingsFragment : InjectingPreferenceFragment() { viewModel.lastBackup.observe(this) { updateBackupWarning() } viewModel.lastAndroidBackup.observe(this) { updateBackupWarning() } viewModel.lastDriveBackup.observe(this) { updateBackupWarning() } - viewModel.googleTaskAccounts.observe(this) { refreshAccounts() } viewModel.caldavAccounts.observe(this) { refreshAccounts() } if (BuildConfig.FLAVOR == "generic") { remove(R.string.upgrade_to_pro) @@ -142,7 +140,6 @@ class MainSettingsFragment : InjectingPreferenceFragment() { private fun refreshAccounts() { val caldavAccounts = viewModel.caldavAccounts.value ?: emptyList() - val googleTaskAccounts = viewModel.googleTaskAccounts.value ?: emptyList() val addAccount = findPreference(R.string.add_account) val index = preferenceScreen.indexOf(addAccount) var current = 0 @@ -153,15 +150,8 @@ class MainSettingsFragment : InjectingPreferenceFragment() { preferenceScreen.insertAt(current++) }) } - googleTaskAccounts.forEach { - setup(it, if (current < index) { - preferenceScreen.getPreference(current++) as IconPreference - } else { - preferenceScreen.insertAt(current++) - }) - } preferenceScreen.removeAt(current, index - current) - if (caldavAccounts.isEmpty() && googleTaskAccounts.isEmpty()) { + if (caldavAccounts.isEmpty()) { addAccount.setTitle(R.string.not_signed_in) addAccount.setIcon(R.drawable.ic_outline_cloud_off_24px) } else { @@ -216,6 +206,12 @@ class MainSettingsFragment : InjectingPreferenceFragment() { newMicrosoftAccountPreference(account), getString(R.string.microsoft) ) + } else if (account.isGoogleTasks) { + (activity as MainPreferences).startPreference( + this, + newGoogleTasksAccountPreference(account), + getString(R.string.gtasks_GPr_header) + ) } else { val intent = Intent(context, account.accountSettingsClass).apply { putExtra(BaseCaldavAccountSettingsActivity.EXTRA_CALDAV_DATA, account) @@ -239,21 +235,6 @@ class MainSettingsFragment : InjectingPreferenceFragment() { setupErrorIcon(pref, account.hasError, account.isEteSyncAccount) } - private fun setup(account: GoogleTaskAccount, pref: IconPreference) { - pref.setTitle(R.string.gtasks_GPr_header) - pref.setIcon(R.drawable.ic_google) - pref.summary = account.account - setupErrorIcon(pref, account.hasError) - pref.setOnPreferenceClickListener { - (activity as MainPreferences).startPreference( - this, - newGoogleTasksAccountPreference(account), - account.account!! - ) - false - } - } - private fun setupErrorIcon( pref: IconPreference, hasError: Boolean,