diff --git a/app/schemas/com.todoroo.astrid.dao.Database/51.json b/app/schemas/com.todoroo.astrid.dao.Database/51.json new file mode 100644 index 000000000..7d5d92ab1 --- /dev/null +++ b/app/schemas/com.todoroo.astrid.dao.Database/51.json @@ -0,0 +1,737 @@ +{ + "formatVersion": 1, + "database": { + "version": 51, + "identityHash": "a2964070f787956ed4c1300b9c156082", + "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": [] + }, + { + "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)", + "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 + } + ], + "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, \"a2964070f787956ed4c1300b9c156082\")" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/todoroo/andlib/data/DatabaseDao.java b/app/src/main/java/com/todoroo/andlib/data/DatabaseDao.java index 8ad692120..6c5ea426c 100644 --- a/app/src/main/java/com/todoroo/andlib/data/DatabaseDao.java +++ b/app/src/main/java/com/todoroo/andlib/data/DatabaseDao.java @@ -55,7 +55,7 @@ public class DatabaseDao { return query(query).toList(); } - public TYPE getFirst(Query query) { + private TYPE getFirst(Query query) { return query(query).first(); } diff --git a/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java b/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java index 1231147ac..9c3314a89 100644 --- a/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java +++ b/app/src/main/java/com/todoroo/astrid/api/CustomFilter.java @@ -3,11 +3,10 @@ package com.todoroo.astrid.api; import android.os.Parcel; import android.os.Parcelable; -import com.todoroo.andlib.utility.AndroidUtilities; -import org.tasks.data.StoreObject; - import java.util.Map; +import static com.todoroo.andlib.utility.AndroidUtilities.mapToSerializedString; + public class CustomFilter extends Filter { private long id; @@ -20,15 +19,15 @@ public class CustomFilter extends Filter { this.id = id; } - public StoreObject toStoreObject() { - StoreObject storeObject = new StoreObject(); - storeObject.setId(id); - storeObject.setItem(listingTitle); - storeObject.setValue(sqlQuery); + public org.tasks.data.Filter toStoreObject() { + org.tasks.data.Filter filter = new org.tasks.data.Filter(); + filter.setId(id); + filter.setTitle(listingTitle); + filter.setSql(sqlQuery); if (valuesForNewTasks != null && valuesForNewTasks.size() > 0) { - storeObject.setValue2(AndroidUtilities.mapToSerializedString(valuesForNewTasks)); + filter.setCriterion(mapToSerializedString(valuesForNewTasks)); } - return storeObject; + return filter; } public long getId() { diff --git a/app/src/main/java/com/todoroo/astrid/core/CustomFilterActivity.java b/app/src/main/java/com/todoroo/astrid/core/CustomFilterActivity.java index 4d9d92083..18501c20f 100644 --- a/app/src/main/java/com/todoroo/astrid/core/CustomFilterActivity.java +++ b/app/src/main/java/com/todoroo/astrid/core/CustomFilterActivity.java @@ -22,6 +22,7 @@ import android.widget.ListView; import com.todoroo.andlib.data.Property.CountProperty; import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.UnaryCriterion; +import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.astrid.activity.TaskListActivity; import com.todoroo.astrid.api.CustomFilter; import com.todoroo.astrid.api.CustomFilterCriterion; @@ -30,12 +31,12 @@ import com.todoroo.astrid.api.MultipleSelectCriterion; import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.TextInputCriterion; import com.todoroo.astrid.dao.Database; -import org.tasks.data.StoreObjectDao; import com.todoroo.astrid.dao.TaskDao.TaskCriteria; -import org.tasks.data.StoreObject; import com.todoroo.astrid.data.Task; import org.tasks.R; +import org.tasks.data.FilterDao; +import org.tasks.data.StoreObjectDao; import org.tasks.dialogs.DialogBuilder; import org.tasks.filters.FilterCriteriaProvider; import org.tasks.injection.ActivityComponent; @@ -55,6 +56,7 @@ import butterknife.BindView; import butterknife.ButterKnife; import static android.text.TextUtils.isEmpty; +import static com.todoroo.andlib.utility.AndroidUtilities.mapToSerializedString; /** * Activity that allows users to build custom filters @@ -134,6 +136,7 @@ public class CustomFilterActivity extends ThemedInjectingAppCompatActivity imple // --- activity @Inject Database database; + @Inject FilterDao filterDao; @Inject StoreObjectDao storeObjectDao; @Inject DialogBuilder dialogBuilder; @Inject FilterCriteriaProvider filterCriteriaProvider; @@ -271,7 +274,7 @@ public class CustomFilterActivity extends ThemedInjectingAppCompatActivity imple } } - StoreObject storeObject = SavedFilter.persist(storeObjectDao, adapter, title, sql.toString(), values); + org.tasks.data.Filter storeObject = persist(title, sql.toString(), values); Filter filter = new CustomFilter(title, sql.toString(), values, storeObject.getId()); setResult(RESULT_OK, new Intent().putExtra(TaskListActivity.OPEN_FILTER, filter)); finish(); @@ -391,4 +394,52 @@ public class CustomFilterActivity extends ThemedInjectingAppCompatActivity imple return super.onContextItemSelected(item); } + + private org.tasks.data.Filter persist(String title, String sql, Map values) { + if(title == null || title.length() == 0) { + return null; + } + + // if filter of this name exists, edit it + org.tasks.data.Filter storeObject = filterDao.getByName(title); + if (storeObject == null) { + storeObject = new org.tasks.data.Filter(); + } + + // populate saved filter properties + storeObject.setTitle(title); + storeObject.setSql(sql); + storeObject.setValues(values == null ? "" : mapToSerializedString(values)); + storeObject.setCriterion(serializeFilters(adapter)); + + storeObject.setId(filterDao.insertOrUpdate(storeObject)); + return storeObject.getId() >= 0 ? storeObject : null; + } + + private static String serializeFilters(CustomFilterAdapter adapter) { + StringBuilder values = new StringBuilder(); + for(int i = 0; i < adapter.getCount(); i++) { + CriterionInstance item = adapter.getItem(i); + + // criterion|entry|text|type|sql + values.append(escape(item.criterion.identifier)).append(AndroidUtilities.SERIALIZATION_SEPARATOR); + values.append(escape(item.getValueFromCriterion())).append(AndroidUtilities.SERIALIZATION_SEPARATOR); + values.append(escape(item.criterion.text)).append(AndroidUtilities.SERIALIZATION_SEPARATOR); + values.append(item.type).append(AndroidUtilities.SERIALIZATION_SEPARATOR); + if(item.criterion.sql != null) { + values.append(item.criterion.sql); + } + values.append('\n'); + } + + return values.toString(); + } + + private static String escape(String item) { + if(item == null) { + return ""; //$NON-NLS-1$ + } + return item.replace(AndroidUtilities.SERIALIZATION_SEPARATOR, + AndroidUtilities.SEPARATOR_ESCAPE); + } } diff --git a/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java b/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java index 584ef9851..7c3959a99 100644 --- a/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java +++ b/app/src/main/java/com/todoroo/astrid/core/CustomFilterExposer.java @@ -10,10 +10,9 @@ import android.text.TextUtils; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.astrid.api.CustomFilter; import com.todoroo.astrid.api.Filter; -import org.tasks.data.StoreObjectDao; -import org.tasks.data.StoreObject; import org.tasks.R; +import org.tasks.data.FilterDao; import java.util.List; import java.util.Map; @@ -26,30 +25,29 @@ import static com.google.common.collect.Lists.transform; public final class CustomFilterExposer { private static final int filter = R.drawable.ic_filter_list_24dp; - - private final StoreObjectDao storeObjectDao; + private FilterDao filterDao; @Inject - public CustomFilterExposer(StoreObjectDao storeObjectDao) { - this.storeObjectDao = storeObjectDao; + public CustomFilterExposer(FilterDao filterDao) { + this.filterDao = filterDao; } public List getFilters() { - return newArrayList(transform(storeObjectDao.getSavedFilters(), this::load)); + return newArrayList(transform(filterDao.getFilters(), this::load)); } public Filter getFilter(long id) { - return load(storeObjectDao.getSavedFilterById(id)); + return load(filterDao.getById(id)); } - private Filter load(StoreObject savedFilter) { + private Filter load(org.tasks.data.Filter savedFilter) { if (savedFilter == null) { return null; } - String title = savedFilter.getItem(); - String sql = savedFilter.getValue(); - String valuesString = savedFilter.getValue2(); + String title = savedFilter.getTitle(); + String sql = savedFilter.getSql(); + String valuesString = savedFilter.getValues(); Map values = null; if(!TextUtils.isEmpty(valuesString)) { diff --git a/app/src/main/java/com/todoroo/astrid/core/SavedFilter.java b/app/src/main/java/com/todoroo/astrid/core/SavedFilter.java deleted file mode 100644 index 94f5c86f4..000000000 --- a/app/src/main/java/com/todoroo/astrid/core/SavedFilter.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.core; - -import com.todoroo.andlib.utility.AndroidUtilities; -import com.todoroo.astrid.core.CustomFilterActivity.CriterionInstance; -import org.tasks.data.StoreObjectDao; -import org.tasks.data.StoreObject; - -import java.util.Map; - -/** - * {@link StoreObject} entries for a saved custom filter - * - * @author Tim Su - * - */ -public class SavedFilter { - - private static final String TYPE = "filter"; //$NON-NLS-1$ - - /** - * Save a filter - */ - public static StoreObject persist(StoreObjectDao dao, CustomFilterAdapter adapter, String title, - String sql, Map values) { - - if(title == null || title.length() == 0) { - return null; - } - - // if filter of this name exists, edit it - StoreObject storeObject = dao.getSavedFilterByName(title); - if (storeObject == null) { - storeObject = new StoreObject(); - } - - // populate saved filter properties - storeObject.setType(TYPE); - storeObject.setItem(title); - storeObject.setValue(sql); - - if(values == null) { - storeObject.setValue2(""); //$NON-NLS-1$ - } else { - storeObject.setValue2(AndroidUtilities.mapToSerializedString(values)); - } - - String filters = serializeFilters(adapter); - storeObject.setValue3(filters); - - if (dao.persist(storeObject)) { - return storeObject; - } - - return null; - } - - /** - * Turn a series of CriterionInstance objects into a string - */ - private static String serializeFilters(CustomFilterAdapter adapter) { - StringBuilder values = new StringBuilder(); - for(int i = 0; i < adapter.getCount(); i++) { - CriterionInstance item = adapter.getItem(i); - - // criterion|entry|text|type|sql - values.append(escape(item.criterion.identifier)).append(AndroidUtilities.SERIALIZATION_SEPARATOR); - values.append(escape(item.getValueFromCriterion())).append(AndroidUtilities.SERIALIZATION_SEPARATOR); - values.append(escape(item.criterion.text)).append(AndroidUtilities.SERIALIZATION_SEPARATOR); - values.append(item.type).append(AndroidUtilities.SERIALIZATION_SEPARATOR); - if(item.criterion.sql != null) { - values.append(item.criterion.sql); - } - values.append('\n'); - } - - return values.toString(); - } - - private static String escape(String item) { - if(item == null) { - return ""; //$NON-NLS-1$ - } - return item.replace(AndroidUtilities.SERIALIZATION_SEPARATOR, - AndroidUtilities.SEPARATOR_ESCAPE); - } -} diff --git a/app/src/main/java/com/todoroo/astrid/dao/Database.java b/app/src/main/java/com/todoroo/astrid/dao/Database.java index 0e47ef0c5..e8987dd15 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/Database.java +++ b/app/src/main/java/com/todoroo/astrid/dao/Database.java @@ -15,6 +15,9 @@ import android.database.sqlite.SQLiteDatabase; import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.Table; import com.todoroo.andlib.utility.AndroidUtilities; + +import org.tasks.data.Filter; +import org.tasks.data.FilterDao; import org.tasks.data.StoreObject; import org.tasks.data.StoreObjectDao; @@ -61,9 +64,10 @@ import timber.log.Timber; Alarm.class, Location.class, Tag.class, - GoogleTask.class + GoogleTask.class, + Filter.class }, - version = 50) + version = 51) public abstract class Database extends RoomDatabase { public abstract NotificationDao notificationDao(); @@ -76,10 +80,11 @@ public abstract class Database extends RoomDatabase { public abstract LocationDao getLocationDao(); public abstract TagDao getTagDao(); public abstract GoogleTaskDao getGoogleTaskDao(); + public abstract FilterDao getFilterDao(); public static final String NAME = "database"; - public static final Table[] TABLES = new Table[] { + private static final Table[] TABLES = new Table[] { Task.TABLE }; diff --git a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java index babeb74cd..17a53defe 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java @@ -55,7 +55,6 @@ public class TaskDao { private final RemoteModelDao dao; private final LocalBroadcastManager localBroadcastManager; - private final Database database; private final Preferences preferences; private final AlarmDao alarmDao; private final TagDao tagDao; @@ -68,7 +67,6 @@ public class TaskDao { Preferences preferences, LocalBroadcastManager localBroadcastManager, AlarmDao alarmDao, TagDao tagDao, LocationDao locationDao, GoogleTaskDao googleTaskDao) { this.context = context; - this.database = database; this.preferences = preferences; this.alarmDao = alarmDao; this.tagDao = tagDao; diff --git a/app/src/main/java/org/tasks/activities/FilterSettingsActivity.java b/app/src/main/java/org/tasks/activities/FilterSettingsActivity.java index 9c748a4e0..5a9dab724 100644 --- a/app/src/main/java/org/tasks/activities/FilterSettingsActivity.java +++ b/app/src/main/java/org/tasks/activities/FilterSettingsActivity.java @@ -16,9 +16,9 @@ import android.view.MenuItem; import android.view.inputmethod.InputMethodManager; import com.todoroo.astrid.api.CustomFilter; -import org.tasks.data.StoreObjectDao; import org.tasks.R; +import org.tasks.data.FilterDao; import org.tasks.dialogs.DialogBuilder; import org.tasks.injection.ActivityComponent; import org.tasks.injection.ThemedInjectingAppCompatActivity; @@ -42,7 +42,7 @@ public class FilterSettingsActivity extends ThemedInjectingAppCompatActivity imp private CustomFilter filter; - @Inject StoreObjectDao storeObjectDao; + @Inject FilterDao filterDao; @Inject DialogBuilder dialogBuilder; @Inject Preferences preferences; @@ -99,7 +99,7 @@ public class FilterSettingsActivity extends ThemedInjectingAppCompatActivity imp boolean nameChanged = !oldName.equals(newName); if (nameChanged) { filter.listingTitle = newName; - storeObjectDao.update(filter.toStoreObject()); + filterDao.update(filter.toStoreObject()); setResult(RESULT_OK, new Intent(ACTION_FILTER_RENAMED).putExtra(TOKEN_FILTER, filter)); } @@ -125,7 +125,7 @@ public class FilterSettingsActivity extends ThemedInjectingAppCompatActivity imp private void deleteTag() { dialogBuilder.newMessageDialog(R.string.delete_tag_confirmation, filter.listingTitle) .setPositiveButton(R.string.delete, (dialog, which) -> { - storeObjectDao.delete(filter.getId()); + filterDao.delete(filter.getId()); setResult(RESULT_OK, new Intent(ACTION_FILTER_DELETED).putExtra(TOKEN_FILTER, filter)); finish(); }) diff --git a/app/src/main/java/org/tasks/data/Filter.java b/app/src/main/java/org/tasks/data/Filter.java new file mode 100644 index 000000000..c5876e45b --- /dev/null +++ b/app/src/main/java/org/tasks/data/Filter.java @@ -0,0 +1,75 @@ +package org.tasks.data; + +import android.arch.persistence.room.ColumnInfo; +import android.arch.persistence.room.Entity; +import android.arch.persistence.room.PrimaryKey; + +@Entity(tableName = "filters") +public class Filter { + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "_id") + private long id; + + @ColumnInfo(name = "title") + private String title; + + @ColumnInfo(name = "sql") + private String sql; + + @ColumnInfo(name = "values") + private String values; + + @ColumnInfo(name = "criterion") + private String criterion; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public String getValues() { + return values; + } + + public void setValues(String values) { + this.values = values; + } + + public String getCriterion() { + return criterion; + } + + public void setCriterion(String criterion) { + this.criterion = criterion; + } + + @Override + public String toString() { + return "Filter{" + + "id=" + id + + ", title='" + title + '\'' + + ", sql='" + sql + '\'' + + ", values='" + values + '\'' + + ", criterion='" + criterion + '\'' + + '}'; + } +} diff --git a/app/src/main/java/org/tasks/data/FilterDao.java b/app/src/main/java/org/tasks/data/FilterDao.java new file mode 100644 index 000000000..1acbe7186 --- /dev/null +++ b/app/src/main/java/org/tasks/data/FilterDao.java @@ -0,0 +1,31 @@ +package org.tasks.data; + +import android.arch.persistence.room.Dao; +import android.arch.persistence.room.Insert; +import android.arch.persistence.room.OnConflictStrategy; +import android.arch.persistence.room.Query; +import android.arch.persistence.room.Update; + +import java.util.List; + +@Dao +public interface FilterDao { + + @Update + void update(Filter filter); + + @Query("DELETE FROM filters WHERE _id = :id") + void delete(long id); + + @Query("SELECT * FROM filters WHERE title = :title COLLATE NOCASE LIMIT 1") + Filter getByName(String title); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + long insertOrUpdate(Filter storeObject); + + @Query("SELECT * FROM filters ORDER BY title ASC") + List getFilters(); + + @Query("SELECT * FROM filters WHERE _id = :id LIMIT 1") + Filter getById(long id); +} diff --git a/app/src/main/java/org/tasks/data/StoreObjectDao.java b/app/src/main/java/org/tasks/data/StoreObjectDao.java index af163c517..0ed88d731 100644 --- a/app/src/main/java/org/tasks/data/StoreObjectDao.java +++ b/app/src/main/java/org/tasks/data/StoreObjectDao.java @@ -13,12 +13,6 @@ import java.util.List; @Dao public abstract class StoreObjectDao { - @Query("SELECT * FROM store WHERE type = 'filter' ORDER BY item ASC") - public abstract List getSavedFilters(); - - @Query("SELECT * FROM store WHERE type = 'filter' AND _id = :id LIMIT 1") - public abstract StoreObject getSavedFilterById(long id); - @Query("SELECT * FROM store WHERE _id = :id LIMIT 1") abstract StoreObject getById(long id); @@ -54,9 +48,6 @@ public abstract class StoreObjectDao { @Update public abstract void update(StoreObject storeObject); - @Query("SELECT * FROM store WHERE type = 'filter' AND item = :title LIMIT 1") - public abstract StoreObject getSavedFilterByName(String title); - @Query("DELETE FROM store WHERE _id = :id") public abstract void delete(long id); } diff --git a/app/src/main/java/org/tasks/data/TagDataDao.java b/app/src/main/java/org/tasks/data/TagDataDao.java index 66ec1d6c3..d2ed09080 100644 --- a/app/src/main/java/org/tasks/data/TagDataDao.java +++ b/app/src/main/java/org/tasks/data/TagDataDao.java @@ -23,9 +23,6 @@ public abstract class TagDataDao { @Query("SELECT * FROM tagdata WHERE remoteId = :uuid LIMIT 1") public abstract TagData getByUuid(String uuid); - @Query("SELECT * FROM tagdata WHERE remoteId = :uuid") - public abstract List getAllByUuid(String uuid); - @Query("SELECT * FROM tagdata WHERE deleted = 0 AND name IS NOT NULL ORDER BY UPPER(name) ASC") public abstract List tagDataOrderedByName(); diff --git a/app/src/main/java/org/tasks/db/Migrations.java b/app/src/main/java/org/tasks/db/Migrations.java index ab38da993..ec704fd73 100644 --- a/app/src/main/java/org/tasks/db/Migrations.java +++ b/app/src/main/java/org/tasks/db/Migrations.java @@ -73,6 +73,16 @@ public class Migrations { } }; + private static final Migration MIGRATION_50_51 = new Migration(50, 51) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + database.execSQL("CREATE TABLE IF NOT EXISTS `filters` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `sql` TEXT, `values` TEXT, `criterion` TEXT)"); + database.execSQL("INSERT INTO `filters` (`title`, `sql`, `values`, `criterion`) " + + "SELECT `item`, `value`, `value2`, `value3` FROM `store` WHERE `type` = 'filter' AND `deleted` = 0"); + database.execSQL("DELETE FROM `store` WHERE `type` = 'filter'"); + } + }; + private static Migration NOOP(int from, int to) { return new Migration(from, to) { @Override @@ -97,6 +107,7 @@ public class Migrations { MIGRATION_46_47, MIGRATION_47_48, MIGRATION_48_49, - MIGRATION_49_50 + MIGRATION_49_50, + MIGRATION_50_51 }; } diff --git a/app/src/main/java/org/tasks/injection/ApplicationModule.java b/app/src/main/java/org/tasks/injection/ApplicationModule.java index 69b5281ec..521c24915 100644 --- a/app/src/main/java/org/tasks/injection/ApplicationModule.java +++ b/app/src/main/java/org/tasks/injection/ApplicationModule.java @@ -4,6 +4,8 @@ import android.arch.persistence.room.Room; import android.content.Context; import com.todoroo.astrid.dao.Database; + +import org.tasks.data.FilterDao; import org.tasks.data.StoreObjectDao; import org.tasks.data.TagDataDao; import org.tasks.data.TaskAttachmentDao; @@ -114,4 +116,9 @@ public class ApplicationModule { public TagDao getTagDao(Database database) { return database.getTagDao(); } + + @Provides + public FilterDao getFilterDao(Database database) { + return database.getFilterDao(); + } }