From 5bee730f1cb1917e6aec7061d776a1d834295bd8 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Fri, 5 Jan 2018 17:09:13 -0600 Subject: [PATCH] Convert TagDataDao to Room --- .../com.todoroo.astrid.dao.Database/40.json | 110 +++++++++ .../todoroo/astrid/sync/SyncModelTest.java | 2 +- .../com/todoroo/astrid/api/TagFilter.java | 6 +- .../astrid/backup/TasksXmlExporter.java | 3 +- .../astrid/backup/TasksXmlImporter.java | 20 +- .../java/com/todoroo/astrid/dao/Database.java | 9 +- .../com/todoroo/astrid/dao/TagDataDao.java | 79 +++---- .../java/com/todoroo/astrid/data/TagData.java | 215 +++++++++++------- .../astrid/service/StartupService.java | 2 +- .../todoroo/astrid/service/TaskCreator.java | 2 +- .../astrid/subtasks/SubtasksHelper.java | 2 +- .../subtasks/SubtasksTagListFragment.java | 4 +- .../com/todoroo/astrid/tags/TagService.java | 4 +- .../todoroo/astrid/tags/TagsControlSet.java | 8 +- .../tasks/activities/TagSettingsActivity.java | 8 +- .../main/java/org/tasks/backup/XmlReader.java | 41 ++++ .../main/java/org/tasks/backup/XmlWriter.java | 54 +++++ .../main/java/org/tasks/db/Migrations.java | 10 +- .../tasks/injection/ApplicationModule.java | 7 + .../java/org/tasks/tasklist/TagFormatter.java | 2 +- 20 files changed, 426 insertions(+), 162 deletions(-) create mode 100644 app/schemas/com.todoroo.astrid.dao.Database/40.json create mode 100644 app/src/main/java/org/tasks/backup/XmlReader.java create mode 100644 app/src/main/java/org/tasks/backup/XmlWriter.java diff --git a/app/schemas/com.todoroo.astrid.dao.Database/40.json b/app/schemas/com.todoroo.astrid.dao.Database/40.json new file mode 100644 index 000000000..a3ea906c8 --- /dev/null +++ b/app/schemas/com.todoroo.astrid.dao.Database/40.json @@ -0,0 +1,110 @@ +{ + "formatVersion": 1, + "database": { + "version": 40, + "identityHash": "522b606947ecd5beebfb95d548aef0c4", + "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": [] + } + ], + "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, \"522b606947ecd5beebfb95d548aef0c4\")" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/todoroo/astrid/sync/SyncModelTest.java b/app/src/androidTest/java/com/todoroo/astrid/sync/SyncModelTest.java index fef4228d3..32abf7bad 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/sync/SyncModelTest.java +++ b/app/src/androidTest/java/com/todoroo/astrid/sync/SyncModelTest.java @@ -23,7 +23,7 @@ public class SyncModelTest extends NewSyncTestCase { @Test public void testCreateTagMakesUuid() { TagData tag = createTagData(); - assertFalse(RemoteModel.NO_UUID.equals(tag.getUUID())); + assertFalse(RemoteModel.NO_UUID.equals(tag.getRemoteId())); } } diff --git a/app/src/main/java/com/todoroo/astrid/api/TagFilter.java b/app/src/main/java/com/todoroo/astrid/api/TagFilter.java index 8fb2da752..fcdbf14cf 100644 --- a/app/src/main/java/com/todoroo/astrid/api/TagFilter.java +++ b/app/src/main/java/com/todoroo/astrid/api/TagFilter.java @@ -27,8 +27,8 @@ public class TagFilter extends Filter { } public TagFilter(TagData tagData) { - super(tagData.getName(), queryTemplate(tagData.getUuid()), getValuesForNewTask(tagData)); - uuid = tagData.getUuid(); + super(tagData.getName(), queryTemplate(tagData.getRemoteId()), getValuesForNewTask(tagData)); + uuid = tagData.getRemoteId(); tint = tagData.getColor(); icon = TAG; } @@ -51,7 +51,7 @@ public class TagFilter extends Filter { ContentValues contentValues = new ContentValues(); contentValues.put(Metadata.KEY.name, TaskToTagMetadata.KEY); contentValues.put(TaskToTagMetadata.TAG_NAME.name, tagData.getName()); - contentValues.put(TaskToTagMetadata.TAG_UUID.name, tagData.getUuid()); + contentValues.put(TaskToTagMetadata.TAG_UUID.name, tagData.getRemoteId()); return contentValues; } diff --git a/app/src/main/java/com/todoroo/astrid/backup/TasksXmlExporter.java b/app/src/main/java/com/todoroo/astrid/backup/TasksXmlExporter.java index e6b624a9e..9cc075744 100755 --- a/app/src/main/java/com/todoroo/astrid/backup/TasksXmlExporter.java +++ b/app/src/main/java/com/todoroo/astrid/backup/TasksXmlExporter.java @@ -30,6 +30,7 @@ import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.UserActivity; import org.tasks.R; +import org.tasks.backup.XmlWriter; import org.tasks.preferences.Preferences; import org.xmlpull.v1.XmlSerializer; @@ -164,7 +165,7 @@ public class TasksXmlExporter { for (TagData tag : tagDataDao.allTags()) { try { xml.startTag(null, BackupConstants.TAGDATA_TAG); - serializeModel(tag, TagData.PROPERTIES, TagData.ID); + tag.writeToXml(new XmlWriter(xml)); xml.endTag(null, BackupConstants.TAGDATA_TAG); } catch(IOException e) { throw new RuntimeException(e); diff --git a/app/src/main/java/com/todoroo/astrid/backup/TasksXmlImporter.java b/app/src/main/java/com/todoroo/astrid/backup/TasksXmlImporter.java index 4c410f9e9..e21de8ad3 100755 --- a/app/src/main/java/com/todoroo/astrid/backup/TasksXmlImporter.java +++ b/app/src/main/java/com/todoroo/astrid/backup/TasksXmlImporter.java @@ -23,6 +23,7 @@ import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.UserActivityDao; import com.todoroo.astrid.data.Metadata; +import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.UserActivity; @@ -30,6 +31,7 @@ import com.todoroo.astrid.tags.TaskToTagMetadata; import org.tasks.LocalBroadcastManager; import org.tasks.R; +import org.tasks.backup.XmlReader; import org.tasks.dialogs.DialogBuilder; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -156,7 +158,6 @@ public class TasksXmlImporter { final Task currentTask = new Task(); final UserActivity userActivity = new UserActivity(); final Metadata metadata = new Metadata(); - final TagData tagdata = new TagData(); public Format2TaskImporter() { } public Format2TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException { @@ -269,11 +270,11 @@ public class TasksXmlImporter { //If you sync with Google tasks it adds some Google task metadata. //For this metadata we don't create a list! if(key.equals(TaskToTagMetadata.KEY) && tagData == null && deletionDate == 0) { - tagdata.clear(); - tagdata.setId(TagData.NO_ID); - tagdata.setUuid(uuid); - tagdata.setName(name); - tagDataDao.persist(tagdata); + tagData = new TagData(); + tagData.setId(RemoteModel.NO_ID); + tagData.setRemoteId(uuid); + tagData.setName(name); + tagDataDao.insert(tagData); } } } @@ -375,10 +376,9 @@ public class TasksXmlImporter { } private void parseTagdata() { - tagdata.clear(); - deserializeModel(tagdata, TagData.PROPERTIES); - if (tagDataDao.getByUuid(tagdata.getUuid()) == null) { - tagDataDao.persist(tagdata); + TagData tagData = new TagData(new XmlReader(xpp)); + if (tagDataDao.getByUuid(tagData.getRemoteId()) == null) { + tagDataDao.insert(tagData); } } } 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 ee20953f4..272fb4570 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/Database.java +++ b/app/src/main/java/com/todoroo/astrid/dao/Database.java @@ -36,10 +36,16 @@ import timber.log.Timber; * @author Tim Su * */ -@android.arch.persistence.room.Database(entities = {Notification.class}, version = 39) +@android.arch.persistence.room.Database( + entities = { + Notification.class, + TagData.class + }, + version = 40) public abstract class Database extends RoomDatabase { public abstract NotificationDao notificationDao(); + public abstract TagDataDao getTagDataDao(); public static final String NAME = "database"; @@ -47,7 +53,6 @@ public abstract class Database extends RoomDatabase { Task.TABLE, Metadata.TABLE, StoreObject.TABLE, - TagData.TABLE, UserActivity.TABLE, TaskAttachment.TABLE, TaskListMetadata.TABLE, diff --git a/app/src/main/java/com/todoroo/astrid/dao/TagDataDao.java b/app/src/main/java/com/todoroo/astrid/dao/TagDataDao.java index 460e88004..35f316ed5 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TagDataDao.java +++ b/app/src/main/java/com/todoroo/astrid/dao/TagDataDao.java @@ -5,69 +5,50 @@ */ package com.todoroo.astrid.dao; -import com.todoroo.andlib.sql.Criterion; -import com.todoroo.andlib.sql.Functions; -import com.todoroo.andlib.sql.Order; -import com.todoroo.andlib.sql.Query; -import com.todoroo.astrid.data.TagData; +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 org.tasks.injection.ApplicationScope; +import com.todoroo.astrid.data.RemoteModel; +import com.todoroo.astrid.data.TagData; +import com.todoroo.astrid.helper.UUIDHelper; import java.util.List; -import javax.inject.Inject; +@Dao +public abstract class TagDataDao { -/** - * Data Access layer for {@link TagData}-related operations. - * - * @author Tim Su - */ -@ApplicationScope -public class TagDataDao { + @Query("SELECT * FROM tagdata WHERE name = :name COLLATE NOCASE LIMIT 1") + public abstract TagData getTagByName(String name); - private final RemoteModelDao dao; + // TODO: does this need to be ordered? + @Query("SELECT * FROM tagdata WHERE deleted = 0 ORDER BY _id ASC") + public abstract List allTags(); - @Inject - public TagDataDao(Database database) { - dao = new RemoteModelDao<>(database, TagData.class); - } + @Query("SELECT * FROM tagdata WHERE remoteId = :uuid LIMIT 1") + public abstract TagData getByUuid(String uuid); - public TagData getTagByName(String name) { - return dao.getFirst(Query.select(TagData.PROPERTIES).where(TagData.NAME.eqCaseInsensitive(name))); - } + @Query("SELECT * FROM tagdata WHERE deleted = 0 AND name IS NOT NULL ORDER BY UPPER(name) ASC") + public abstract List tagDataOrderedByName(); - public List allTags() { - // TODO: does this need to be ordered? - return dao.toList(Query.select(TagData.PROPERTIES) - .where(TagData.DELETION_DATE.eq(0)) - .orderBy(Order.asc(TagData.ID))); - } + @Insert(onConflict = OnConflictStrategy.REPLACE) + public abstract void persist(TagData tagData); - public TagData getByUuid(String uuid) { - return dao.getFirst(Query.select(TagData.PROPERTIES).where(TagData.UUID.eq(uuid))); - } - - public List tagDataOrderedByName() { - return dao.toList(Query.select(TagData.PROPERTIES).where(Criterion.and( - TagData.DELETION_DATE.eq(0), - TagData.NAME.isNotNull())) - .orderBy(Order.asc(Functions.upper(TagData.NAME)))); - } + @Query("UPDATE tagdata SET name = :name WHERE remoteId = :remoteId") + public abstract void rename(String remoteId, String name); - public void persist(TagData tagData) { - dao.persist(tagData); - } + @Query("DELETE FROM tagdata WHERE _id = :id") + public abstract void delete(Long id); - public void update(Criterion where, TagData template) { - dao.update(where, template); - } - - public void delete(long id) { - dao.delete(id); - } + @Insert + public abstract void insert(TagData tag); public void createNew(TagData tag) { - dao.createNew(tag); + if (RemoteModel.isUuidEmpty(tag.getRemoteId())) { + tag.setRemoteId(UUIDHelper.newUUID()); + } + insert(tag); } } diff --git a/app/src/main/java/com/todoroo/astrid/data/TagData.java b/app/src/main/java/com/todoroo/astrid/data/TagData.java index 28e274300..9351d2021 100644 --- a/app/src/main/java/com/todoroo/astrid/data/TagData.java +++ b/app/src/main/java/com/todoroo/astrid/data/TagData.java @@ -1,121 +1,180 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ package com.todoroo.astrid.data; +import android.arch.persistence.room.ColumnInfo; +import android.arch.persistence.room.Entity; +import android.arch.persistence.room.Ignore; +import android.arch.persistence.room.PrimaryKey; +import android.os.Parcel; +import android.os.Parcelable; -import android.content.ContentValues; +import org.tasks.backup.XmlReader; +import org.tasks.backup.XmlWriter; -import com.todoroo.andlib.data.Property; -import com.todoroo.andlib.data.Property.IntegerProperty; -import com.todoroo.andlib.data.Property.LongProperty; -import com.todoroo.andlib.data.Property.StringProperty; -import com.todoroo.andlib.data.Table; +@Entity(tableName = "tagdata") +public final class TagData implements Parcelable { -/** - * Data Model which represents a collaboration space for users / tasks. - * - * @author Tim Su - * - */ -public final class TagData extends RemoteModel { + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "_id") + private Long id; - // --- table and uri + @ColumnInfo(name = "remoteId") + private String remoteId = RemoteModel.NO_UUID; - /** table for this model */ - public static final Table TABLE = new Table("tagdata", TagData.class); + @ColumnInfo(name = "name") + private String name = ""; - // --- properties + @ColumnInfo(name = "color") + private Integer color = -1; - /** ID */ - public static final LongProperty ID = new LongProperty( - TABLE, ID_PROPERTY_NAME); + @ColumnInfo(name = "tagOrdering") + private String tagOrdering = "[]"; - /** Remote goal id */ - public static final StringProperty UUID = new StringProperty( - TABLE, UUID_PROPERTY_NAME); + @Deprecated + @ColumnInfo(name = "deleted") + private Long deleted = 0L; - /** Name of Tag */ - public static final StringProperty NAME = new StringProperty( - TABLE, "name"); + public TagData() { + } - public static final IntegerProperty COLOR = new IntegerProperty( - TABLE, "color"); + @Ignore + public TagData(XmlReader reader) { + reader.readString("remoteId", this::setRemoteId); + reader.readString("name", this::setName); + reader.readInteger("color", this::setColor); + reader.readString("tagOrdering", this::setTagOrdering); + reader.readLong("deleted", this::setDeleted); + } - /** Unixtime Project was deleted. 0 means not deleted */ - @Deprecated - public static final LongProperty DELETION_DATE = new LongProperty( - TABLE, "deleted", Property.PROP_FLAG_DATE); + @Ignore + private TagData(Parcel parcel) { + id = parcel.readLong(); + remoteId = parcel.readString(); + name = parcel.readString(); + color = parcel.readInt(); + tagOrdering = parcel.readString(); + deleted = parcel.readLong(); + } - /** Tag ordering */ - @Deprecated - public static final StringProperty TAG_ORDERING = new StringProperty( - TABLE, "tagOrdering"); + public void writeToXml(XmlWriter writer) { + writer.writeString("remoteId", remoteId); + writer.writeString("name", name); + writer.writeInteger("color", color); + writer.writeString("tagOrdering", tagOrdering); + writer.writeLong("deleted", deleted); + } - /** List of all properties for this model */ - public static final Property[] PROPERTIES = generateProperties(TagData.class); + public Long getId() { + return id; + } - // --- defaults + public void setId(long id) { + this.id = id; + } - /** Default values container */ - private static final ContentValues defaultValues = new ContentValues(); + public String getRemoteId() { + return remoteId; + } - static { - defaultValues.put(UUID.name, NO_UUID); - defaultValues.put(NAME.name, ""); - defaultValues.put(DELETION_DATE.name, 0); - defaultValues.put(TAG_ORDERING.name, "[]"); - defaultValues.put(COLOR.name, -1); + public void setRemoteId(String remoteId) { + this.remoteId = remoteId; } - @Override - public ContentValues getDefaultValues() { - return defaultValues; + public String getName() { + return name; } - @Override - public long getId() { - return getIdHelper(ID); + public void setName(String name) { + this.name = name; } - public String getUuid() { - return getUuidHelper(UUID); + public String getTagOrdering() { + return tagOrdering; } - // --- parcelable helpers + public void setTagOrdering(String tagOrdering) { + this.tagOrdering = tagOrdering; + } - public static final Creator CREATOR = new ModelCreator<>(TagData.class); + public Integer getColor() { + return color; + } - // --- data access methods + public void setColor(int color) { + this.color = color; + } - public String getName() { - return getValue(NAME); + public Long getDeleted() { + return deleted; } - public void setName(String name) { - setValue(NAME, name); + public void setDeleted(long deleted) { + this.deleted = deleted; } - public String getTagOrdering() { - return getValue(TAG_ORDERING); + public static final Creator CREATOR = new Creator() { + @Override + public TagData createFromParcel(Parcel source) { + return new TagData(source); + } + + @Override + public TagData[] newArray(int size) { + return new TagData[size]; + } + }; + + @Override + public int describeContents() { + return 0; } - public void setColor(int color) { - setValue(COLOR, color); + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(id); + dest.writeString(remoteId); + dest.writeString(name); + dest.writeInt(color); + dest.writeString(tagOrdering); + dest.writeLong(deleted); } - public int getColor() { - return getValue(COLOR); + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TagData tagData = (TagData) o; + + if (id != null ? !id.equals(tagData.id) : tagData.id != null) return false; + if (remoteId != null ? !remoteId.equals(tagData.remoteId) : tagData.remoteId != null) + return false; + if (name != null ? !name.equals(tagData.name) : tagData.name != null) return false; + if (color != null ? !color.equals(tagData.color) : tagData.color != null) return false; + if (tagOrdering != null ? !tagOrdering.equals(tagData.tagOrdering) : tagData.tagOrdering != null) + return false; + return deleted != null ? deleted.equals(tagData.deleted) : tagData.deleted == null; } - // TODO: remove? - public String getUUID() { - return getValue(UUID); + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (remoteId != null ? remoteId.hashCode() : 0); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (color != null ? color.hashCode() : 0); + result = 31 * result + (tagOrdering != null ? tagOrdering.hashCode() : 0); + result = 31 * result + (deleted != null ? deleted.hashCode() : 0); + return result; } - public void setUUID(String uuid) { - setValue(UUID, uuid); + @Override + public String toString() { + return "TagData{" + + "id=" + id + + ", remoteId='" + remoteId + '\'' + + ", name='" + name + '\'' + + ", color=" + color + + ", tagOrdering='" + tagOrdering + '\'' + + ", deleted=" + deleted + + '}'; } } diff --git a/app/src/main/java/com/todoroo/astrid/service/StartupService.java b/app/src/main/java/com/todoroo/astrid/service/StartupService.java index c00a0f56b..d386fb234 100644 --- a/app/src/main/java/com/todoroo/astrid/service/StartupService.java +++ b/app/src/main/java/com/todoroo/astrid/service/StartupService.java @@ -137,7 +137,7 @@ public class StartupService { } private void removeDuplicateTags() { - ListMultimap tagsByUuid = Multimaps.index(tagService.getTagList(), TagData::getUuid); + ListMultimap tagsByUuid = Multimaps.index(tagService.getTagList(), TagData::getRemoteId); for (String uuid : tagsByUuid.keySet()) { removeDuplicateTagData(tagsByUuid.get(uuid)); removeDuplicateTagMetadata(uuid); diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskCreator.java b/app/src/main/java/com/todoroo/astrid/service/TaskCreator.java index 5dbeda4e1..2c3e26141 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskCreator.java +++ b/app/src/main/java/com/todoroo/astrid/service/TaskCreator.java @@ -148,7 +148,7 @@ public class TaskCreator { tagData.setName(tagName); tagDataDao.persist(tagData); } - createLink(task, tagData.getName(), tagData.getUUID()); + createLink(task, tagData.getName(), tagData.getRemoteId()); } private void createLink(Task task, String tagName, String tagUuid) { diff --git a/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksHelper.java b/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksHelper.java index d323b9f4a..0416607c2 100644 --- a/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksHelper.java +++ b/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksHelper.java @@ -66,7 +66,7 @@ public class SubtasksHelper { TagData tagData = tagDataDao.getTagByName(filter.listingTitle); TaskListMetadata tlm = null; if (tagData != null) { - tlm = taskListMetadataDao.fetchByTagId(tagData.getUuid()); + tlm = taskListMetadataDao.fetchByTagId(tagData.getRemoteId()); } else if (BuiltInFilterExposer.isInbox(context, filter)) { tlm = taskListMetadataDao.fetchByTagId(TaskListMetadata.FILTER_ID_ALL); } else if (BuiltInFilterExposer.isTodayFilter(context, filter)) { diff --git a/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java b/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java index 45a9b3f25..891c2a371 100644 --- a/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java +++ b/app/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java @@ -48,8 +48,8 @@ public class SubtasksTagListFragment extends TagListFragment { @Override public void setTaskAdapter() { - String tdId = tagData.getUuid(); - TaskListMetadata taskListMetadata = taskListMetadataDao.fetchByTagId(tagData.getUuid()); + String tdId = tagData.getRemoteId(); + TaskListMetadata taskListMetadata = taskListMetadataDao.fetchByTagId(tagData.getRemoteId()); if (taskListMetadata == null && !RemoteModel.isUuidEmpty(tdId)) { taskListMetadata = new TaskListMetadata(); taskListMetadata.setTagUUID(tdId); diff --git a/app/src/main/java/com/todoroo/astrid/tags/TagService.java b/app/src/main/java/com/todoroo/astrid/tags/TagService.java index 256f84f98..45c79aa09 100644 --- a/app/src/main/java/com/todoroo/astrid/tags/TagService.java +++ b/app/src/main/java/com/todoroo/astrid/tags/TagService.java @@ -156,9 +156,7 @@ public final class TagService { } public int rename(String uuid, String newName) { - TagData template = new TagData(); - template.setName(newName); - tagDataDao.update(TagData.UUID.eq(uuid), template); + tagDataDao.rename(uuid, newName); Metadata metadataTemplate = new Metadata(); metadataTemplate.setValue(TaskToTagMetadata.TAG_NAME, newName); diff --git a/app/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java b/app/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java index 50c14b87c..ac3440923 100644 --- a/app/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java +++ b/app/src/main/java/com/todoroo/astrid/tags/TagsControlSet.java @@ -390,7 +390,7 @@ public final class TagsControlSet extends TaskEditControlFragment { */ private boolean synchronizeTags(long taskId, String taskUuid) { for (TagData tagData : selectedTags) { - if (RemoteModel.NO_UUID.equals(tagData.getUuid())) { + if (RemoteModel.NO_UUID.equals(tagData.getRemoteId())) { tagDataDao.persist(tagData); } } @@ -400,7 +400,7 @@ public final class TagsControlSet extends TaskEditControlFragment { Sets.SetView removed = difference(existingHash, selectedHash); deleteLinks(taskId, taskUuid, filter(removed, notNull())); for (TagData tagData : added) { - Metadata newLink = TaskToTagMetadata.newTagMetadata(taskId, taskUuid, tagData.getName(), tagData.getUuid()); + Metadata newLink = TaskToTagMetadata.newTagMetadata(taskId, taskUuid, tagData.getName(), tagData.getRemoteId()); metadataDao.createNew(newLink); } return !removed.isEmpty() || !added.isEmpty(); @@ -416,9 +416,9 @@ public final class TagsControlSet extends TaskEditControlFragment { for (TagData tag : tags) { // TODO: Right now this is in a loop because each deleteTemplate needs the individual tagUuid in order to record // the outstanding entry correctly. If possible, this should be improved to a single query - deleteTemplate.setValue(TaskToTagMetadata.TAG_UUID, tag.getUuid()); // Need this for recording changes in outstanding table + deleteTemplate.setValue(TaskToTagMetadata.TAG_UUID, tag.getRemoteId()); // Need this for recording changes in outstanding table metadataDao.update(Criterion.and(MetadataDao.MetadataCriteria.withKey(TaskToTagMetadata.KEY), Metadata.DELETION_DATE.eq(0), - TaskToTagMetadata.TASK_UUID.eq(taskUuid), TaskToTagMetadata.TAG_UUID.eq(tag.getUuid())), deleteTemplate); + TaskToTagMetadata.TASK_UUID.eq(taskUuid), TaskToTagMetadata.TAG_UUID.eq(tag.getRemoteId())), deleteTemplate); } } diff --git a/app/src/main/java/org/tasks/activities/TagSettingsActivity.java b/app/src/main/java/org/tasks/activities/TagSettingsActivity.java index 6658cb768..dbd21307f 100644 --- a/app/src/main/java/org/tasks/activities/TagSettingsActivity.java +++ b/app/src/main/java/org/tasks/activities/TagSettingsActivity.java @@ -90,7 +90,7 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity implem if (tagData == null) { isNewTag = true; tagData = new TagData(); - tagData.setUUID(UUIDHelper.newUUID()); + tagData.setRemoteId(UUIDHelper.newUUID()); } if (savedInstanceState == null) { selectedTheme = tagData.getColor(); @@ -195,13 +195,13 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity implem } else if (hasChanges()) { tagData.setName(newName); tagData.setColor(selectedTheme); - tagService.rename(tagData.getUuid(), newName); + tagService.rename(tagData.getRemoteId(), newName); tagDataDao.persist(tagData); Metadata m = new Metadata(); m.setValue(TaskToTagMetadata.TAG_NAME, newName); metadataDao.update(Criterion.and( MetadataDao.MetadataCriteria.withKey(TaskToTagMetadata.KEY), - TaskToTagMetadata.TAG_UUID.eq(tagData.getUUID())), m); + TaskToTagMetadata.TAG_UUID.eq(tagData.getRemoteId())), m); setResult(RESULT_OK, new Intent(ACTION_RELOAD).putExtra(TaskListActivity.OPEN_FILTER, new TagFilter(tagData))); } @@ -249,7 +249,7 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity implem dialogBuilder.newMessageDialog(R.string.delete_tag_confirmation, tagData.getName()) .setPositiveButton(R.string.delete, (dialog, which) -> { if (tagData != null) { - String uuid = tagData.getUuid(); + String uuid = tagData.getRemoteId(); metadataDao.deleteWhere(Criterion.and(MetadataDao.MetadataCriteria.withKey(TaskToTagMetadata.KEY), TaskToTagMetadata.TAG_UUID.eq(uuid))); tagDataDao.delete(tagData.getId()); setResult(RESULT_OK, new Intent(ACTION_DELETED).putExtra(EXTRA_TAG_UUID, uuid)); diff --git a/app/src/main/java/org/tasks/backup/XmlReader.java b/app/src/main/java/org/tasks/backup/XmlReader.java new file mode 100644 index 000000000..9ad12f167 --- /dev/null +++ b/app/src/main/java/org/tasks/backup/XmlReader.java @@ -0,0 +1,41 @@ +package org.tasks.backup; + +import com.todoroo.astrid.backup.TasksXmlExporter; + +import org.xmlpull.v1.XmlPullParser; + +public class XmlReader { + + public interface ValueWriter { + void write(T value); + } + + private final XmlPullParser xpp; + + public XmlReader(XmlPullParser xpp) { + this.xpp = xpp; + } + + public void readLong(String name, ValueWriter writer) { + String value = xpp.getAttributeValue(null, name); + if(value != null) { + writer.write(TasksXmlExporter.XML_NULL.equals(value) ? + null : Long.parseLong(value)); + } + } + + public void readInteger(String name, ValueWriter writer) { + String value = xpp.getAttributeValue(null, name); + if(value != null) { + writer.write(TasksXmlExporter.XML_NULL.equals(value) ? + null : Integer.parseInt(value)); + } + } + + public void readString(String name, ValueWriter writer) { + String value = xpp.getAttributeValue(null, name); + if (value != null) { + writer.write(value); + } + } +} diff --git a/app/src/main/java/org/tasks/backup/XmlWriter.java b/app/src/main/java/org/tasks/backup/XmlWriter.java new file mode 100644 index 000000000..2f7e52d8c --- /dev/null +++ b/app/src/main/java/org/tasks/backup/XmlWriter.java @@ -0,0 +1,54 @@ +package org.tasks.backup; + +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; + +import timber.log.Timber; + +import static com.todoroo.astrid.backup.TasksXmlExporter.XML_NULL; + +public class XmlWriter { + private final XmlSerializer xml; + + public XmlWriter(XmlSerializer xml) { + this.xml = xml; + } + + public void writeLong(String name, Long value) { + try { + String valueString = (value == null) ? XML_NULL : value.toString(); + xml.attribute(null, name, valueString); + } catch (UnsupportedOperationException e) { + // didn't read this value, do nothing + Timber.e(e, e.getMessage()); + } catch (IllegalArgumentException | IOException | IllegalStateException e) { + throw new RuntimeException(e); + } + } + + public void writeString(String name, String value) { + try { + if(value != null) { + xml.attribute(null, name, value); + } + } catch (UnsupportedOperationException e) { + // didn't read this value, do nothing + Timber.v(e, e.getMessage()); + } catch (IllegalArgumentException | IOException | IllegalStateException e) { + throw new RuntimeException(e); + } + } + + public void writeInteger(String name, Integer value) { + try { + String valueString = (value == null) ? XML_NULL : value.toString(); + xml.attribute(null, name, valueString); + } catch (UnsupportedOperationException e) { + // didn't read this value, do nothing + Timber.e(e, e.getMessage()); + } catch (IllegalArgumentException | IOException | IllegalStateException e) { + throw new RuntimeException(e); + } + } +} diff --git a/app/src/main/java/org/tasks/db/Migrations.java b/app/src/main/java/org/tasks/db/Migrations.java index 26b329ef6..55d59a5ab 100644 --- a/app/src/main/java/org/tasks/db/Migrations.java +++ b/app/src/main/java/org/tasks/db/Migrations.java @@ -44,11 +44,19 @@ public class Migrations { } }; + private static final Migration MIGRATION_39_40 = new Migration(39, 40) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + + } + }; + public static Migration[] MIGRATIONS = new Migration[] { MIGRATION_35_36, MIGRATION_36_37, MIGRATION_37_38, - MIGRATION_38_39 + MIGRATION_38_39, + MIGRATION_39_40 }; public static RoomDatabase.Callback ON_CREATE = new RoomDatabase.Callback() { diff --git a/app/src/main/java/org/tasks/injection/ApplicationModule.java b/app/src/main/java/org/tasks/injection/ApplicationModule.java index dc03ca21b..425a9c47f 100644 --- a/app/src/main/java/org/tasks/injection/ApplicationModule.java +++ b/app/src/main/java/org/tasks/injection/ApplicationModule.java @@ -4,6 +4,7 @@ import android.arch.persistence.room.Room; import android.content.Context; import com.todoroo.astrid.dao.Database; +import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.provider.Astrid2TaskProvider; import org.tasks.ErrorReportingSingleThreadExecutor; @@ -50,6 +51,7 @@ public class ApplicationModule { public Database getAppDatabase() { return Room .databaseBuilder(context, Database.class, Database.NAME) + .allowMainThreadQueries() // TODO: remove me .addMigrations(Migrations.MIGRATIONS) .addCallback(Migrations.ON_CREATE) .build() @@ -60,4 +62,9 @@ public class ApplicationModule { public NotificationDao getNotificationDao(Database database) { return database.notificationDao(); } + + @Provides + public TagDataDao getTagDataDao(Database database) { + return database.getTagDataDao(); + } } diff --git a/app/src/main/java/org/tasks/tasklist/TagFormatter.java b/app/src/main/java/org/tasks/tasklist/TagFormatter.java index 471b0e0b5..ba559ae39 100644 --- a/app/src/main/java/org/tasks/tasklist/TagFormatter.java +++ b/app/src/main/java/org/tasks/tasklist/TagFormatter.java @@ -48,7 +48,7 @@ public class TagFormatter { tagCharacters = typedValue.getFloat(); for (TagData tagData : tagService.getTagList()) { - tagMap.put(tagData.getUuid(), tagData); + tagMap.put(tagData.getRemoteId(), tagData); } }