From 88d5e73d322a0844a502ae989ba90b2f8536e954 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 8 Feb 2013 17:21:06 -0800 Subject: [PATCH 01/10] Added TaskAttachment data model --- .../todoroo/astrid/data/TaskAttachment.java | 150 ++++++++++++++++++ .../src/com/todoroo/astrid/dao/Database.java | 3 + 2 files changed, 153 insertions(+) create mode 100644 api/src/com/todoroo/astrid/data/TaskAttachment.java diff --git a/api/src/com/todoroo/astrid/data/TaskAttachment.java b/api/src/com/todoroo/astrid/data/TaskAttachment.java new file mode 100644 index 000000000..51acc2f3a --- /dev/null +++ b/api/src/com/todoroo/astrid/data/TaskAttachment.java @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2012 Todoroo Inc + * + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.data; + + +import android.content.ContentValues; +import android.net.Uri; + +import com.todoroo.andlib.data.AbstractModel; +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; +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.astrid.api.AstridApiConstants; + +/** + * Data Model which represents a user. + * + * @author Tim Su + * + */ +@SuppressWarnings("nls") +public final class TaskAttachment extends RemoteModel { + + // --- table and uri + + /** table for this model */ + public static final Table TABLE = new Table("task_attachments", TaskAttachment.class); + + /** content uri for this model */ + public static final Uri CONTENT_URI = Uri.parse("content://" + AstridApiConstants.API_PACKAGE + "/" + + TABLE.name); + + // --- properties + + /** ID */ + public static final LongProperty ID = new LongProperty( + TABLE, ID_PROPERTY_NAME); + + /** Remote id */ + public static final StringProperty UUID = new StringProperty( + TABLE, UUID_PROPERTY_NAME); + + /** Pushed at date */ + public static final LongProperty PUSHED_AT = new LongProperty( + TABLE, PUSHED_AT_PROPERTY_NAME); + + /** Creator user id */ + public static final StringProperty USER_UUID = new StringProperty( + TABLE, "user_id"); + + /** Task uuid */ + public static final StringProperty TASK_UUID = new StringProperty( + TABLE, "task_id"); + + /** File name */ + public static final StringProperty NAME = new StringProperty( + TABLE, "name"); + + /** File url (for downloading) */ + public static final StringProperty URL = new StringProperty( + TABLE, "url"); + + /** File path (on local storage) */ + public static final StringProperty FILE_PATH = new StringProperty( + TABLE, "path"); + + /** File size (in bytes) */ + public static final IntegerProperty SIZE = new IntegerProperty( + TABLE, "size"); + + /** File mimetype */ + public static final StringProperty FILETYPE = new StringProperty( + TABLE, "filetype"); + + /** Attachment creation date */ + public static final LongProperty CREATED_AT = new LongProperty( + TABLE, "created_at", Property.PROP_FLAG_DATE); + + /** Attachment deletion date */ + public static final LongProperty DELETED_AT = new LongProperty( + TABLE, "created_at", Property.PROP_FLAG_DATE); + + /** List of all properties for this model */ + public static final Property[] PROPERTIES = generateProperties(TaskAttachment.class); + + // --- defaults + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + + static { + defaultValues.put(UUID.name, NO_UUID); + defaultValues.put(PUSHED_AT.name, 0); + defaultValues.put(USER_UUID.name, NO_UUID); + defaultValues.put(TASK_UUID.name, NO_UUID); + defaultValues.put(NAME.name, ""); + defaultValues.put(URL.name, ""); + defaultValues.put(FILE_PATH.name, ""); + defaultValues.put(SIZE.name, 0); + defaultValues.put(FILETYPE.name, ""); + defaultValues.put(CREATED_AT.name, 0); + defaultValues.put(DELETED_AT.name, 0); + } + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + // --- data access boilerplate + + public TaskAttachment() { + super(); + } + + public TaskAttachment(TodorooCursor cursor) { + this(); + readPropertiesFromCursor(cursor); + } + + public void readFromCursor(TodorooCursor cursor) { + super.readPropertiesFromCursor(cursor); + } + + @Override + public long getId() { + return getIdHelper(ID); + } + + @Override + public String getUuid() { + return getUuidHelper(UUID); + } + + // --- parcelable helpers + + public static final Creator CREATOR = new ModelCreator(TaskAttachment.class); + + @Override + protected Creator getCreator() { + return CREATOR; + } + +} diff --git a/astrid/src/com/todoroo/astrid/dao/Database.java b/astrid/src/com/todoroo/astrid/dao/Database.java index d4d49b10e..9dee69beb 100644 --- a/astrid/src/com/todoroo/astrid/dao/Database.java +++ b/astrid/src/com/todoroo/astrid/dao/Database.java @@ -22,6 +22,7 @@ import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagMetadata; import com.todoroo.astrid.data.TagOutstanding; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.data.TaskOutstanding; import com.todoroo.astrid.data.Update; import com.todoroo.astrid.data.User; @@ -68,6 +69,7 @@ public class Database extends AbstractDatabase { ABTestEvent.TABLE, TagMetadata.TABLE, History.TABLE, + TaskAttachment.TABLE, TaskOutstanding.TABLE, TagOutstanding.TABLE, @@ -342,6 +344,7 @@ public class Database extends AbstractDatabase { database.execSQL(createTableSql(visitor, UserActivity.TABLE.name, UserActivity.PROPERTIES)); database.execSQL(createTableSql(visitor, UserActivityOutstanding.TABLE.name, UserActivityOutstanding.PROPERTIES)); database.execSQL(createTableSql(visitor, History.TABLE.name, History.PROPERTIES)); + database.execSQL(createTableSql(visitor, TaskAttachment.TABLE.name, TaskAttachment.PROPERTIES)); database.execSQL(addColumnSql(Task.TABLE, Task.PUSHED_AT, visitor, null)); database.execSQL(addColumnSql(Task.TABLE, Task.IS_PUBLIC, visitor, "0")); From f3d7b1958c9ebe05c5701cf1081b745ada460c3a Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 8 Feb 2013 17:59:37 -0800 Subject: [PATCH 02/10] Added all the boilerplate for task attachments--outstanding daos, integration with messages, etc. --- .../todoroo/astrid/data/TaskAttachment.java | 6 +- .../sync/messages/AcknowledgeChange.java | 2 + .../astrid/actfm/sync/messages/NameMaps.java | 80 +++++++++++-------- .../sync/messages/ServerToClientMessage.java | 5 ++ .../todoroo/astrid/core/PluginServices.java | 16 ++++ .../src/com/todoroo/astrid/dao/Database.java | 3 + 6 files changed, 77 insertions(+), 35 deletions(-) diff --git a/api/src/com/todoroo/astrid/data/TaskAttachment.java b/api/src/com/todoroo/astrid/data/TaskAttachment.java index 51acc2f3a..593f1c880 100644 --- a/api/src/com/todoroo/astrid/data/TaskAttachment.java +++ b/api/src/com/todoroo/astrid/data/TaskAttachment.java @@ -75,8 +75,8 @@ public final class TaskAttachment extends RemoteModel { TABLE, "size"); /** File mimetype */ - public static final StringProperty FILETYPE = new StringProperty( - TABLE, "filetype"); + public static final StringProperty CONTENT_TYPE = new StringProperty( + TABLE, "content_type"); /** Attachment creation date */ public static final LongProperty CREATED_AT = new LongProperty( @@ -103,7 +103,7 @@ public final class TaskAttachment extends RemoteModel { defaultValues.put(URL.name, ""); defaultValues.put(FILE_PATH.name, ""); defaultValues.put(SIZE.name, 0); - defaultValues.put(FILETYPE.name, ""); + defaultValues.put(CONTENT_TYPE.name, ""); defaultValues.put(CREATED_AT.name, 0); defaultValues.put(DELETED_AT.name, 0); } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/AcknowledgeChange.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/AcknowledgeChange.java index 9f51567f8..f57d0340a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/AcknowledgeChange.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/AcknowledgeChange.java @@ -27,6 +27,8 @@ public class AcknowledgeChange extends ServerToClientMessage { dao = PluginServices.getTagOutstandingDao(); else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) dao = PluginServices.getUserActivityOutstandingDao(); + else if (NameMaps.TABLE_ID_ATTACHMENTS.equals(table)) + dao = PluginServices.getTaskAttachmentOutstandingDao(); else dao = null; } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java index 348ae579b..ccd635afc 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java @@ -8,8 +8,10 @@ import java.util.Set; import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Table; import com.todoroo.andlib.utility.AndroidUtilities; +import com.todoroo.astrid.data.History; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.data.User; import com.todoroo.astrid.data.UserActivity; @@ -28,6 +30,7 @@ public class NameMaps { public static final String TABLE_ID_USERS = "users"; public static final String TABLE_ID_USER_ACTIVITY = "user_activities"; public static final String TABLE_ID_HISTORY = "history"; + public static final String TABLE_ID_ATTACHMENTS = "task_attachments"; private static final String PUSHED_AT_PREFIX = "pushed_at"; public static final String PUSHED_AT_TASKS = PUSHED_AT_PREFIX + "_" + TABLE_ID_TASKS; @@ -41,7 +44,9 @@ public class NameMaps { TABLE_LOCAL_TO_SERVER.put(Task.TABLE, TABLE_ID_TASKS); TABLE_LOCAL_TO_SERVER.put(TagData.TABLE, TABLE_ID_TAGS); TABLE_LOCAL_TO_SERVER.put(User.TABLE, TABLE_ID_USERS); + TABLE_LOCAL_TO_SERVER.put(History.TABLE, TABLE_ID_HISTORY); TABLE_LOCAL_TO_SERVER.put(UserActivity.TABLE, TABLE_ID_USER_ACTIVITY); + TABLE_LOCAL_TO_SERVER.put(TaskAttachment.TABLE, TABLE_ID_ATTACHMENTS); // Reverse the mapping to construct the server to local map TABLE_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TABLE_LOCAL_TO_SERVER); @@ -76,6 +81,8 @@ public class NameMaps { return computeSyncableProperties(TAG_DATA_PROPERTIES_LOCAL_TO_SERVER.keySet(), TAG_PROPERTIES_EXCLUDED); else if (TABLE_ID_USER_ACTIVITY.equals(table)) return computeSyncableProperties(USER_ACTIVITY_PROPERTIES_LOCAL_TO_SERVER.keySet(), USER_ACTIVITY_PROPERTIES_EXCLUDED); + else if (TABLE_ID_ATTACHMENTS.equals(table)) + return computeSyncableProperties(TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER.keySet(), TASK_ATTACHMENT_PROPERTIES_EXCLUDED); return null; } @@ -240,42 +247,46 @@ public class NameMaps { } // ---------- - // History + // TaskAttachment // ---------- -// private static final Map, String> HISTORY_PROPERTIES_LOCAL_TO_SERVER; -// private static final Map> HISTORY_COLUMN_NAMES_TO_PROPERTIES; -// private static final Map HISTORY_COLUMNS_LOCAL_TO_SERVER; -// private static final Map> HISTORY_PROPERTIES_SERVER_TO_LOCAL; -// private static final Set HISTORY_PROPERTIES_EXCLUDED; -// -// private static void putHistoryPropertyToServerName(Property property, String serverName, boolean writeable) { -// putPropertyToServerName(property, serverName, HISTORY_PROPERTIES_LOCAL_TO_SERVER, HISTORY_COLUMN_NAMES_TO_PROPERTIES, -// HISTORY_COLUMNS_LOCAL_TO_SERVER, HISTORY_PROPERTIES_EXCLUDED, writeable); -// } -// -// static { -// HISTORY_PROPERTIES_LOCAL_TO_SERVER = new HashMap, String>(); -// HISTORY_COLUMN_NAMES_TO_PROPERTIES = new HashMap>(); -// HISTORY_COLUMNS_LOCAL_TO_SERVER = new HashMap(); -// HISTORY_PROPERTIES_EXCLUDED = new HashSet(); -// -// putHistoryPropertyToServerName(History.UUID, "id", false); -// putHistoryPropertyToServerName(History.CREATED_AT, "created_at", false); -// putHistoryPropertyToServerName(History.USER_UUID, "user_id", false); -// putHistoryPropertyToServerName(History.COLUMN, "column", false); -// putHistoryPropertyToServerName(History.OLD_VALUE, "prev", false); -// putHistoryPropertyToServerName(History.NEW_VALUE, "value", false); -// -// // Reverse the mapping to construct the server to local map -// HISTORY_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(USER_ACTIVITY_PROPERTIES_LOCAL_TO_SERVER); -// } + private static final Map, String> TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER; + private static final Map> TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES; + private static final Map TASK_ATTACHMENT_COLUMNS_LOCAL_TO_SERVER; + private static final Map> TASK_ATTACHMENT_PROPERTIES_SERVER_TO_LOCAL; + private static final Set TASK_ATTACHMENT_PROPERTIES_EXCLUDED; + + private static void putTaskAttachmentPropertyToServerName(Property property, String serverName, boolean writeable) { + putPropertyToServerName(property, serverName, TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER, TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES, + TASK_ATTACHMENT_COLUMNS_LOCAL_TO_SERVER, TASK_ATTACHMENT_PROPERTIES_EXCLUDED, writeable); + } + + static { + TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER = new HashMap, String>(); + TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES = new HashMap>(); + TASK_ATTACHMENT_COLUMNS_LOCAL_TO_SERVER = new HashMap(); + TASK_ATTACHMENT_PROPERTIES_EXCLUDED = new HashSet(); + + putTaskAttachmentPropertyToServerName(TaskAttachment.UUID, "uuid", false); + putTaskAttachmentPropertyToServerName(TaskAttachment.USER_UUID, "user_id", true); + putTaskAttachmentPropertyToServerName(TaskAttachment.TASK_UUID, "task_id", true); + putTaskAttachmentPropertyToServerName(TaskAttachment.NAME, "name", false); + putTaskAttachmentPropertyToServerName(TaskAttachment.URL, "url", false); + putTaskAttachmentPropertyToServerName(TaskAttachment.SIZE, "size", false); + putTaskAttachmentPropertyToServerName(TaskAttachment.CONTENT_TYPE, "content_type", false); + putTaskAttachmentPropertyToServerName(TaskAttachment.CREATED_AT, "created_at", true); + putTaskAttachmentPropertyToServerName(TaskAttachment.DELETED_AT, "deleted_at", true); + + + // Reverse the mapping to construct the server to local map + TASK_ATTACHMENT_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER); + } // ---------- // Mapping helpers // ---------- - private static B mapColumnName(String table, String col, Map taskMap, Map tagMap, Map userMap, Map userActivityMap) { + private static B mapColumnName(String table, String col, Map taskMap, Map tagMap, Map userMap, Map userActivityMap, Map taskAttachmentMap) { Map map = null; if (TABLE_ID_TASKS.equals(table)) map = taskMap; @@ -285,6 +296,8 @@ public class NameMaps { map = userMap; else if (TABLE_ID_USER_ACTIVITY.equals(table)) map = userActivityMap; + else if (TABLE_ID_ATTACHMENTS.equals(table)) + map = taskAttachmentMap; if (map == null) return null; @@ -302,20 +315,23 @@ public class NameMaps { } else if (TABLE_ID_USER_ACTIVITY.equals(table)) { if (USER_ACTIVITY_COLUMN_NAMES_TO_PROPERTIES.containsKey(column)) return !USER_ACTIVITY_PROPERTIES_EXCLUDED.contains(column); + } else if (TABLE_ID_ATTACHMENTS.equals(table)) { + if (TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES.containsKey(column)) + return !TASK_ATTACHMENT_PROPERTIES_EXCLUDED.contains(column); } return false; } public static String localColumnNameToServerColumnName(String table, String localColumn) { - return mapColumnName(table, localColumn, TASK_COLUMNS_LOCAL_TO_SERVER, TAG_DATA_COLUMNS_LOCAL_TO_SERVER, USER_COLUMNS_LOCAL_TO_SERVER, USER_ACTIVITY_COLUMNS_LOCAL_TO_SERVER); + return mapColumnName(table, localColumn, TASK_COLUMNS_LOCAL_TO_SERVER, TAG_DATA_COLUMNS_LOCAL_TO_SERVER, USER_COLUMNS_LOCAL_TO_SERVER, USER_ACTIVITY_COLUMNS_LOCAL_TO_SERVER, TASK_ATTACHMENT_COLUMNS_LOCAL_TO_SERVER); } public static Property localColumnNameToProperty(String table, String localColumn) { - return mapColumnName(table, localColumn, TASK_COLUMN_NAMES_TO_PROPERTIES, TAG_DATA_COLUMN_NAMES_TO_PROPERTIES, USER_COLUMN_NAMES_TO_PROPERTIES, USER_ACTIVITY_COLUMN_NAMES_TO_PROPERTIES); + return mapColumnName(table, localColumn, TASK_COLUMN_NAMES_TO_PROPERTIES, TAG_DATA_COLUMN_NAMES_TO_PROPERTIES, USER_COLUMN_NAMES_TO_PROPERTIES, USER_ACTIVITY_COLUMN_NAMES_TO_PROPERTIES, TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES); } public static Property serverColumnNameToLocalProperty(String table, String serverColumn) { - return mapColumnName(table, serverColumn, TASK_PROPERTIES_SERVER_TO_LOCAL, TAG_DATA_PROPERTIES_SERVER_TO_LOCAL, USER_PROPERTIES_SERVER_TO_LOCAL, USER_ACTIVITY_PROPERTIES_SERVER_TO_LOCAL); + return mapColumnName(table, serverColumn, TASK_PROPERTIES_SERVER_TO_LOCAL, TAG_DATA_PROPERTIES_SERVER_TO_LOCAL, USER_PROPERTIES_SERVER_TO_LOCAL, USER_ACTIVITY_PROPERTIES_SERVER_TO_LOCAL, TASK_ATTACHMENT_PROPERTIES_SERVER_TO_LOCAL); } } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ServerToClientMessage.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ServerToClientMessage.java index 20f026f4e..11ec35986 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ServerToClientMessage.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ServerToClientMessage.java @@ -5,6 +5,7 @@ import org.json.JSONObject; import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.data.User; import com.todoroo.astrid.data.UserActivity; @@ -54,6 +55,8 @@ public abstract class ServerToClientMessage { return new MakeChanges(json, PluginServices.getUserDao()); else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) return new MakeChanges(json, PluginServices.getUserActivityDao()); + else if (NameMaps.TABLE_ID_ATTACHMENTS.equals(table)) + return new MakeChanges(json, PluginServices.getTaskAttachmentDao()); else return null; } @@ -68,6 +71,8 @@ public abstract class ServerToClientMessage { return new NowBriefed(json, PluginServices.getUserActivityDao()); else if (NameMaps.TABLE_ID_USERS.equals(table)) return new NowBriefed(json, PluginServices.getUserDao()); + else if (NameMaps.TABLE_ID_ATTACHMENTS.equals(table)) + return new NowBriefed(json, PluginServices.getTaskAttachmentDao()); else return null; } diff --git a/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java b/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java index 327e00488..c26421249 100644 --- a/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java +++ b/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java @@ -17,6 +17,8 @@ import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagMetadataDao; import com.todoroo.astrid.dao.TagOutstandingDao; +import com.todoroo.astrid.dao.TaskAttachmentDao; +import com.todoroo.astrid.dao.TaskAttachmentOutstandingDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskOutstandingDao; import com.todoroo.astrid.dao.UserActivityDao; @@ -85,6 +87,12 @@ public final class PluginServices { @Autowired HistoryDao historyDao; + @Autowired + TaskAttachmentDao taskAttachmentDao; + + @Autowired + TaskAttachmentOutstandingDao taskAttachmentOutstandingDao; + private static volatile PluginServices instance; static { @@ -172,6 +180,14 @@ public final class PluginServices { return getInstance().historyDao; } + public static TaskAttachmentDao getTaskAttachmentDao() { + return getInstance().taskAttachmentDao; + } + + public static TaskAttachmentOutstandingDao getTaskAttachmentOutstandingDao() { + return getInstance().taskAttachmentOutstandingDao; + } + // -- helpers /** diff --git a/astrid/src/com/todoroo/astrid/dao/Database.java b/astrid/src/com/todoroo/astrid/dao/Database.java index 9dee69beb..8c46a3410 100644 --- a/astrid/src/com/todoroo/astrid/dao/Database.java +++ b/astrid/src/com/todoroo/astrid/dao/Database.java @@ -23,6 +23,7 @@ import com.todoroo.astrid.data.TagMetadata; import com.todoroo.astrid.data.TagOutstanding; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskAttachment; +import com.todoroo.astrid.data.TaskAttachmentOutstanding; import com.todoroo.astrid.data.TaskOutstanding; import com.todoroo.astrid.data.Update; import com.todoroo.astrid.data.User; @@ -74,6 +75,7 @@ public class Database extends AbstractDatabase { TaskOutstanding.TABLE, TagOutstanding.TABLE, UserActivityOutstanding.TABLE, + TaskAttachmentOutstanding.TABLE }; // --- listeners @@ -340,6 +342,7 @@ public class Database extends AbstractDatabase { case 28: try { database.execSQL(createTableSql(visitor, TaskOutstanding.TABLE.name, TaskOutstanding.PROPERTIES)); database.execSQL(createTableSql(visitor, TagOutstanding.TABLE.name, TagOutstanding.PROPERTIES)); + database.execSQL(createTableSql(visitor, TaskAttachmentOutstanding.TABLE.name, TagOutstanding.PROPERTIES)); database.execSQL(createTableSql(visitor, TagMetadata.TABLE.name, TagMetadata.PROPERTIES)); database.execSQL(createTableSql(visitor, UserActivity.TABLE.name, UserActivity.PROPERTIES)); database.execSQL(createTableSql(visitor, UserActivityOutstanding.TABLE.name, UserActivityOutstanding.PROPERTIES)); From abc741b293a56ecc6a8eca1875a6c8eb092ad6ed Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 8 Feb 2013 18:25:30 -0800 Subject: [PATCH 03/10] Forgot to add dao files --- .../data/TaskAttachmentOutstanding.java | 63 +++++++++++++++++++ .../todoroo/astrid/dao/TaskAttachmentDao.java | 56 +++++++++++++++++ .../dao/TaskAttachmentOutstandingDao.java | 12 ++++ 3 files changed, 131 insertions(+) create mode 100644 api/src/com/todoroo/astrid/data/TaskAttachmentOutstanding.java create mode 100644 astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java create mode 100644 astrid/src/com/todoroo/astrid/dao/TaskAttachmentOutstandingDao.java diff --git a/api/src/com/todoroo/astrid/data/TaskAttachmentOutstanding.java b/api/src/com/todoroo/astrid/data/TaskAttachmentOutstanding.java new file mode 100644 index 000000000..a51960dc6 --- /dev/null +++ b/api/src/com/todoroo/astrid/data/TaskAttachmentOutstanding.java @@ -0,0 +1,63 @@ +package com.todoroo.astrid.data; + +import android.content.ContentValues; + +import com.todoroo.andlib.data.AbstractModel; +import com.todoroo.andlib.data.Property; +import com.todoroo.andlib.data.Property.LongProperty; +import com.todoroo.andlib.data.Property.StringProperty; +import com.todoroo.andlib.data.Table; + +@SuppressWarnings("nls") +public class TaskAttachmentOutstanding extends OutstandingEntry { + + /** table for this model */ + public static final Table TABLE = new Table("task_attachment_outstanding", TaskAttachmentOutstanding.class); + + // --- properties + + /** ID */ + public static final LongProperty ID = new LongProperty( + TABLE, ID_PROPERTY_NAME); + + public static final LongProperty TASK_ATTACHMENT_ID = new LongProperty( + TABLE, ENTITY_ID_PROPERTY_NAME); + + public static final StringProperty COLUMN_STRING = new StringProperty( + TABLE, COLUMN_STRING_PROPERTY_NAME); + + public static final StringProperty VALUE_STRING = new StringProperty( + TABLE, VALUE_STRING_PROPERTY_NAME); + + public static final LongProperty CREATED_AT = new LongProperty( + TABLE, CREATED_AT_PROPERTY_NAME); + + private static final ContentValues defaultValues = new ContentValues(); + + static { + defaultValues.put(TASK_ATTACHMENT_ID.name, 0); + defaultValues.put(COLUMN_STRING.name, ""); + defaultValues.put(VALUE_STRING.name, ""); + } + + /** List of all properties for this model */ + public static final Property[] PROPERTIES = generateProperties(TaskAttachmentOutstanding.class); + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + @Override + public long getId() { + return getIdHelper(ID); + } + + public static final Creator CREATOR = new ModelCreator(TaskAttachmentOutstanding.class); + + @Override + protected Creator getCreator() { + return CREATOR; + } + +} diff --git a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java new file mode 100644 index 000000000..99ccc28af --- /dev/null +++ b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2012 Todoroo Inc + * + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.dao; + +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.astrid.actfm.sync.messages.NameMaps; +import com.todoroo.astrid.data.TagData; +import com.todoroo.astrid.data.TaskAttachment; + +/** + * Data Access layer for {@link TagData}-related operations. + * + * @author Tim Su + * + */ +public class TaskAttachmentDao extends RemoteModelDao { + + @Autowired Database database; + + @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UR_UNINIT_READ") + public TaskAttachmentDao() { + super(TaskAttachment.class); + DependencyInjectionService.getInstance().inject(this); + setDatabase(database); + } + + @Override + protected boolean shouldRecordOutstandingEntry(String columnName) { + return NameMaps.shouldRecordOutstandingColumnForTable(NameMaps.TABLE_ID_ATTACHMENTS, columnName); + } + + // --- SQL clause generators + + /** + * Generates SQL clauses + */ + public static class TagDataCriteria { + + /** @returns tasks by id */ + public static Criterion byId(long id) { + return TagData.ID.eq(id); + } + + public static Criterion isTeam() { + return TagData.IS_TEAM.eq(1); + } + + } + +} + diff --git a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentOutstandingDao.java b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentOutstandingDao.java new file mode 100644 index 000000000..c2dc328ae --- /dev/null +++ b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentOutstandingDao.java @@ -0,0 +1,12 @@ +package com.todoroo.astrid.dao; + +import com.todoroo.astrid.data.TaskAttachmentOutstanding; + + +public class TaskAttachmentOutstandingDao extends OutstandingEntryDao { + + public TaskAttachmentOutstandingDao() { + super(TaskAttachmentOutstanding.class); + } + +} From 2f98b8d308af7570fa5e22d2eb9507e0f05e71d3 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Sat, 9 Feb 2013 11:35:46 -0800 Subject: [PATCH 04/10] Removed and updated all references to FileMetadata to use new TaskAttachment --- .../todoroo/astrid/data/TaskAttachment.java | 37 +++ .../astrid/actfm/sync/ActFmSyncService.java | 314 +++++++++--------- .../todoroo/astrid/files/FileMetadata.java | 158 +++++---- .../todoroo/astrid/files/FileUtilities.java | 5 +- .../todoroo/astrid/files/FilesControlSet.java | 105 +++--- .../astrid/activity/EditPreferences.java | 6 +- .../astrid/activity/TaskEditFragment.java | 20 +- .../astrid/activity/TaskListFragment.java | 6 +- .../todoroo/astrid/adapter/TaskAdapter.java | 3 +- .../todoroo/astrid/dao/TaskAttachmentDao.java | 13 + .../com/todoroo/astrid/ui/QuickAddBar.java | 10 +- 11 files changed, 353 insertions(+), 324 deletions(-) diff --git a/api/src/com/todoroo/astrid/data/TaskAttachment.java b/api/src/com/todoroo/astrid/data/TaskAttachment.java index 593f1c880..1941eb565 100644 --- a/api/src/com/todoroo/astrid/data/TaskAttachment.java +++ b/api/src/com/todoroo/astrid/data/TaskAttachment.java @@ -113,6 +113,43 @@ public final class TaskAttachment extends RemoteModel { return defaultValues; } + // -- Constants + /** default directory for files on external storage */ + public static final String FILES_DIRECTORY_DEFAULT = "attachments"; //$NON-NLS-1$ + + /** preference key for some other download directory */ + public static final String FILES_DIRECTORY_PREF = "custom_files_dir"; //$NON-NLS-1$ + + /** Constants for file types */ + public static final String FILE_TYPE_AUDIO = "audio/"; //$NON-NLS-1$ + public static final String FILE_TYPE_IMAGE = "image/"; //$NON-NLS-1$ + public static final String FILE_TYPE_PDF = "application/pdf"; //$NON-NLS-1$ + + public static final String FILE_TYPE_DOC = "application/msword"; //$NON-NLS-1$ + public static final String FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; //$NON-NLS-1$ + public static final String FILE_TYPE_PPT = "application/vnd.ms-powerpoint"; //$NON-NLS-1$ + public static final String FILE_TYPE_PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; //$NON-NLS-1$ + public static final String FILE_TYPE_XLS = "application/vnd.ms-excel"; //$NON-NLS-1$ + public static final String FILE_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; //$NON-NLS-1$ + + public static final String[] MS_FILETYPES = { + FILE_TYPE_DOC, FILE_TYPE_DOCX, + FILE_TYPE_XLS, FILE_TYPE_XLSX, + FILE_TYPE_PPT, FILE_TYPE_PPTX, + }; + + public static final String FILE_TYPE_OTHER = "application/octet-stream"; //$NON-NLS-1$ + + public static TaskAttachment createNewAttachment(String taskUuid, String filePath, String fileName, String fileType) { + TaskAttachment attachment = new TaskAttachment(); + attachment.setValue(TaskAttachment.TASK_UUID, taskUuid); + attachment.setValue(NAME, fileName); + attachment.setValue(FILE_PATH, filePath); + attachment.setValue(CONTENT_TYPE, fileType); + attachment.setValue(DELETED_AT, 0L); + return attachment; + } + // --- data access boilerplate public TaskAttachment() { diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java index 58fbcaf3f..bf627552c 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java @@ -5,18 +5,13 @@ */ package com.todoroo.astrid.actfm.sync; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.http.entity.mime.MultipartEntity; -import org.apache.http.entity.mime.content.FileBody; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -26,11 +21,8 @@ import android.text.TextUtils; import android.util.Log; import com.timsu.astrid.GCMIntentService; -import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.andlib.sql.Criterion; -import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.billing.BillingConstants; @@ -38,13 +30,9 @@ import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.UserDao; -import com.todoroo.astrid.data.Metadata; -import com.todoroo.astrid.data.MetadataApiDao.MetadataCriteria; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.TagData; -import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.User; -import com.todoroo.astrid.files.FileMetadata; import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.TagDataService; @@ -290,99 +278,99 @@ public final class ActFmSyncService { handleException("fetch-tag-order-io", e); } } - - public void pushAttachmentInBackground(final Metadata fileMetadata) { - if (!ActFmPreferenceService.isPremiumUser()) - return; - new Thread(new Runnable() { - @Override - public void run() { - waitUntilEmpty.close(); - taskPushThreads.incrementAndGet(); - try { - Task t = taskDao.fetch(fileMetadata.getValue(Metadata.TASK), Task.UUID); - if (t == null || !RemoteModel.isValidUuid(t.getUuid())) - return; - if (fileMetadata.getValue(FileMetadata.DELETION_DATE) > 0) - deleteAttachment(fileMetadata); - else - pushAttachment(t.getValue(Task.UUID), fileMetadata); - } finally { - if (taskPushThreads.decrementAndGet() == 0) { - waitUntilEmpty.open(); - } - } - } - }).start(); - } - - /** - * Push a file attachment to the server - * @param remoteTaskId - * @param fileMetadata - */ - public void pushAttachment(String remoteTaskId, Metadata fileMetadata) { - if (!ActFmPreferenceService.isPremiumUser()) - return; - - if (!fileMetadata.containsNonNullValue(FileMetadata.FILE_PATH) || !RemoteModel.isValidUuid(remoteTaskId)) - return; - - File f = new File(fileMetadata.getValue(FileMetadata.FILE_PATH)); - if (!f.exists()) - return; - - if (!checkForToken()) - return; - - ArrayList params = new ArrayList(); - params.add("task_id"); params.add(remoteTaskId); - params.add("token"); params.add(token); - - try { - MultipartEntity entity = new MultipartEntity(); - FileBody body = new FileBody(f, fileMetadata.getValue(FileMetadata.FILE_TYPE)); - entity.addPart("file", body); - - JSONObject result = actFmInvoker.post("task_attachment_create", entity, - params.toArray(new Object[params.size()])); - - fileMetadata.setValue(FileMetadata.REMOTE_ID, result.optLong("id")); - fileMetadata.setValue(FileMetadata.URL, result.optString("url")); - metadataService.save(fileMetadata); - } catch (ActFmServiceException e) { - handleException("push-attachment-error", e); - } catch (IOException e) { - handleException("push-attachment-error", e); - } - } - - public void deleteAttachment(Metadata fileMetadata) { - long attachmentId = fileMetadata.getValue(FileMetadata.REMOTE_ID); - if (attachmentId <= 0) - return; - - if (!checkForToken()) - return; - - ArrayList params = new ArrayList(); - params.add("id"); params.add(attachmentId); - params.add("token"); params.add(token); - - try { - JSONObject result = actFmInvoker.post("task_attachment_remove", null, params.toArray(new Object[params.size()])); - if (result.optString("status").equals("success")) { - metadataService.delete(fileMetadata); - } - } catch (ActFmServiceException e) { - if (e.result != null && e.result.optString("code").equals("not_found")) - metadataService.delete(fileMetadata); - else - handleException("push-attachment-error", e); - } catch (IOException e) { - handleException("push-attachment-error", e); - } - } +// +// public void pushAttachmentInBackground(final Metadata fileMetadata) { +// if (!ActFmPreferenceService.isPremiumUser()) +// return; +// new Thread(new Runnable() { +// @Override +// public void run() { +// waitUntilEmpty.close(); +// taskPushThreads.incrementAndGet(); +// try { +// Task t = taskDao.fetch(fileMetadata.getValue(Metadata.TASK), Task.UUID); +// if (t == null || !RemoteModel.isValidUuid(t.getUuid())) +// return; +// if (fileMetadata.getValue(FileMetadata.DELETION_DATE) > 0) +// deleteAttachment(fileMetadata); +// else +// pushAttachment(t.getValue(Task.UUID), fileMetadata); +// } finally { +// if (taskPushThreads.decrementAndGet() == 0) { +// waitUntilEmpty.open(); +// } +// } +// } +// }).start(); +// } +// +// /** +// * Push a file attachment to the server +// * @param remoteTaskId +// * @param fileMetadata +// */ +// public void pushAttachment(String remoteTaskId, Metadata fileMetadata) { +// if (!ActFmPreferenceService.isPremiumUser()) +// return; +// +// if (!fileMetadata.containsNonNullValue(FileMetadata.FILE_PATH) || !RemoteModel.isValidUuid(remoteTaskId)) +// return; +// +// File f = new File(fileMetadata.getValue(FileMetadata.FILE_PATH)); +// if (!f.exists()) +// return; +// +// if (!checkForToken()) +// return; +// +// ArrayList params = new ArrayList(); +// params.add("task_id"); params.add(remoteTaskId); +// params.add("token"); params.add(token); +// +// try { +// MultipartEntity entity = new MultipartEntity(); +// FileBody body = new FileBody(f, fileMetadata.getValue(FileMetadata.FILE_TYPE)); +// entity.addPart("file", body); +// +// JSONObject result = actFmInvoker.post("task_attachment_create", entity, +// params.toArray(new Object[params.size()])); +// +// fileMetadata.setValue(FileMetadata.REMOTE_ID, result.optLong("id")); +// fileMetadata.setValue(FileMetadata.URL, result.optString("url")); +// metadataService.save(fileMetadata); +// } catch (ActFmServiceException e) { +// handleException("push-attachment-error", e); +// } catch (IOException e) { +// handleException("push-attachment-error", e); +// } +// } +// +// public void deleteAttachment(Metadata fileMetadata) { +// long attachmentId = fileMetadata.getValue(FileMetadata.REMOTE_ID); +// if (attachmentId <= 0) +// return; +// +// if (!checkForToken()) +// return; +// +// ArrayList params = new ArrayList(); +// params.add("id"); params.add(attachmentId); +// params.add("token"); params.add(token); +// +// try { +// JSONObject result = actFmInvoker.post("task_attachment_remove", null, params.toArray(new Object[params.size()])); +// if (result.optString("status").equals("success")) { +// metadataService.delete(fileMetadata); +// } +// } catch (ActFmServiceException e) { +// if (e.result != null && e.result.optString("code").equals("not_found")) +// metadataService.delete(fileMetadata); +// else +// handleException("push-attachment-error", e); +// } catch (IOException e) { +// handleException("push-attachment-error", e); +// } +// } // --- data fetch methods public int fetchFeaturedLists(int serverTime) throws JSONException, IOException { @@ -477,64 +465,64 @@ public final class ActFmSyncService { parameters[i+2] = getParameters[i]; return actFmInvoker.invoke(method, parameters); } - - // --- helpers - private void synchronizeAttachments(JSONObject item, Task model) { - TodorooCursor attachments = metadataService.query(Query.select(Metadata.PROPERTIES) - .where(Criterion.and(MetadataCriteria.byTaskAndwithKey(model.getId(), - FileMetadata.METADATA_KEY), FileMetadata.REMOTE_ID.gt(0)))); - try { - HashMap currentFiles = new HashMap(); - for (attachments.moveToFirst(); !attachments.isAfterLast(); attachments.moveToNext()) { - Metadata m = new Metadata(attachments); - currentFiles.put(m.getValue(FileMetadata.REMOTE_ID), m); - } - - JSONArray remoteFiles = item.getJSONArray("attachments"); - for (int i = 0; i < remoteFiles.length(); i++) { - JSONObject file = remoteFiles.getJSONObject(i); - - long id = file.optLong("id"); - if (currentFiles.containsKey(id)) { - // Match, make sure name and url are up to date, then remove from map - Metadata fileMetadata = currentFiles.get(id); - fileMetadata.setValue(FileMetadata.URL, file.getString("url")); - fileMetadata.setValue(FileMetadata.NAME, file.getString("name")); - metadataService.save(fileMetadata); - currentFiles.remove(id); - } else { - // Create new file attachment - Metadata newAttachment = FileMetadata.createNewFileMetadata(model.getId(), "", - file.getString("name"), file.getString("content_type")); - String url = file.getString("url"); - newAttachment.setValue(FileMetadata.URL, url); - newAttachment.setValue(FileMetadata.REMOTE_ID, id); - metadataService.save(newAttachment); - } - } - - // Remove all the leftovers - Set attachmentsToDelete = currentFiles.keySet(); - for (Long remoteId : attachmentsToDelete) { - Metadata toDelete = currentFiles.get(remoteId); - String path = toDelete.getValue(FileMetadata.FILE_PATH); - if (TextUtils.isEmpty(path)) - metadataService.delete(toDelete); - else { - File f = new File(toDelete.getValue(FileMetadata.FILE_PATH)); - if (!f.exists() || f.delete()) { - metadataService.delete(toDelete); - } - - } - } - - } catch (JSONException e) { - e.printStackTrace(); - } finally { - attachments.close(); - } - } +// +// // --- helpers +// private void synchronizeAttachments(JSONObject item, Task model) { +// TodorooCursor attachments = metadataService.query(Query.select(Metadata.PROPERTIES) +// .where(Criterion.and(MetadataCriteria.byTaskAndwithKey(model.getId(), +// FileMetadata.METADATA_KEY), FileMetadata.REMOTE_ID.gt(0)))); +// try { +// HashMap currentFiles = new HashMap(); +// for (attachments.moveToFirst(); !attachments.isAfterLast(); attachments.moveToNext()) { +// Metadata m = new Metadata(attachments); +// currentFiles.put(m.getValue(FileMetadata.REMOTE_ID), m); +// } +// +// JSONArray remoteFiles = item.getJSONArray("attachments"); +// for (int i = 0; i < remoteFiles.length(); i++) { +// JSONObject file = remoteFiles.getJSONObject(i); +// +// long id = file.optLong("id"); +// if (currentFiles.containsKey(id)) { +// // Match, make sure name and url are up to date, then remove from map +// Metadata fileMetadata = currentFiles.get(id); +// fileMetadata.setValue(FileMetadata.URL, file.getString("url")); +// fileMetadata.setValue(FileMetadata.NAME, file.getString("name")); +// metadataService.save(fileMetadata); +// currentFiles.remove(id); +// } else { +// // Create new file attachment +// Metadata newAttachment = FileMetadata.createNewFileMetadata(model.getId(), "", +// file.getString("name"), file.getString("content_type")); +// String url = file.getString("url"); +// newAttachment.setValue(FileMetadata.URL, url); +// newAttachment.setValue(FileMetadata.REMOTE_ID, id); +// metadataService.save(newAttachment); +// } +// } +// +// // Remove all the leftovers +// Set attachmentsToDelete = currentFiles.keySet(); +// for (Long remoteId : attachmentsToDelete) { +// Metadata toDelete = currentFiles.get(remoteId); +// String path = toDelete.getValue(FileMetadata.FILE_PATH); +// if (TextUtils.isEmpty(path)) +// metadataService.delete(toDelete); +// else { +// File f = new File(toDelete.getValue(FileMetadata.FILE_PATH)); +// if (!f.exists() || f.delete()) { +// metadataService.delete(toDelete); +// } +// +// } +// } +// +// } catch (JSONException e) { +// e.printStackTrace(); +// } finally { +// attachments.close(); +// } +// } protected void handleException(String message, Exception exception) { diff --git a/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java b/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java index 735924b08..a4fe924c2 100644 --- a/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java +++ b/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java @@ -5,87 +5,79 @@ */ package com.todoroo.astrid.files; -import com.todoroo.andlib.data.Property.LongProperty; -import com.todoroo.andlib.data.Property.StringProperty; -import com.todoroo.andlib.data.TodorooCursor; -import com.todoroo.andlib.sql.Criterion; -import com.todoroo.andlib.sql.Query; -import com.todoroo.astrid.core.PluginServices; -import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; -import com.todoroo.astrid.data.Metadata; -public class FileMetadata { - - /** metadata key */ - public static final String METADATA_KEY = "file"; //$NON-NLS-1$ - - /** default directory for files on external storage */ - public static final String FILES_DIRECTORY_DEFAULT = "attachments"; //$NON-NLS-1$ - - /** preference key for some other download directory */ - public static final String FILES_DIRECTORY_PREF = "custom_files_dir"; //$NON-NLS-1$ - - /** Constants for file types */ - public static final String FILE_TYPE_AUDIO = "audio/"; //$NON-NLS-1$ - public static final String FILE_TYPE_IMAGE = "image/"; //$NON-NLS-1$ - public static final String FILE_TYPE_PDF = "application/pdf"; //$NON-NLS-1$ - - public static final String FILE_TYPE_DOC = "application/msword"; //$NON-NLS-1$ - public static final String FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; //$NON-NLS-1$ - public static final String FILE_TYPE_PPT = "application/vnd.ms-powerpoint"; //$NON-NLS-1$ - public static final String FILE_TYPE_PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; //$NON-NLS-1$ - public static final String FILE_TYPE_XLS = "application/vnd.ms-excel"; //$NON-NLS-1$ - public static final String FILE_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; //$NON-NLS-1$ - - public static final String[] MS_FILETYPES = { - FILE_TYPE_DOC, FILE_TYPE_DOCX, - FILE_TYPE_XLS, FILE_TYPE_XLSX, - FILE_TYPE_PPT, FILE_TYPE_PPTX, - }; - - public static final String FILE_TYPE_OTHER = "application/octet-stream"; //$NON-NLS-1$ - - public static final StringProperty FILE_PATH = new StringProperty(Metadata.TABLE, - Metadata.VALUE1.name); - - public static final StringProperty FILE_TYPE = new StringProperty(Metadata.TABLE, - Metadata.VALUE2.name); - - public static final LongProperty DELETION_DATE = new LongProperty(Metadata.TABLE, - Metadata.VALUE3.name); - - public static final LongProperty REMOTE_ID = new LongProperty(Metadata.TABLE, - Metadata.VALUE4.name); - - public static final StringProperty URL = new StringProperty(Metadata.TABLE, - Metadata.VALUE5.name); - - public static final StringProperty NAME = new StringProperty(Metadata.TABLE, - Metadata.VALUE6.name); - - - public static Metadata createNewFileMetadata(long taskId, String filePath, String fileName, String fileType) { - Metadata metadata = new Metadata(); - metadata.setValue(Metadata.KEY, METADATA_KEY); - metadata.setValue(Metadata.TASK, taskId); - metadata.setValue(NAME, fileName); - metadata.setValue(FILE_PATH, filePath); - metadata.setValue(FILE_TYPE, fileType); - metadata.setValue(REMOTE_ID, 0L); - metadata.setValue(DELETION_DATE, 0L); - return metadata; - } - - public static boolean taskHasAttachments(long taskId) { - TodorooCursor files = PluginServices.getMetadataService() - .query(Query.select(Metadata.TASK).where( - Criterion.and(MetadataCriteria.byTaskAndwithKey(taskId, METADATA_KEY), - DELETION_DATE.eq(0))).limit(1)); - try { - return files.getCount() > 0; - } finally { - files.close(); - } - } - -} +//public class FileMetadata { +// +// /** metadata key */ +// public static final String METADATA_KEY = "file"; //$NON-NLS-1$ +// +// /** default directory for files on external storage */ +// public static final String FILES_DIRECTORY_DEFAULT = "attachments"; //$NON-NLS-1$ +// +// /** preference key for some other download directory */ +// public static final String FILES_DIRECTORY_PREF = "custom_files_dir"; //$NON-NLS-1$ +// +// /** Constants for file types */ +// public static final String FILE_TYPE_AUDIO = "audio/"; //$NON-NLS-1$ +// public static final String FILE_TYPE_IMAGE = "image/"; //$NON-NLS-1$ +// public static final String FILE_TYPE_PDF = "application/pdf"; //$NON-NLS-1$ +// +// public static final String FILE_TYPE_DOC = "application/msword"; //$NON-NLS-1$ +// public static final String FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; //$NON-NLS-1$ +// public static final String FILE_TYPE_PPT = "application/vnd.ms-powerpoint"; //$NON-NLS-1$ +// public static final String FILE_TYPE_PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; //$NON-NLS-1$ +// public static final String FILE_TYPE_XLS = "application/vnd.ms-excel"; //$NON-NLS-1$ +// public static final String FILE_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; //$NON-NLS-1$ +// +// public static final String[] MS_FILETYPES = { +// FILE_TYPE_DOC, FILE_TYPE_DOCX, +// FILE_TYPE_XLS, FILE_TYPE_XLSX, +// FILE_TYPE_PPT, FILE_TYPE_PPTX, +// }; +// +// public static final String FILE_TYPE_OTHER = "application/octet-stream"; //$NON-NLS-1$ +// +// public static final StringProperty FILE_PATH = new StringProperty(Metadata.TABLE, +// Metadata.VALUE1.name); +// +// public static final StringProperty FILE_TYPE = new StringProperty(Metadata.TABLE, +// Metadata.VALUE2.name); +// +// public static final LongProperty DELETION_DATE = new LongProperty(Metadata.TABLE, +// Metadata.VALUE3.name); +// +// public static final LongProperty REMOTE_ID = new LongProperty(Metadata.TABLE, +// Metadata.VALUE4.name); +// +// public static final StringProperty URL = new StringProperty(Metadata.TABLE, +// Metadata.VALUE5.name); +// +// public static final StringProperty NAME = new StringProperty(Metadata.TABLE, +// Metadata.VALUE6.name); +// +// +// public static Metadata createNewFileMetadata(long taskId, String filePath, String fileName, String fileType) { +// Metadata metadata = new Metadata(); +// metadata.setValue(Metadata.KEY, METADATA_KEY); +// metadata.setValue(Metadata.TASK, taskId); +// metadata.setValue(NAME, fileName); +// metadata.setValue(FILE_PATH, filePath); +// metadata.setValue(FILE_TYPE, fileType); +// metadata.setValue(REMOTE_ID, 0L); +// metadata.setValue(DELETION_DATE, 0L); +// return metadata; +// } +// +// public static boolean taskHasAttachments(long taskId) { +// TodorooCursor files = PluginServices.getMetadataService() +// .query(Query.select(Metadata.TASK).where( +// Criterion.and(MetadataCriteria.byTaskAndwithKey(taskId, METADATA_KEY), +// DELETION_DATE.eq(0))).limit(1)); +// try { +// return files.getCount() > 0; +// } finally { +// files.close(); +// } +// } +// +//} diff --git a/astrid/plugin-src/com/todoroo/astrid/files/FileUtilities.java b/astrid/plugin-src/com/todoroo/astrid/files/FileUtilities.java index 0516a04b8..7743608b8 100644 --- a/astrid/plugin-src/com/todoroo/astrid/files/FileUtilities.java +++ b/astrid/plugin-src/com/todoroo/astrid/files/FileUtilities.java @@ -16,6 +16,7 @@ import android.text.TextUtils; import com.timsu.astrid.R; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.data.TaskAttachment; public class FileUtilities { @@ -68,12 +69,12 @@ public class FileUtilities { public static File getAttachmentsDirectory(Context context) { File directory = null; - String customDir = Preferences.getStringValue(FileMetadata.FILES_DIRECTORY_PREF); + String customDir = Preferences.getStringValue(TaskAttachment.FILES_DIRECTORY_PREF); if (!TextUtils.isEmpty(customDir)) directory = new File(customDir); if (directory == null || !directory.exists()) - directory = context.getExternalFilesDir(FileMetadata.FILES_DIRECTORY_DEFAULT); + directory = context.getExternalFilesDir(TaskAttachment.FILES_DIRECTORY_DEFAULT); return directory; } diff --git a/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java b/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java index a97490893..578e211ca 100644 --- a/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java @@ -44,23 +44,19 @@ import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; -import com.todoroo.astrid.actfm.sync.ActFmSyncService; -import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; -import com.todoroo.astrid.data.Metadata; +import com.todoroo.astrid.dao.TaskAttachmentDao; +import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.service.MetadataService; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.ui.PopupControlSet; import com.todoroo.astrid.utility.Constants; public class FilesControlSet extends PopupControlSet { @Autowired - private MetadataService metadataService; + private TaskAttachmentDao taskAttachmentDao; - @Autowired - private ActFmSyncService actFmSyncService; - - private final ArrayList files = new ArrayList(); + private final ArrayList files = new ArrayList(); private final LinearLayout fileDisplayList; private LinearLayout fileList; private final LayoutInflater inflater; @@ -77,7 +73,7 @@ public class FilesControlSet extends PopupControlSet { @Override protected void refreshDisplayView() { fileDisplayList.removeAllViews(); - for (final Metadata m : files) { + for (final TaskAttachment m : files) { View fileRow = inflater.inflate(R.layout.file_display_row, null); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.RIGHT; @@ -95,16 +91,16 @@ public class FilesControlSet extends PopupControlSet { public void refreshMetadata() { if (model != null) { - TodorooCursor cursor = metadataService.query( - Query.select(Metadata.PROPERTIES) - .where(Criterion.and(MetadataCriteria.byTaskAndwithKey(model.getId(), FileMetadata.METADATA_KEY), - FileMetadata.DELETION_DATE.eq(0)))); + TodorooCursor cursor = taskAttachmentDao.query( + Query.select(TaskAttachment.PROPERTIES) + .where(Criterion.and(TaskAttachment.TASK_UUID.eq(model.getUuid()), + TaskAttachment.DELETED_AT.eq(0)))); try { files.clear(); for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - Metadata metadata = new Metadata(); - metadata.readFromCursor(cursor); - files.add(metadata); + TaskAttachment attachment = new TaskAttachment(); + attachment.readFromCursor(cursor); + files.add(attachment); } } finally { cursor.close(); @@ -117,15 +113,15 @@ public class FilesControlSet extends PopupControlSet { private void validateFiles() { for (int i = 0; i < files.size(); i++) { - Metadata m = files.get(i); - if (m.containsNonNullValue(FileMetadata.FILE_PATH)) { - File f = new File(m.getValue(FileMetadata.FILE_PATH)); + TaskAttachment m = files.get(i); + if (m.containsNonNullValue(TaskAttachment.FILE_PATH)) { + File f = new File(m.getValue(TaskAttachment.FILE_PATH)); if (!f.exists()) { - m.setValue(FileMetadata.FILE_PATH, ""); //$NON-NLS-1$ - if (m.containsNonNullValue(FileMetadata.URL)) { // We're ok, just the local file was deleted - metadataService.save(m); + m.setValue(TaskAttachment.FILE_PATH, ""); //$NON-NLS-1$ + if (m.containsNonNullValue(TaskAttachment.URL)) { // We're ok, just the local file was deleted + taskAttachmentDao.saveExisting(m); } else { // No local file and no url -- delete the metadata - metadataService.delete(m); + taskAttachmentDao.delete(m.getId()); files.remove(i); i--; } @@ -152,7 +148,7 @@ public class FilesControlSet extends PopupControlSet { final LinearLayout finalList = fileList; fileList.removeAllViews(); LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - for (final Metadata m : files) { + for (final TaskAttachment m : files) { final View fileRow = inflater.inflate(R.layout.file_row, null); setUpFileRow(m, fileRow, fileList, lp); @@ -170,16 +166,15 @@ public class FilesControlSet extends PopupControlSet { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface d, int which) { - if (m.getValue(FileMetadata.REMOTE_ID) > 0) { - m.setValue(FileMetadata.DELETION_DATE, DateUtilities.now()); - metadataService.save(m); - actFmSyncService.pushAttachmentInBackground(m); + if (RemoteModel.isValidUuid(m.getValue(TaskAttachment.UUID))) { + m.setValue(TaskAttachment.DELETED_AT, DateUtilities.now()); + taskAttachmentDao.saveExisting(m); } else { - metadataService.delete(m); + taskAttachmentDao.delete(m.getId()); } - if (m.containsNonNullValue(FileMetadata.FILE_PATH)) { - File f = new File(m.getValue(FileMetadata.FILE_PATH)); + if (m.containsNonNullValue(TaskAttachment.FILE_PATH)) { + File f = new File(m.getValue(TaskAttachment.FILE_PATH)); f.delete(); } files.remove(m); @@ -193,8 +188,8 @@ public class FilesControlSet extends PopupControlSet { } } - private void setupFileClickListener(View view, final Metadata m) { - final String filePath = m.containsNonNullValue(FileMetadata.FILE_PATH) ? m.getValue(FileMetadata.FILE_PATH) : null; + private void setupFileClickListener(View view, final TaskAttachment m) { + final String filePath = m.containsNonNullValue(TaskAttachment.FILE_PATH) ? m.getValue(TaskAttachment.FILE_PATH) : null; if (TextUtils.isEmpty(filePath)) { view.setOnClickListener(new OnClickListener() { @Override @@ -218,18 +213,18 @@ public class FilesControlSet extends PopupControlSet { } } - private void showFile(final Metadata m) { - final String fileType = m.containsNonNullValue(FileMetadata.FILE_TYPE) ? m.getValue(FileMetadata.FILE_TYPE) : FileMetadata.FILE_TYPE_OTHER; - final String filePath = m.getValue(FileMetadata.FILE_PATH); + private void showFile(final TaskAttachment m) { + final String fileType = m.containsNonNullValue(TaskAttachment.CONTENT_TYPE) ? m.getValue(TaskAttachment.CONTENT_TYPE) : TaskAttachment.FILE_TYPE_OTHER; + final String filePath = m.getValue(TaskAttachment.FILE_PATH); - if (fileType.startsWith(FileMetadata.FILE_TYPE_AUDIO)) { - RecognizerApi.play(activity, m.getValue(FileMetadata.FILE_PATH), new PlaybackExceptionHandler() { + if (fileType.startsWith(TaskAttachment.FILE_TYPE_AUDIO)) { + RecognizerApi.play(activity, m.getValue(TaskAttachment.FILE_PATH), new PlaybackExceptionHandler() { @Override public void playbackFailed(String file) { showFromIntent(filePath, fileType); } }); - } else if (fileType.startsWith(FileMetadata.FILE_TYPE_IMAGE)) { + } else if (fileType.startsWith(TaskAttachment.FILE_TYPE_IMAGE)) { AlertDialog image = new AlertDialog.Builder(activity).create(); ImageView imageView = new ImageView(activity); imageView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); @@ -252,7 +247,7 @@ public class FilesControlSet extends PopupControlSet { image.show(); } else { String useType = fileType; - if (fileType.equals(FileMetadata.FILE_TYPE_OTHER)) { + if (fileType.equals(TaskAttachment.FILE_TYPE_OTHER)) { String extension = AndroidUtilities.getFileExtension(filePath); MimeTypeMap map = MimeTypeMap.getSingleton(); @@ -260,8 +255,8 @@ public class FilesControlSet extends PopupControlSet { if (!TextUtils.isEmpty(guessedType)) useType = guessedType; if (useType != guessedType) { - m.setValue(FileMetadata.FILE_TYPE, useType); - metadataService.save(m); + m.setValue(TaskAttachment.CONTENT_TYPE, useType); + taskAttachmentDao.saveExisting(m); } } showFromIntent(filePath, useType); @@ -279,11 +274,11 @@ public class FilesControlSet extends PopupControlSet { } private void handleActivityNotFound(String fileType) { - if (fileType.startsWith(FileMetadata.FILE_TYPE_AUDIO)) { + if (fileType.startsWith(TaskAttachment.FILE_TYPE_AUDIO)) { searchMarket("com.clov4r.android.nil", R.string.search_market_audio_title, R.string.search_market_audio); //$NON-NLS-1$ - } else if (fileType.equals(FileMetadata.FILE_TYPE_PDF)) { + } else if (fileType.equals(TaskAttachment.FILE_TYPE_PDF)) { searchMarket("com.adobe.reader", R.string.search_market_pdf_title, R.string.search_market_pdf); //$NON-NLS-1$ - } else if (AndroidUtilities.indexOf(FileMetadata.MS_FILETYPES, fileType) >= 0) { + } else if (AndroidUtilities.indexOf(TaskAttachment.MS_FILETYPES, fileType) >= 0) { searchMarket("com.dataviz.docstogo", R.string.search_market_ms_title, R.string.search_market_ms); //$NON-NLS-1$ } else { DialogUtilities.okDialog(activity, activity.getString(R.string.file_type_unhandled_title), @@ -311,7 +306,7 @@ public class FilesControlSet extends PopupControlSet { } @SuppressWarnings("nls") - private void downloadFile(final Metadata m) { + private void downloadFile(final TaskAttachment m) { final ProgressDialog pd = new ProgressDialog(activity); pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setMessage(activity.getString(R.string.file_download_progress)); @@ -320,9 +315,9 @@ public class FilesControlSet extends PopupControlSet { new Thread() { @Override public void run() { - String urlString = m.getValue(FileMetadata.URL); + String urlString = m.getValue(TaskAttachment.URL); urlString = urlString.replace(" ", "%20"); - String name = m.getValue(FileMetadata.NAME); + String name = m.getValue(TaskAttachment.NAME); StringBuilder filePathBuilder = new StringBuilder(); File directory = FileUtilities.getAttachmentsDirectory(activity); @@ -378,8 +373,8 @@ public class FilesControlSet extends PopupControlSet { fileOutput.flush(); fileOutput.close(); - m.setValue(FileMetadata.FILE_PATH, file.getAbsolutePath()); - metadataService.save(m); + m.setValue(TaskAttachment.FILE_PATH, file.getAbsolutePath()); + taskAttachmentDao.saveExisting(m); activity.runOnUiThread(new Runnable() { @Override public void run() { @@ -404,11 +399,11 @@ public class FilesControlSet extends PopupControlSet { pd.show(); } - private void setUpFileRow(Metadata m, View row, LinearLayout parent, LayoutParams lp) { + private void setUpFileRow(TaskAttachment m, View row, LinearLayout parent, LayoutParams lp) { TextView nameView = (TextView) row.findViewById(R.id.file_text); TextView typeView = (TextView) row.findViewById(R.id.file_type); String name = getNameString(m); - String type = getTypeString(m.getValue(FileMetadata.NAME)); + String type = getTypeString(m.getValue(TaskAttachment.NAME)); nameView.setText(name); if (TextUtils.isEmpty(type)) @@ -419,8 +414,8 @@ public class FilesControlSet extends PopupControlSet { parent.addView(row, lp); } - private String getNameString(Metadata metadata) { - String name = metadata.getValue(FileMetadata.NAME); + private String getNameString(TaskAttachment metadata) { + String name = metadata.getValue(TaskAttachment.NAME); int extension = name.lastIndexOf('.'); if (extension < 0) return name; diff --git a/astrid/src/com/todoroo/astrid/activity/EditPreferences.java b/astrid/src/com/todoroo/astrid/activity/EditPreferences.java index 8dbf9158a..8167a7f66 100644 --- a/astrid/src/com/todoroo/astrid/activity/EditPreferences.java +++ b/astrid/src/com/todoroo/astrid/activity/EditPreferences.java @@ -50,8 +50,8 @@ import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.files.FileExplore; -import com.todoroo.astrid.files.FileMetadata; import com.todoroo.astrid.gcal.CalendarStartupReceiver; import com.todoroo.astrid.gtasks.GtasksPreferences; import com.todoroo.astrid.helper.MetadataHelper; @@ -575,7 +575,7 @@ public class EditPreferences extends TodorooPreferenceActivity { // pp preferences else if (r.getString(R.string.p_files_dir).equals(preference.getKey())) { - String dir = Preferences.getStringValue(FileMetadata.FILES_DIRECTORY_PREF); + String dir = Preferences.getStringValue(TaskAttachment.FILES_DIRECTORY_PREF); if (TextUtils.isEmpty(dir)) { dir = r.getString(R.string.p_files_dir_desc_default); @@ -665,7 +665,7 @@ public class EditPreferences extends TodorooPreferenceActivity { } else if (requestCode == REQUEST_CODE_FILES_DIR && resultCode == RESULT_OK) { if (data != null) { String dir = data.getStringExtra(FileExplore.RESULT_DIR_SELECTED); - Preferences.setString(FileMetadata.FILES_DIRECTORY_PREF, dir); + Preferences.setString(TaskAttachment.FILES_DIRECTORY_PREF, dir); } return; } diff --git a/astrid/src/com/todoroo/astrid/activity/TaskEditFragment.java b/astrid/src/com/todoroo/astrid/activity/TaskEditFragment.java index 610301d66..4354742c4 100755 --- a/astrid/src/com/todoroo/astrid/activity/TaskEditFragment.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskEditFragment.java @@ -70,12 +70,12 @@ import com.todoroo.astrid.actfm.TaskCommentsFragment; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.actfm.sync.ActFmSyncService; import com.todoroo.astrid.api.AstridApiConstants; -import com.todoroo.astrid.data.Metadata; +import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.files.AACRecordingActivity; import com.todoroo.astrid.files.FileExplore; -import com.todoroo.astrid.files.FileMetadata; import com.todoroo.astrid.files.FileUtilities; import com.todoroo.astrid.files.FilesControlSet; import com.todoroo.astrid.gcal.GCalControlSet; @@ -212,6 +212,9 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { @Autowired private MetadataService metadataService; + @Autowired + private TaskAttachmentDao taskAttachmentDao; + @Autowired private AddOnService addOnService; @@ -870,7 +873,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { loadItem(intent); synchronized (controls) { - if (!FileMetadata.taskHasAttachments(model.getId())) { + if (!taskAttachmentDao.taskHasAttachments(model.getUuid())) { filesControlSet.getDisplayView().setVisibility(View.GONE); } for (TaskEditControlSet controlSet : controls) @@ -1140,7 +1143,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { String name = dst.getName(); String extension = AndroidUtilities.getFileExtension(name); - String type = FileMetadata.FILE_TYPE_OTHER; + String type = TaskAttachment.FILE_TYPE_OTHER; if (!TextUtils.isEmpty(extension)) { MimeTypeMap map = MimeTypeMap.getSingleton(); String guessedType = map.getMimeTypeFromExtension(extension); @@ -1163,16 +1166,15 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { fos.flush(); fos.close(); - createNewFileAttachment(path, nameRef.get(), FileMetadata.FILE_TYPE_IMAGE + "png"); + createNewFileAttachment(path, nameRef.get(), TaskAttachment.FILE_TYPE_IMAGE + "png"); } catch (Exception e) { Toast.makeText(getActivity(), R.string.file_err_copy, Toast.LENGTH_LONG).show(); } } private void createNewFileAttachment(String path, String fileName, String fileType) { - Metadata fileMetadata = FileMetadata.createNewFileMetadata(model.getId(), path, fileName, fileType); - metadataService.save(fileMetadata); - actFmSyncService.pushAttachmentInBackground(fileMetadata); + TaskAttachment attachment = TaskAttachment.createNewAttachment(model.getUuid(), path, fileName, fileType); + taskAttachmentDao.createNew(attachment); filesControlSet.refreshMetadata(); filesControlSet.getDisplayView().setVisibility(View.VISIBLE); } @@ -1291,7 +1293,7 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { } else if (requestCode == REQUEST_CODE_RECORD && resultCode == Activity.RESULT_OK) { String recordedAudioPath = data.getStringExtra(AACRecordingActivity.RESULT_OUTFILE); String recordedAudioName = data.getStringExtra(AACRecordingActivity.RESULT_FILENAME); - createNewFileAttachment(recordedAudioPath, recordedAudioName, FileMetadata.FILE_TYPE_AUDIO + "m4a"); //$NON-NLS-1$ + createNewFileAttachment(recordedAudioPath, recordedAudioName, TaskAttachment.FILE_TYPE_AUDIO + "m4a"); //$NON-NLS-1$ } else if (requestCode == REQUEST_CODE_ATTACH_FILE && resultCode == Activity.RESULT_OK) { attachFile(data.getStringExtra(FileExplore.RESULT_FILE_SELECTED)); } else if (requestCode == REQUEST_CODE_BEAST_MODE) { diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java index 95aba44a1..a2de4490a 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskListFragment.java @@ -87,8 +87,8 @@ import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.data.User; -import com.todoroo.astrid.files.FileMetadata; import com.todoroo.astrid.helper.SyncActionHelper; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader.ContextMenuItem; @@ -981,9 +981,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener, tagsJoinCriterion).toString() //$NON-NLS-1$ + Join.left(User.TABLE.as(USER_IMAGE_JOIN), Task.USER_ID.eq(Field.field(USER_IMAGE_JOIN + "." + User.UUID.name))).toString() - + Join.left(Metadata.TABLE.as(FILE_METADATA_JOIN), - Criterion.and(Field.field(FILE_METADATA_JOIN + "." + Metadata.KEY.name).eq(FileMetadata.METADATA_KEY), - Task.ID.eq(Field.field(FILE_METADATA_JOIN + "." + Metadata.TASK.name)))) + + Join.left(TaskAttachment.TABLE.as(FILE_METADATA_JOIN), Task.UUID.eq(Field.field(FILE_METADATA_JOIN) + "." + TaskAttachment.UUID.name)) + filter.getSqlQuery(); sqlQueryTemplate.set(SortHelper.adjustQueryForFlagsAndSort( diff --git a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java index fd9597740..8274c1593 100644 --- a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java @@ -77,6 +77,7 @@ import com.todoroo.astrid.core.LinkActionExposer; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.data.User; import com.todoroo.astrid.files.FilesAction; import com.todoroo.astrid.files.FilesControlSet; @@ -113,7 +114,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { @SuppressWarnings("nls") private static final StringProperty TAGS = new StringProperty(null, "group_concat(" + TaskListFragment.TAGS_METADATA_JOIN + "." + TaskToTagMetadata.TAG_NAME.name + ", ' | ')").as("tags"); @SuppressWarnings("nls") - private static final LongProperty FILE_ID_PROPERTY = Metadata.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId"); + private static final LongProperty FILE_ID_PROPERTY = TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId"); @SuppressWarnings("nls") private static final IntegerProperty HAS_NOTES_PROPERTY = new IntegerProperty(null, "length(" + Task.NOTES + ") > 0").as("hasNotes"); diff --git a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java index 99ccc28af..1499c570a 100644 --- a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java +++ b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java @@ -5,9 +5,11 @@ */ package com.todoroo.astrid.dao; +import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.sql.Query; import com.todoroo.astrid.actfm.sync.messages.NameMaps; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TaskAttachment; @@ -34,6 +36,17 @@ public class TaskAttachmentDao extends RemoteModelDao { return NameMaps.shouldRecordOutstandingColumnForTable(NameMaps.TABLE_ID_ATTACHMENTS, columnName); } + public boolean taskHasAttachments(String taskUuid) { + TodorooCursor files = query(Query.select(TaskAttachment.TASK_UUID).where( + Criterion.and(TaskAttachment.TASK_UUID.eq(taskUuid), + TaskAttachment.DELETED_AT.eq(0))).limit(1)); + try { + return files.getCount() > 0; + } finally { + files.close(); + } + } + // --- SQL clause generators /** diff --git a/astrid/src/com/todoroo/astrid/ui/QuickAddBar.java b/astrid/src/com/todoroo/astrid/ui/QuickAddBar.java index f1875db4a..8eb5af1a8 100644 --- a/astrid/src/com/todoroo/astrid/ui/QuickAddBar.java +++ b/astrid/src/com/todoroo/astrid/ui/QuickAddBar.java @@ -46,12 +46,12 @@ import com.todoroo.astrid.activity.TaskListActivity; import com.todoroo.astrid.activity.TaskListFragment; import com.todoroo.astrid.activity.TaskListFragment.OnTaskListItemClickedListener; import com.todoroo.astrid.core.PluginServices; +import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskDao; -import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.files.FileMetadata; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.files.FileUtilities; import com.todoroo.astrid.gcal.GCalControlSet; import com.todoroo.astrid.gcal.GCalHelper; @@ -90,6 +90,8 @@ public class QuickAddBar extends LinearLayout { @Autowired ExceptionService exceptionService; @Autowired MetadataService metadataService; @Autowired ActFmPreferenceService actFmPreferenceService; + @Autowired + private TaskAttachmentDao taskAttachmentDao; private VoiceRecognizer voiceRecognizer; @@ -361,8 +363,8 @@ public class QuickAddBar extends LinearLayout { voiceRecognizer.convert(path); currentVoiceFile = null; - Metadata fileMetadata = FileMetadata.createNewFileMetadata(task.getId(), path, nameRef.get(), FileMetadata.FILE_TYPE_AUDIO + "m4a"); - metadataService.save(fileMetadata); + TaskAttachment attachment = TaskAttachment.createNewAttachment(task.getUuid(), path, nameRef.get(), TaskAttachment.FILE_TYPE_AUDIO + "m4a"); + taskAttachmentDao.createNew(attachment); } fragment.onTaskCreated(task); From bce73a1d1d5fae6ce0e1af2ab26dbf3795efe973 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Sat, 9 Feb 2013 11:37:40 -0800 Subject: [PATCH 05/10] Deprecated and removed unecessary fields from FileMetadata --- .../todoroo/astrid/files/FileMetadata.java | 108 ++++++------------ 1 file changed, 33 insertions(+), 75 deletions(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java b/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java index a4fe924c2..b51bc6c1c 100644 --- a/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java +++ b/astrid/plugin-src/com/todoroo/astrid/files/FileMetadata.java @@ -5,79 +5,37 @@ */ package com.todoroo.astrid.files; +import com.todoroo.andlib.data.Property.LongProperty; +import com.todoroo.andlib.data.Property.StringProperty; +import com.todoroo.astrid.data.Metadata; -//public class FileMetadata { -// -// /** metadata key */ -// public static final String METADATA_KEY = "file"; //$NON-NLS-1$ -// -// /** default directory for files on external storage */ -// public static final String FILES_DIRECTORY_DEFAULT = "attachments"; //$NON-NLS-1$ -// -// /** preference key for some other download directory */ -// public static final String FILES_DIRECTORY_PREF = "custom_files_dir"; //$NON-NLS-1$ -// -// /** Constants for file types */ -// public static final String FILE_TYPE_AUDIO = "audio/"; //$NON-NLS-1$ -// public static final String FILE_TYPE_IMAGE = "image/"; //$NON-NLS-1$ -// public static final String FILE_TYPE_PDF = "application/pdf"; //$NON-NLS-1$ -// -// public static final String FILE_TYPE_DOC = "application/msword"; //$NON-NLS-1$ -// public static final String FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; //$NON-NLS-1$ -// public static final String FILE_TYPE_PPT = "application/vnd.ms-powerpoint"; //$NON-NLS-1$ -// public static final String FILE_TYPE_PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; //$NON-NLS-1$ -// public static final String FILE_TYPE_XLS = "application/vnd.ms-excel"; //$NON-NLS-1$ -// public static final String FILE_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; //$NON-NLS-1$ -// -// public static final String[] MS_FILETYPES = { -// FILE_TYPE_DOC, FILE_TYPE_DOCX, -// FILE_TYPE_XLS, FILE_TYPE_XLSX, -// FILE_TYPE_PPT, FILE_TYPE_PPTX, -// }; -// -// public static final String FILE_TYPE_OTHER = "application/octet-stream"; //$NON-NLS-1$ -// -// public static final StringProperty FILE_PATH = new StringProperty(Metadata.TABLE, -// Metadata.VALUE1.name); -// -// public static final StringProperty FILE_TYPE = new StringProperty(Metadata.TABLE, -// Metadata.VALUE2.name); -// -// public static final LongProperty DELETION_DATE = new LongProperty(Metadata.TABLE, -// Metadata.VALUE3.name); -// -// public static final LongProperty REMOTE_ID = new LongProperty(Metadata.TABLE, -// Metadata.VALUE4.name); -// -// public static final StringProperty URL = new StringProperty(Metadata.TABLE, -// Metadata.VALUE5.name); -// -// public static final StringProperty NAME = new StringProperty(Metadata.TABLE, -// Metadata.VALUE6.name); -// -// -// public static Metadata createNewFileMetadata(long taskId, String filePath, String fileName, String fileType) { -// Metadata metadata = new Metadata(); -// metadata.setValue(Metadata.KEY, METADATA_KEY); -// metadata.setValue(Metadata.TASK, taskId); -// metadata.setValue(NAME, fileName); -// metadata.setValue(FILE_PATH, filePath); -// metadata.setValue(FILE_TYPE, fileType); -// metadata.setValue(REMOTE_ID, 0L); -// metadata.setValue(DELETION_DATE, 0L); -// return metadata; -// } -// -// public static boolean taskHasAttachments(long taskId) { -// TodorooCursor files = PluginServices.getMetadataService() -// .query(Query.select(Metadata.TASK).where( -// Criterion.and(MetadataCriteria.byTaskAndwithKey(taskId, METADATA_KEY), -// DELETION_DATE.eq(0))).limit(1)); -// try { -// return files.getCount() > 0; -// } finally { -// files.close(); -// } -// } -// -//} +/** + * This class was deprecated with SyncV2. Use TaskAttachment instead. + * @author Sam + * + */ +@Deprecated +public class FileMetadata { + + /** metadata key */ + public static final String METADATA_KEY = "file"; //$NON-NLS-1$ + + public static final StringProperty FILE_PATH = new StringProperty(Metadata.TABLE, + Metadata.VALUE1.name); + + public static final StringProperty FILE_TYPE = new StringProperty(Metadata.TABLE, + Metadata.VALUE2.name); + + public static final LongProperty DELETION_DATE = new LongProperty(Metadata.TABLE, + Metadata.VALUE3.name); + + public static final LongProperty REMOTE_ID = new LongProperty(Metadata.TABLE, + Metadata.VALUE4.name); + + public static final StringProperty URL = new StringProperty(Metadata.TABLE, + Metadata.VALUE5.name); + + public static final StringProperty NAME = new StringProperty(Metadata.TABLE, + Metadata.VALUE6.name); + +} From 3e953d34df69ee6df56928a66d1d8e64845d5f01 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Sat, 9 Feb 2013 11:50:08 -0800 Subject: [PATCH 06/10] Wrote a migration from FileMetadata to TaskAttachment --- .../actfm/sync/AstridNewSyncMigrator.java | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/AstridNewSyncMigrator.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/AstridNewSyncMigrator.java index a1a72ebd2..bb6a2cf0e 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/AstridNewSyncMigrator.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/AstridNewSyncMigrator.java @@ -17,6 +17,7 @@ import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; import com.todoroo.astrid.dao.OutstandingEntryDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagOutstandingDao; +import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskOutstandingDao; import com.todoroo.astrid.dao.UpdateDao; @@ -29,10 +30,12 @@ import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagOutstanding; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.data.TaskOutstanding; import com.todoroo.astrid.data.Update; import com.todoroo.astrid.data.User; import com.todoroo.astrid.data.UserActivity; +import com.todoroo.astrid.files.FileMetadata; import com.todoroo.astrid.helper.UUIDHelper; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.TagDataService; @@ -48,6 +51,7 @@ public class AstridNewSyncMigrator { @Autowired private UpdateDao updateDao; @Autowired private UserActivityDao userActivityDao; @Autowired private UserDao userDao; + @Autowired private TaskAttachmentDao taskAttachmentDao; @Autowired private TaskOutstandingDao taskOutstandingDao; @Autowired private TagOutstandingDao tagOutstandingDao; @@ -131,9 +135,9 @@ public class AstridNewSyncMigrator { Log.e(LOG_TAG, "Error asserting UUIDs", e); } - // ---------- + // -------------- // Migrate unsynced task comments to UserActivity table - // ---------- + // -------------- try { TodorooCursor updates = updateDao.query(Query.select(Update.PROPERTIES).where( Criterion.and(Criterion.or(Update.UUID.eq(0), Update.UUID.isNull()), Criterion.or(Update.ACTION_CODE.eq(UserActivity.ACTION_TAG_COMMENT), @@ -177,15 +181,58 @@ public class AstridNewSyncMigrator { } - // ---------- + // -------------- // Drop any entries from the Users table that don't have a UUID - // ---------- + // -------------- try { userDao.deleteWhere(Criterion.or(User.UUID.isNull(), User.UUID.eq(""), User.UUID.eq("0"))); } catch (Exception e) { Log.e(LOG_TAG, "Error deleting incomplete user entries", e); } + // -------------- + // Migrate legacy FileMetadata models to new TaskAttachment models + // -------------- + try { + TodorooCursor fmCursor = metadataService.query(Query.select(Metadata.PROPERTIES) + .where(MetadataCriteria.withKey(FileMetadata.METADATA_KEY))); + try { + Metadata m = new Metadata(); + for (fmCursor.moveToFirst(); !fmCursor.isAfterLast(); fmCursor.moveToNext()) { + m.clear(); + m.readFromCursor(fmCursor); + + TaskAttachment attachment = new TaskAttachment(); + Task task = taskDao.fetch(m.getValue(Metadata.TASK), Task.UUID); + if (task == null || !RemoteModel.isValidUuid(task.getUuid())) + continue; + + Long oldRemoteId = m.getValue(FileMetadata.REMOTE_ID); + boolean synced = false; + if (oldRemoteId != null && oldRemoteId > 0) { + synced = true; + attachment.setValue(TaskAttachment.UUID, Long.toString(oldRemoteId)); + } + attachment.setValue(TaskAttachment.TASK_UUID, task.getUuid()); + attachment.setValue(TaskAttachment.NAME, m.getValue(FileMetadata.NAME)); + attachment.setValue(TaskAttachment.URL, m.getValue(FileMetadata.URL)); + attachment.setValue(TaskAttachment.FILE_PATH, m.getValue(FileMetadata.FILE_PATH)); + attachment.setValue(TaskAttachment.CONTENT_TYPE, m.getValue(FileMetadata.FILE_TYPE)); + attachment.setValue(TaskAttachment.DELETED_AT, m.getValue(FileMetadata.DELETION_DATE)); + + if (synced) + attachment.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true); + + taskAttachmentDao.createNew(attachment); + + } + } finally { + fmCursor.close(); + } + } catch (Exception e) { + Log.e(LOG_TAG, "Error migrating task attachment metadata", e); + } + // -------------- // Finally, ensure that all tag metadata entities have all important fields filled in // -------------- From dd96750138f24037482443becad81a5a6a0f9c89 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Sat, 9 Feb 2013 13:06:40 -0800 Subject: [PATCH 07/10] Record file attachment outstanding entries and report them using special ChangesHappened logic --- .../andlib/utility/AndroidUtilities.java | 27 ++++++++++++++ .../todoroo/astrid/data/TaskAttachment.java | 1 + .../actfm/sync/messages/ChangesHappened.java | 34 +++++++++++++++++ .../astrid/actfm/sync/messages/NameMaps.java | 2 + .../todoroo/astrid/files/FilesControlSet.java | 2 + .../todoroo/astrid/dao/TaskAttachmentDao.java | 37 +++++++++++++++++++ 6 files changed, 103 insertions(+) diff --git a/api/src/com/todoroo/andlib/utility/AndroidUtilities.java b/api/src/com/todoroo/andlib/utility/AndroidUtilities.java index 09b2bf05d..1f0a9fb53 100644 --- a/api/src/com/todoroo/andlib/utility/AndroidUtilities.java +++ b/api/src/com/todoroo/andlib/utility/AndroidUtilities.java @@ -10,6 +10,7 @@ import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -153,6 +154,32 @@ public class AndroidUtilities { return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length); } + + private static final int BUFFER_SIZE = 4096; + public static String encodeBase64File(File file) { + try { + FileInputStream in = new FileInputStream(file); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte[] buffer = new byte[BUFFER_SIZE]; + int len = 0; + while ((len = in.read(buffer)) > 0) { + baos.write(buffer, 0, len); + } + + byte[] bytes = baos.toByteArray(); + return Base64.encodeToString(bytes, Base64.DEFAULT); + } finally { + in.close(); + } + } catch (FileNotFoundException e) { + return null; + } catch (IOException e) { + return null; + } + } + /** * Start the given intent, handling security exceptions if they arise * diff --git a/api/src/com/todoroo/astrid/data/TaskAttachment.java b/api/src/com/todoroo/astrid/data/TaskAttachment.java index 1941eb565..784d5f247 100644 --- a/api/src/com/todoroo/astrid/data/TaskAttachment.java +++ b/api/src/com/todoroo/astrid/data/TaskAttachment.java @@ -144,6 +144,7 @@ public final class TaskAttachment extends RemoteModel { TaskAttachment attachment = new TaskAttachment(); attachment.setValue(TaskAttachment.TASK_UUID, taskUuid); attachment.setValue(NAME, fileName); + attachment.setValue(USER_UUID, Task.USER_ID_SELF); attachment.setValue(FILE_PATH, filePath); attachment.setValue(CONTENT_TYPE, fileType); attachment.setValue(DELETED_AT, 0L); diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java index 4c8662146..e3d6e4199 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java @@ -1,5 +1,6 @@ package com.todoroo.astrid.actfm.sync.messages; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -7,6 +8,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import android.text.TextUtils; import android.util.Log; import com.todoroo.andlib.data.Property; @@ -14,6 +16,7 @@ import com.todoroo.andlib.data.Property.PropertyVisitor; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.sql.Order; import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.actfm.sync.ActFmSyncThread.ModelType; @@ -110,6 +113,15 @@ public class ChangesHappened localProperty = NameMaps.localColumnNameToProperty(table, localColumn); if (localProperty == null) @@ -155,6 +167,28 @@ public class ChangesHappened { private String getAsString(OE data) { diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java index ccd635afc..db3c054ee 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java @@ -255,6 +255,8 @@ public class NameMaps { private static final Map> TASK_ATTACHMENT_PROPERTIES_SERVER_TO_LOCAL; private static final Set TASK_ATTACHMENT_PROPERTIES_EXCLUDED; + public static final String ATTACHMENT_ADDED_COLUMN = "file"; + private static void putTaskAttachmentPropertyToServerName(Property property, String serverName, boolean writeable) { putPropertyToServerName(property, serverName, TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER, TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES, TASK_ATTACHMENT_COLUMNS_LOCAL_TO_SERVER, TASK_ATTACHMENT_PROPERTIES_EXCLUDED, writeable); diff --git a/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java b/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java index 578e211ca..b63689cd1 100644 --- a/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/files/FilesControlSet.java @@ -46,6 +46,7 @@ import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.data.RemoteModel; +import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.ui.PopupControlSet; @@ -256,6 +257,7 @@ public class FilesControlSet extends PopupControlSet { useType = guessedType; if (useType != guessedType) { m.setValue(TaskAttachment.CONTENT_TYPE, useType); + m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true); taskAttachmentDao.saveExisting(m); } } diff --git a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java index 1499c570a..684f1dbc3 100644 --- a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java +++ b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java @@ -5,14 +5,23 @@ */ package com.todoroo.astrid.dao; +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.ContentValues; +import android.text.TextUtils; + import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.actfm.sync.messages.NameMaps; +import com.todoroo.astrid.data.OutstandingEntry; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TaskAttachment; +import com.todoroo.astrid.data.TaskAttachmentOutstanding; /** * Data Access layer for {@link TagData}-related operations. @@ -36,6 +45,34 @@ public class TaskAttachmentDao extends RemoteModelDao { return NameMaps.shouldRecordOutstandingColumnForTable(NameMaps.TABLE_ID_ATTACHMENTS, columnName); } + @Override + protected int createOutstandingEntries(long modelId, ContentValues modelSetValues) { + // new attachment case -- only set by us when creating new attachments; when setting during sync outstanding entries suppressed + if (modelSetValues.containsKey(TaskAttachment.CONTENT_TYPE.name)) { + TaskAttachmentOutstanding m = new TaskAttachmentOutstanding(); + String path = modelSetValues.getAsString(TaskAttachment.FILE_PATH.name); + if (TextUtils.isEmpty(path)) + return -1; + try { + JSONObject newFileHash = new JSONObject(); + newFileHash.put("name", modelSetValues.getAsString(TaskAttachment.NAME.name)); //$NON-NLS-1$ + newFileHash.put("type", modelSetValues.getAsString(TaskAttachment.CONTENT_TYPE.name)); //$NON-NLS-1$ + newFileHash.put("path", modelSetValues.getAsString(path)); //$NON-NLS-1$ + + m.setValue(OutstandingEntry.ENTITY_ID_PROPERTY, modelId); + m.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, NameMaps.ATTACHMENT_ADDED_COLUMN); + m.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, newFileHash.toString()); + m.setValue(OutstandingEntry.CREATED_AT_PROPERTY, DateUtilities.now()); + } catch (JSONException e) { + return -1; + } + } + int result = super.createOutstandingEntries(modelId, modelSetValues); + if (result < 0) // Error + return result; + return 1 + result; + } + public boolean taskHasAttachments(String taskUuid) { TodorooCursor files = query(Query.select(TaskAttachment.TASK_UUID).where( Criterion.and(TaskAttachment.TASK_UUID.eq(taskUuid), From 4f0fa9825324ca0321d4190068921949612a9153 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 11 Feb 2013 10:40:31 -0800 Subject: [PATCH 08/10] Fixed duplicate column name in TaskAttachment --- api/src/com/todoroo/astrid/data/TaskAttachment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/com/todoroo/astrid/data/TaskAttachment.java b/api/src/com/todoroo/astrid/data/TaskAttachment.java index 784d5f247..c3ea0fb9c 100644 --- a/api/src/com/todoroo/astrid/data/TaskAttachment.java +++ b/api/src/com/todoroo/astrid/data/TaskAttachment.java @@ -84,7 +84,7 @@ public final class TaskAttachment extends RemoteModel { /** Attachment deletion date */ public static final LongProperty DELETED_AT = new LongProperty( - TABLE, "created_at", Property.PROP_FLAG_DATE); + TABLE, "deleted_at", Property.PROP_FLAG_DATE); /** List of all properties for this model */ public static final Property[] PROPERTIES = generateProperties(TaskAttachment.class); From 49507146c58293fa7cd3dfd9565e3876d029553f Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 11 Feb 2013 11:23:51 -0800 Subject: [PATCH 09/10] Fixed several bugs/missing pieces that were preventing task attachments from syncing --- api/src/com/todoroo/astrid/data/TaskAttachment.java | 5 +++++ .../com/todoroo/astrid/actfm/sync/ActFmSyncThread.java | 10 +++++++--- .../astrid/actfm/sync/messages/ChangesHappened.java | 5 +++++ .../todoroo/astrid/actfm/sync/messages/NameMaps.java | 2 +- .../src/com/todoroo/astrid/dao/TaskAttachmentDao.java | 3 ++- .../astrid/service/AstridDependencyInjector.java | 4 ++++ .../src/com/todoroo/astrid/service/StartupService.java | 5 ++++- 7 files changed, 28 insertions(+), 6 deletions(-) diff --git a/api/src/com/todoroo/astrid/data/TaskAttachment.java b/api/src/com/todoroo/astrid/data/TaskAttachment.java index c3ea0fb9c..26f7b0bdb 100644 --- a/api/src/com/todoroo/astrid/data/TaskAttachment.java +++ b/api/src/com/todoroo/astrid/data/TaskAttachment.java @@ -16,6 +16,7 @@ import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.data.Table; import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.api.AstridApiConstants; /** @@ -32,6 +33,9 @@ public final class TaskAttachment extends RemoteModel { /** table for this model */ public static final Table TABLE = new Table("task_attachments", TaskAttachment.class); + /** model class for entries in the outstanding table */ + public static final Class> OUTSTANDING_MODEL = TaskAttachmentOutstanding.class; + /** content uri for this model */ public static final Uri CONTENT_URI = Uri.parse("content://" + AstridApiConstants.API_PACKAGE + "/" + TABLE.name); @@ -147,6 +151,7 @@ public final class TaskAttachment extends RemoteModel { attachment.setValue(USER_UUID, Task.USER_ID_SELF); attachment.setValue(FILE_PATH, filePath); attachment.setValue(CONTENT_TYPE, fileType); + attachment.setValue(CREATED_AT, DateUtilities.now()); attachment.setValue(DELETED_AT, 0L); return attachment; } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncThread.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncThread.java index 7c4526bf2..413d43c45 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncThread.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncThread.java @@ -32,6 +32,7 @@ import com.todoroo.astrid.dao.OutstandingEntryDao; import com.todoroo.astrid.dao.RemoteModelDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagOutstandingDao; +import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskOutstandingDao; import com.todoroo.astrid.dao.UserActivityDao; @@ -41,6 +42,7 @@ import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagOutstanding; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.data.TaskOutstanding; import com.todoroo.astrid.data.User; import com.todoroo.astrid.data.UserActivity; @@ -87,7 +89,8 @@ public class ActFmSyncThread { public static enum ModelType { TYPE_TASK, TYPE_TAG, - TYPE_ACTIVITY + TYPE_ACTIVITY, + TYPE_ATTACHMENT } private static volatile ActFmSyncThread instance; @@ -96,14 +99,14 @@ public class ActFmSyncThread { if (instance == null) { synchronized(ActFmSyncThread.class) { if (instance == null) { - initializeSyncComponents(PluginServices.getTaskDao(), PluginServices.getTagDataDao(), PluginServices.getUserActivityDao()); + initializeSyncComponents(PluginServices.getTaskDao(), PluginServices.getTagDataDao(), PluginServices.getUserActivityDao(), PluginServices.getTaskAttachmentDao()); } } } return instance; } - public static ActFmSyncThread initializeSyncComponents(TaskDao taskDao, TagDataDao tagDataDao, UserActivityDao userActivityDao) { + public static ActFmSyncThread initializeSyncComponents(TaskDao taskDao, TagDataDao tagDataDao, UserActivityDao userActivityDao, TaskAttachmentDao taskAttachmentDao) { if (instance == null) { synchronized(ActFmSyncThread.class) { if (instance == null) { @@ -115,6 +118,7 @@ public class ActFmSyncThread { taskDao.addListener(new SyncDatabaseListener(instance, ModelType.TYPE_TASK)); tagDataDao.addListener(new SyncDatabaseListener(instance, ModelType.TYPE_TAG)); userActivityDao.addListener(new SyncDatabaseListener(instance, ModelType.TYPE_ACTIVITY)); + taskAttachmentDao.addListener(new SyncDatabaseListener(instance, ModelType.TYPE_ATTACHMENT)); instance.startSyncThread(); } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java index e3d6e4199..55daf8c74 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java @@ -29,6 +29,8 @@ import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagOutstanding; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskAttachment; +import com.todoroo.astrid.data.TaskAttachmentOutstanding; import com.todoroo.astrid.data.TaskOutstanding; import com.todoroo.astrid.data.UserActivity; import com.todoroo.astrid.data.UserActivityOutstanding; @@ -55,6 +57,9 @@ public class ChangesHappened(id, UserActivity.class, PluginServices.getUserActivityDao(), PluginServices.getUserActivityOutstandingDao()); + case TYPE_ATTACHMENT: + return new ChangesHappened(id, TaskAttachment.class, + PluginServices.getTaskAttachmentDao(), PluginServices.getTaskAttachmentOutstandingDao()); default: return null; } diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java index db3c054ee..c629e69ac 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/NameMaps.java @@ -269,7 +269,7 @@ public class NameMaps { TASK_ATTACHMENT_PROPERTIES_EXCLUDED = new HashSet(); putTaskAttachmentPropertyToServerName(TaskAttachment.UUID, "uuid", false); - putTaskAttachmentPropertyToServerName(TaskAttachment.USER_UUID, "user_id", true); + putTaskAttachmentPropertyToServerName(TaskAttachment.USER_UUID, "user_id", false); putTaskAttachmentPropertyToServerName(TaskAttachment.TASK_UUID, "task_id", true); putTaskAttachmentPropertyToServerName(TaskAttachment.NAME, "name", false); putTaskAttachmentPropertyToServerName(TaskAttachment.URL, "url", false); diff --git a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java index 684f1dbc3..e5db9c216 100644 --- a/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java +++ b/astrid/src/com/todoroo/astrid/dao/TaskAttachmentDao.java @@ -57,12 +57,13 @@ public class TaskAttachmentDao extends RemoteModelDao { JSONObject newFileHash = new JSONObject(); newFileHash.put("name", modelSetValues.getAsString(TaskAttachment.NAME.name)); //$NON-NLS-1$ newFileHash.put("type", modelSetValues.getAsString(TaskAttachment.CONTENT_TYPE.name)); //$NON-NLS-1$ - newFileHash.put("path", modelSetValues.getAsString(path)); //$NON-NLS-1$ + newFileHash.put("path", path); //$NON-NLS-1$ m.setValue(OutstandingEntry.ENTITY_ID_PROPERTY, modelId); m.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, NameMaps.ATTACHMENT_ADDED_COLUMN); m.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, newFileHash.toString()); m.setValue(OutstandingEntry.CREATED_AT_PROPERTY, DateUtilities.now()); + database.insert(outstandingTable.name, null, m.getSetValues()); } catch (JSONException e) { return -1; } diff --git a/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java b/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java index 90143c2ab..5c16aff88 100644 --- a/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java +++ b/astrid/src/com/todoroo/astrid/service/AstridDependencyInjector.java @@ -21,6 +21,8 @@ import com.todoroo.astrid.dao.StoreObjectDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TagMetadataDao; import com.todoroo.astrid.dao.TagOutstandingDao; +import com.todoroo.astrid.dao.TaskAttachmentDao; +import com.todoroo.astrid.dao.TaskAttachmentOutstandingDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskOutstandingDao; import com.todoroo.astrid.dao.UpdateDao; @@ -83,6 +85,8 @@ public class AstridDependencyInjector extends AbstractDependencyInjector { injectables.put("tagOutstandingDao", TagOutstandingDao.class); injectables.put("userActivityOutstandingDao", UserActivityOutstandingDao.class); injectables.put("historyDao", HistoryDao.class); + injectables.put("taskAttachmentDao", TaskAttachmentDao.class); + injectables.put("taskAttachmentOutstandingDao", TaskAttachmentOutstandingDao.class); // com.todoroo.astrid.service injectables.put("taskService", TaskService.class); diff --git a/astrid/src/com/todoroo/astrid/service/StartupService.java b/astrid/src/com/todoroo/astrid/service/StartupService.java index 877ed1406..428f71f49 100644 --- a/astrid/src/com/todoroo/astrid/service/StartupService.java +++ b/astrid/src/com/todoroo/astrid/service/StartupService.java @@ -52,6 +52,7 @@ import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; import com.todoroo.astrid.dao.TagDataDao; +import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.UserActivityDao; import com.todoroo.astrid.data.Metadata; @@ -106,6 +107,8 @@ public class StartupService { @Autowired UserActivityDao userActivityDao; + @Autowired TaskAttachmentDao taskAttachmentDao; + @Autowired MetadataService metadataService; @Autowired Database database; @@ -221,7 +224,7 @@ public class StartupService { abTestInvoker.reportAcquisition(); initializeDatabaseListeners(); - ActFmSyncThread.initializeSyncComponents(taskDao, tagDataDao, userActivityDao); + ActFmSyncThread.initializeSyncComponents(taskDao, tagDataDao, userActivityDao, taskAttachmentDao); // perform startup activities in a background thread new Thread(new Runnable() { From b995f6dbbedabf84d8365d9dd26db82d70c439f0 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 11 Feb 2013 14:03:09 -0800 Subject: [PATCH 10/10] Fixed file uploading (use JSON instead of string), make sure that EditNoteActivity has Task.PUSHED_AT --- .../com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java | 2 +- .../plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java index 55daf8c74..7471d726a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/messages/ChangesHappened.java @@ -125,7 +125,7 @@ public class ChangesHappened localProperty = NameMaps.localColumnNameToProperty(table, localColumn); diff --git a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java index 5249e946e..ab70706e8 100644 --- a/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/notes/EditNoteActivity.java @@ -148,7 +148,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene public void loadViewForTaskID(long t){ try { - task = PluginServices.getTaskService().fetchById(t, Task.NOTES, Task.ID, Task.UUID, Task.TITLE, Task.HISTORY_FETCH_DATE); + task = PluginServices.getTaskService().fetchById(t, Task.NOTES, Task.ID, Task.UUID, Task.TITLE, Task.HISTORY_FETCH_DATE, Task.PUSHED_AT); } catch (SQLiteException e) { StartupService.handleSQLiteError(ContextManager.getContext(), e); }