diff --git a/astrid/.classpath b/astrid/.classpath index a02fb551c..d479a46be 100644 --- a/astrid/.classpath +++ b/astrid/.classpath @@ -4,7 +4,7 @@ - + diff --git a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java index 8adcd2deb..dd74e2256 100644 --- a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java +++ b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java @@ -173,4 +173,18 @@ public class AndroidUtilities { return result; } + /** + * Returns true if a and b or null or a.equals(b) + * @param a + * @param b + * @return + */ + public static boolean equals(Object a, Object b) { + if(a == null && b == null) + return true; + if(a == null) + return false; + return a.equals(b); + } + } diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/FilterExposer.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/FilterExposer.java index 3cc33097e..41f7c81b3 100644 --- a/astrid/plugin-src/com/todoroo/astrid/rmilk/FilterExposer.java +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/FilterExposer.java @@ -4,10 +4,12 @@ package com.todoroo.astrid.rmilk; import android.content.BroadcastReceiver; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; -import com.todoroo.astrid.R; +import com.timsu.astrid.R; +import com.todoroo.andlib.sql.QueryTemplate; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.FilterCategory; @@ -15,6 +17,7 @@ import com.todoroo.astrid.api.FilterListHeader; import com.todoroo.astrid.api.FilterListItem; import com.todoroo.astrid.rmilk.Utilities.ListContainer; import com.todoroo.astrid.rmilk.data.MilkDataService; +import com.todoroo.astrid.rmilk.data.MilkTask; /** * Exposes filters based on RTM lists @@ -30,9 +33,10 @@ public class FilterExposer extends BroadcastReceiver { String listTitle = context.getString(R.string.rmilk_FEx_list_item). replace("$N", list.name).replace("$C", Integer.toString(list.count)); String title = context.getString(R.string.rmilk_FEx_list_title, list.name); - Filter filter = new Filter(listTitle, title, - "TODO", - "TODO"); + ContentValues values = new ContentValues(); // TODO + Filter filter = new Filter(Utilities.IDENTIFIER, listTitle, title, + new QueryTemplate().join(MilkDataService.MILK_JOIN).where(MilkTask.LIST_ID.eq(list.id)), + values); return filter; } @@ -54,8 +58,9 @@ public class FilterExposer extends BroadcastReceiver { for(int i = 0; i < lists.length; i++) listFilters[i] = filterFromList(context, lists[i]); - FilterListHeader rtmHeader = new FilterListHeader(context.getString(R.string.rmilk_FEx_header)); - FilterCategory rtmLists = new FilterCategory( + FilterListHeader rtmHeader = new FilterListHeader(Utilities.IDENTIFIER, + context.getString(R.string.rmilk_FEx_header)); + FilterCategory rtmLists = new FilterCategory(Utilities.IDENTIFIER, context.getString(R.string.rmilk_FEx_list), listFilters); // transmit filter list @@ -63,7 +68,7 @@ public class FilterExposer extends BroadcastReceiver { list[0] = rtmHeader; list[1] = rtmLists; Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS); - broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ITEMS, list); + broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list); context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); } diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkPreferences.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkPreferences.java index c47ad29db..e21bd3e8e 100644 --- a/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkPreferences.java +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkPreferences.java @@ -61,7 +61,7 @@ public class MilkPreferences extends PreferenceActivity { getString(R.string.rmilk_MPr_sync_key)); syncAction.setOnPreferenceClickListener(new OnPreferenceClickListener() { public boolean onPreferenceClick(Preference p) { - new RTMSyncProvider().synchronize(MilkPreferences.this); + new RTMSyncProvider().synchronize(); return true; } }); diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/Utilities.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/Utilities.java index b5c722ce0..ce90bcf2a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/rmilk/Utilities.java +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/Utilities.java @@ -22,6 +22,11 @@ import com.todoroo.astrid.rmilk.data.MilkList; @SuppressWarnings("nls") public class Utilities { + // --- constants + + /** add-on identifier */ + public static final String IDENTIFIER = "rmilk"; + // --- helper classes /** @@ -50,19 +55,6 @@ public class Utilities { public int count; } - // --- Metadata keys - // NOTE: no sql escaping is provided for keys - - public static final String KEY_LIST_ID = "rmilk_listId"; - - public static final String KEY_TASK_SERIES_ID = "rmilk_taskSeriesId"; - - public static final String KEY_TASK_ID = "rmilk_taskId"; - - public static final String KEY_REPEAT = "rmilk_repeat"; - - public static final String KEY_UPDATED = "rmilk_updated"; - // --- Preference Keys private static final String PREF_TOKEN = "rmilk_token"; diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/api/data/RtmList.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/api/data/RtmList.java index 09593d306..b81db6628 100644 --- a/astrid/plugin-src/com/todoroo/astrid/rmilk/api/data/RtmList.java +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/api/data/RtmList.java @@ -26,18 +26,21 @@ public class RtmList extends RtmData { private final String id; private final boolean smart; + private final boolean archived; private final String name; public RtmList(String id, String name, boolean smart) { this.id = id; this.name = name; this.smart = smart; + this.archived = false; } public RtmList(Element elt) { id = elt.getAttribute("id"); name = elt.getAttribute("name"); smart = elt.getAttribute("smart") == "1"; + archived = elt.getAttribute("archived") == "1"; } public String getId() { @@ -51,4 +54,8 @@ public class RtmList extends RtmData { public boolean isSmart() { return smart; } + + public boolean isArchived() { + return archived; +} } diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/data/MilkDataService.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/data/MilkDataService.java index 9369f6950..a48df830d 100644 --- a/astrid/plugin-src/com/todoroo/astrid/rmilk/data/MilkDataService.java +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/data/MilkDataService.java @@ -3,164 +3,87 @@ */ package com.todoroo.astrid.rmilk.data; -import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Random; import android.content.Context; -import android.database.sqlite.SQLiteQueryBuilder; import com.todoroo.andlib.data.GenericDao; import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.TodorooCursor; -import com.todoroo.andlib.data.Property.IntegerProperty; +import com.todoroo.andlib.data.Property.CountProperty; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; -import com.todoroo.astrid.dao.Database; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.sql.Join; +import com.todoroo.andlib.sql.Order; +import com.todoroo.andlib.sql.Query; import com.todoroo.astrid.dao.TaskDao; -import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Task; -import com.todoroo.astrid.rmilk.Utilities; import com.todoroo.astrid.rmilk.Utilities.ListContainer; import com.todoroo.astrid.rmilk.api.data.RtmList; import com.todoroo.astrid.rmilk.api.data.RtmLists; -import com.todoroo.astrid.service.MetadataService; -@SuppressWarnings("nls") public class MilkDataService { + // --- constants + + /** for joining milk task table with task table */ + public static final Join MILK_JOIN = Join.left(MilkTask.TABLE, + Task.ID.eq(MilkTask.TASK)); + + // --- instance variables + protected final Context context; private final MilkDatabase milkDatabase = new MilkDatabase(); - @Autowired - private MetadataService metadataService; - - private final GenericDao listDao; + private final GenericDao milkListDao; + private final GenericDao milkTaskDao; @Autowired private TaskDao taskDao; - @Autowired - private Database database; - static final Random random = new Random(); public MilkDataService(Context context) { this.context = context; DependencyInjectionService.getInstance().inject(this); - listDao = new GenericDao(MilkList.class, milkDatabase); + milkListDao = new GenericDao(MilkList.class, milkDatabase); + milkTaskDao = new GenericDao(MilkTask.class, milkDatabase); + milkDatabase.openForReading(); } - // --- RTM properties - - /** RTM List id */ - public static final StringJoinProperty LIST_ID = - new StringJoinProperty(Utilities.KEY_LIST_ID); - - /** RTM Task Series id */ - public static final StringJoinProperty TASK_SERIES_ID = - new StringJoinProperty(Utilities.KEY_TASK_SERIES_ID); - - /** RTM Task id */ - public static final StringJoinProperty TASK_ID = - new StringJoinProperty(Utilities.KEY_TASK_ID); - - /** 1 if task repeats in RTM, 0 otherwise */ - public static final IntegerJoinProperty REPEAT = - new IntegerJoinProperty(Utilities.KEY_REPEAT); - - /** 1 if task was updated since last sync, 0 otherwise */ - public static final IntegerJoinProperty UPDATED = - new IntegerJoinProperty(Utilities.KEY_UPDATED); - - // --- non-RTM properties we synchronize - - public static final StringJoinProperty TAGS = - new StringJoinProperty(com.todoroo.astrid.tags.TagService.KEY); - // --- task and metadata methods - /** Properties to fetch when user wants to view / edit tasks */ - public static final Property[] RTM_PROPERTIES = new Property[] { - Task.ID, - LIST_ID, - TASK_SERIES_ID, - TASK_ID, - REPEAT - }; - - /** - * Read a single task by task id - * @param taskId - * @return item, or null if it doesn't exist - */ - public Task readTask(long taskId) { - SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); - builder.setTables(createJoinClause(RTM_PROPERTIES)); - TodorooCursor cursor = - taskDao.query(database, RTM_PROPERTIES, builder, - Task.ID.qualifiedName()+ " = " + taskId, - null, null); - try { - if (cursor.getCount() == 0) - return null; - cursor.moveToFirst(); - Task task = new Task(cursor, RTM_PROPERTIES); - return task; - } finally { - cursor.close(); - } - } - - /** Helper method for building a join clause for task/metadata joins */ - public static String createJoinClause(Property[] properties) { - StringBuilder stringBuilder = new StringBuilder(Database.TASK_TABLE); - int joinTableCount = 0; - for(Property property : properties) { - if(property instanceof JoinProperty) { - JoinProperty jp = (JoinProperty)property; - stringBuilder.append(" LEFT JOIN (").append(jp.joinTable()). - append(") m").append(++joinTableCount). - append(" ON ").append(Task.ID_PROPERTY).append(" = m"). - append(joinTableCount).append('.').append(Metadata.TASK.name). - append(' '); - } - } - return stringBuilder.toString(); - } - /** * Clears RTM metadata information. Used when user logs out of RTM */ public void clearMetadata() { - metadataService.deleteWhere(String.format("%s = '%s' OR %s = '%s' " + - "OR %s = '%s OR %s = '%s'", - Metadata.KEY, LIST_ID, - Metadata.KEY, TASK_SERIES_ID, - Metadata.KEY, TASK_ID, - Metadata.KEY, REPEAT)); + milkTaskDao.deleteWhere(Criterion.all); } + /** + * Gets tasks that were created since last sync + * @param properties + * @return + */ public TodorooCursor getLocallyCreated(Property[] properties) { - SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); - builder.setTables(createJoinClause(properties)); - TodorooCursor cursor = - taskDao.query(database, properties, builder, - TASK_ID + " ISNULL", - null, null); - return cursor; + return + taskDao.query(Query.select(properties).join(MILK_JOIN).where( + Criterion.or(MilkTask.UPDATED.eq(0), MilkTask.TASK.isNull()))); } + /** + * Gets tasks that were modified since last sync + * @param properties + * @return + */ public TodorooCursor getLocallyUpdated(Property[] properties) { - SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); - builder.setTables(createJoinClause(properties)); - TodorooCursor cursor = - taskDao.query(database, properties, builder, - "NOT " + TASK_ID + " ISNULL", // TODO wrong! - null, null); - return cursor; + return + taskDao.query(Query.select(properties).join(MILK_JOIN). + where(Criterion.and(MilkTask.UPDATED.neq(0), + MilkTask.UPDATED.lt(Task.MODIFICATION_DATE)))); } // --- list methods @@ -171,17 +94,15 @@ public class MilkDataService { * @return null if no list by this id exists, otherwise list name */ public String getList(String listId) { - pluginDatabase.open(context); - TodorooCursor cursor = listDao.fetch(pluginDatabase, - List.PROPERTIES, ListSql.withId(listId), null, "1"); //$NON-NLS-1$ + TodorooCursor cursor = milkListDao.query(Query.select( + MilkList.NAME).where(MilkList.ID.eq(listId))); try { if(cursor.getCount() == 0) return null; cursor.moveToFirst(); - return cursor.get(List.NAME); + return cursor.get(MilkList.NAME); } finally { cursor.close(); - pluginDatabase.close(); } } @@ -190,49 +111,26 @@ public class MilkDataService { * @return */ public ListContainer[] getListsWithCounts() { - // read all list titles - pluginDatabase.open(context); - TodorooCursor listCursor = listDao.fetch(pluginDatabase, - List.PROPERTIES, null); - HashMap listIdToContainerMap; - try { - int count = listCursor.getCount(); - if(count == 0) - return new ListContainer[0]; - - listIdToContainerMap = - new HashMap(count); - List list = new List(); - for(int i = 0; i < count; i++) { - listCursor.moveToNext(); - list.readFromCursor(listCursor, List.PROPERTIES); - ListContainer container = new ListContainer(list); - listIdToContainerMap.put(container.id, container); - } - } finally { - listCursor.close(); - } + CountProperty COUNT = new CountProperty(); // read all list counts - IntegerProperty countProperty = Property.countProperty(); - TodorooCursor metadataCursor = metadataService.fetchWithCount( - MetadataSql.withKey(Utilities.KEY_LIST_ID), Metadata.VALUE + " ASC", false); //$NON-NLS-1$ - ListContainer[] containers = new ListContainer[metadataCursor.getCount()]; + TodorooCursor cursor = milkTaskDao.query(Query.select(MilkList.ID, MilkList.NAME, COUNT). + join(Join.inner(MilkList.TABLE, MilkTask.LIST_ID.eq(MilkList.ID))). + orderBy(Order.asc(MilkList.POSITION), Order.asc(MilkList.ID)). + groupBy(MilkTask.LIST_ID)); + ListContainer[] containers = new ListContainer[cursor.getCount()]; try { for(int i = 0; i < containers.length; i++) { - metadataCursor.moveToNext(); - String id = metadataCursor.get(Metadata.VALUE); - ListContainer container = listIdToContainerMap.get(id); - if(container == null) { - container = new ListContainer(id, "[unknown]"); //$NON-NLS-1$ - } - container.count = metadataCursor.get(countProperty); - containers[i] = container; + cursor.moveToNext(); + long id = cursor.get(MilkList.ID); + String name = cursor.get(MilkList.NAME); + int count = cursor.get(COUNT); + containers[i] = new ListContainer(id, name); + containers[i].count = count; } return containers; } finally { - metadataCursor.close(); - pluginDatabase.close(); + cursor.close(); } } @@ -240,10 +138,10 @@ public class MilkDataService { * Get RTM lists as strings * @return */ - public ListContainer[] getLists() { + /*public ListContainer[] getLists() { // read all list titles - pluginDatabase.open(context); - TodorooCursor cursor = listDao.fetch(pluginDatabase, + milkDatabase.open(context); + TodorooCursor cursor = milkListDao.fetch(milkDatabase, List.PROPERTIES, null, List.ID + " ASC"); //$NON-NLS-1$ ListContainer[] containers = new ListContainer[cursor.getCount()]; try { @@ -257,25 +155,22 @@ public class MilkDataService { return containers; } finally { cursor.close(); - pluginDatabase.close(); + milkDatabase.close(); } - } + }*/ /** * Clears current cache of RTM lists and re-populates * @param lists */ public void setLists(RtmLists lists) { - pluginDatabase.open(context); - try { - List model = new List(); - for(Map.Entry list : lists.getLists().entrySet()) { - model.setValue(List.ID, list.getValue().getId()); - model.setValue(List.NAME, list.getValue().getName()); - listDao.save(pluginDatabase, model); - } - } finally { - pluginDatabase.close(); + milkListDao.deleteWhere(Criterion.all); + MilkList model = new MilkList(); + for(Map.Entry list : lists.getLists().entrySet()) { + model.setValue(MilkList.ID, Long.parseLong(list.getValue().getId())); + model.setValue(MilkList.NAME, list.getValue().getName()); + model.setValue(MilkList.ARCHIVED, list.getValue().isArchived()? 1 : 0); + milkListDao.createNew(model); } } diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/data/MilkTask.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/data/MilkTask.java new file mode 100644 index 000000000..c79726ac6 --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/data/MilkTask.java @@ -0,0 +1,104 @@ +/** + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.rmilk.data; + + +import android.content.ContentValues; + +import com.todoroo.andlib.data.AbstractModel; +import com.todoroo.andlib.data.Property; +import com.todoroo.andlib.data.Table; +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.data.Property.IntegerProperty; +import com.todoroo.andlib.data.Property.LongProperty; +import com.todoroo.astrid.model.Task; + +/** + * Data Model which represents a list in RTM + * + * @author Tim Su + * + */ +@SuppressWarnings("nls") +public class MilkTask extends AbstractModel { + + // --- table + + public static final Table TABLE = new Table("tasks", MilkTask.class); + + // --- properties + + /** Task Id */ + public static final LongProperty TASK = new LongProperty( + TABLE, "task"); + + /** {@link MilkList} id */ + public static final LongProperty LIST_ID = new LongProperty( + TABLE, "listId"); + + /** RTM Task Id */ + public static final LongProperty TASK_SERIES_ID = new LongProperty( + TABLE, "taskSeriesId"); + + /** RTM Task Series Id */ + public static final LongProperty TASK_ID = new LongProperty( + TABLE, "taskId"); + + /** Whether task repeats in RTM (1 or 0) */ + public static final IntegerProperty REPEATING = new IntegerProperty( + TABLE, "repeating"); + + /** Unixtime task was last updated in RTM */ + public static final LongProperty UPDATED = new LongProperty( + TABLE, "updated"); + + /** List of all properties for this model */ + public static final Property[] PROPERTIES = generateProperties(MilkTask.class); + + // --- defaults + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + + static { + defaultValues.put(REPEATING.name, 0); + defaultValues.put(UPDATED.name, 0); + } + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + // --- data access boilerplate + + public MilkTask() { + super(); + } + + public MilkTask(TodorooCursor cursor) { + this(); + readPropertiesFromCursor(cursor); + } + + public void readFromCursor(TodorooCursor cursor) { + super.readPropertiesFromCursor(cursor); + } + + @Override + public long getId() { + return getIdHelper(TASK); + }; + + + // --- parcelable helpers + + private static final Creator CREATOR = new ModelCreator(Task.class); + + @Override + protected Creator getCreator() { + return CREATOR; + } + +} diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMSyncProvider.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMSyncProvider.java index e9a6a0447..84b6c1680 100644 --- a/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMSyncProvider.java +++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/sync/RTMSyncProvider.java @@ -41,6 +41,7 @@ import com.todoroo.astrid.rmilk.api.data.RtmTasks; import com.todoroo.astrid.rmilk.api.data.RtmAuth.Perms; import com.todoroo.astrid.rmilk.api.data.RtmTask.Priority; import com.todoroo.astrid.rmilk.data.MilkDataService; +import com.todoroo.astrid.rmilk.data.MilkTask; import com.todoroo.astrid.service.AstridDependencyInjector; public class RTMSyncProvider extends SynchronizationProvider { @@ -284,11 +285,11 @@ public class RTMSyncProvider extends SynchronizationProvider { Task.CREATION_DATE, Task.COMPLETION_DATE, Task.DELETION_DATE, - MilkDataService.LIST_ID, - MilkDataService.TASK_SERIES_ID, - MilkDataService.TASK_ID, - MilkDataService.REPEAT, - MilkDataService.TAGS, + MilkTask.LIST_ID, + MilkTask.TASK_SERIES_ID, + MilkTask.TASK_ID, + MilkTask.REPEATING, + // TODO tags }; // fetch locally created tasks @@ -320,12 +321,12 @@ public class RTMSyncProvider extends SynchronizationProvider { * @return */ private boolean shouldTransmit(Task task, Property property, Task remoteTask) { - if(!task.hasValue(property)) + if(!task.containsValue(property)) return false; if(remoteTask == null) return true; - if(!remoteTask.hasValue(property)) + if(!remoteTask.containsValue(property)) return true; return !AndroidUtilities.equals(task.getValue(property), remoteTask.getValue(property)); } @@ -333,8 +334,8 @@ public class RTMSyncProvider extends SynchronizationProvider { @Override protected void create(Task task) throws IOException { String listId = null; - if(task.hasValue(MilkDataService.LIST_ID)) - listId = task.getValue(MilkDataService.LIST_ID); + if(task.containsValue(MilkTask.LIST_ID)) + listId = Long.toString(task.getValue(MilkTask.LIST_ID)); RtmTaskSeries rtmTask = rtmService.tasks_add(timeline, listId, task.getValue(Task.TITLE)); @@ -360,7 +361,7 @@ public class RTMSyncProvider extends SynchronizationProvider { if(shouldTransmit(task, Task.DUE_DATE, remoteTask)) rtmService.tasks_setDueDate(timeline, id.listId, id.taskSeriesId, id.taskId, DateUtilities.unixtimeToDate(task.getValue(Task.DUE_DATE)), - task.getValue(Task.URGENCY) == Task.URGENCY_SPECIFIC_DAY_TIME); + task.hasDueTime()); if(shouldTransmit(task, Task.COMPLETION_DATE, remoteTask)) { if(task.getValue(Task.COMPLETION_DATE) == 0) rtmService.tasks_uncomplete(timeline, id.listId, id.taskSeriesId, @@ -373,8 +374,8 @@ public class RTMSyncProvider extends SynchronizationProvider { rtmService.tasks_delete(timeline, id.listId, id.taskSeriesId, id.taskId); - if(shouldTransmit(task, MilkDataService.LIST_ID, remoteTask) && remoteTask != null) - rtmService.tasks_moveTo(timeline, remoteTask.getValue(MilkDataService.LIST_ID), + if(shouldTransmit(task, MilkTask.LIST_ID, remoteTask) && remoteTask != null) + rtmService.tasks_moveTo(timeline, Long.toString(remoteTask.getValue(MilkTask.LIST_ID)), id.listId, id.taskSeriesId, id.taskId); } @@ -382,10 +383,10 @@ public class RTMSyncProvider extends SynchronizationProvider { private Task parseRemoteTask(RtmTaskSeries rtmTaskSeries) { Task task = new Task(); - task.setValue(MilkDataService.LIST_ID, rtmTaskSeries.getList().getId()); - task.setValue(MilkDataService.TASK_SERIES_ID, rtmTaskSeries.getId()); + task.setValue(MilkTask.LIST_ID, Long.parseLong(rtmTaskSeries.getList().getId())); + task.setValue(MilkTask.TASK_SERIES_ID, Long.parseLong(rtmTaskSeries.getId())); task.setValue(Task.TITLE, rtmTaskSeries.getName()); - task.setValue(MilkDataService.REPEAT, rtmTaskSeries.hasRecurrence() ? 1 : 0); + task.setValue(MilkTask.REPEATING, rtmTaskSeries.hasRecurrence() ? 1 : 0); RtmTask rtmTask = rtmTaskSeries.getTask(); if(rtmTask != null) { @@ -393,18 +394,16 @@ public class RTMSyncProvider extends SynchronizationProvider { task.setValue(Task.COMPLETION_DATE, DateUtilities.dateToUnixtime(rtmTask.getCompleted())); task.setValue(Task.DELETION_DATE, DateUtilities.dateToUnixtime(rtmTask.getDeleted())); if(rtmTask.getDue() != null) { - task.setValue(Task.DUE_DATE, DateUtilities.dateToUnixtime(rtmTask.getDue())); - if(rtmTask.getHasDueTime()) - task.setValue(Task.URGENCY, Task.URGENCY_SPECIFIC_DAY_TIME); - else - task.setValue(Task.URGENCY, Task.URGENCY_SPECIFIC_DAY); + task.setValue(Task.DUE_DATE, + task.createDueDate(rtmTask.getHasDueTime() ? Task.URGENCY_SPECIFIC_DAY_TIME : + Task.URGENCY_SPECIFIC_DAY, DateUtilities.dateToUnixtime(rtmTask.getDue()))); } else { - task.setValue(Task.URGENCY, Task.URGENCY_NONE); + task.setValue(Task.DUE_DATE, 0L); } task.setValue(Task.IMPORTANCE, rtmTask.getPriority().ordinal()); } else { // error in upstream code, try to handle gracefully - Log.e("rtmsync", "Got null task parsing remote task series", + Log.e("rtmsync", "Got null task parsing remote task series", //$NON-NLS-1$//$NON-NLS-2$ new Throwable()); } @@ -416,9 +415,9 @@ public class RTMSyncProvider extends SynchronizationProvider { int length = tasks.size(); for(int i = 0; i < length; i++) { Task task = tasks.get(i); - if(task.getValue(MilkDataService.LIST_ID).equals(target.getValue(MilkDataService.LIST_ID)) && - task.getValue(MilkDataService.TASK_SERIES_ID).equals(target.getValue(MilkDataService.TASK_SERIES_ID)) && - task.getValue(MilkDataService.TASK_ID).equals(target.getValue(MilkDataService.TASK_ID))) + if(task.getValue(MilkTask.LIST_ID).equals(target.getValue(MilkTask.LIST_ID)) && + task.getValue(MilkTask.TASK_SERIES_ID).equals(target.getValue(MilkTask.TASK_SERIES_ID)) && + task.getValue(MilkTask.TASK_ID).equals(target.getValue(MilkTask.TASK_ID))) return task; } return null; @@ -426,7 +425,7 @@ public class RTMSyncProvider extends SynchronizationProvider { @Override protected Task read(Task task) throws IOException { - RtmTaskSeries rtmTask = rtmService.tasks_getTask(task.getValue(MilkDataService.TASK_SERIES_ID), + RtmTaskSeries rtmTask = rtmService.tasks_getTask(Long.toString(task.getValue(MilkTask.TASK_SERIES_ID)), task.getValue(Task.TITLE)); if(rtmTask != null) return parseRemoteTask(rtmTask); @@ -435,25 +434,25 @@ public class RTMSyncProvider extends SynchronizationProvider { @Override protected void transferIdentifiers(Task source, Task destination) { - destination.setValue(MilkDataService.LIST_ID, source.getValue(MilkDataService.LIST_ID)); - destination.setValue(MilkDataService.TASK_SERIES_ID, source.getValue(MilkDataService.TASK_SERIES_ID)); - destination.setValue(MilkDataService.TASK_ID, source.getValue(MilkDataService.TASK_ID)); + destination.setValue(MilkTask.LIST_ID, source.getValue(MilkTask.LIST_ID)); + destination.setValue(MilkTask.TASK_SERIES_ID, source.getValue(MilkTask.TASK_SERIES_ID)); + destination.setValue(MilkTask.TASK_ID, source.getValue(MilkTask.TASK_ID)); } // ---------------------------------------------------------------------- // ------------------------------------------------------- helper classes // ---------------------------------------------------------------------- - /** Helper class for processing RTM id's into one field */ + /** Helper class for storing RTM id's */ private static class RtmId { public String taskId; public String taskSeriesId; public String listId; public RtmId(Task task) { - taskId = task.getValue(MilkDataService.TASK_ID); - taskSeriesId = task.getValue(MilkDataService.TASK_SERIES_ID); - listId = task.getValue(MilkDataService.LIST_ID); + taskId = Long.toString(task.getValue(MilkTask.TASK_ID)); + taskSeriesId = Long.toString(task.getValue(MilkTask.TASK_SERIES_ID)); + listId = Long.toString(task.getValue(MilkTask.LIST_ID)); } } diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java index f8f8cf833..d81a7acdf 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java @@ -2,8 +2,8 @@ package com.todoroo.astrid.tags; import java.util.ArrayList; -import com.todoroo.andlib.data.Property.CountProperty; import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.data.Property.CountProperty; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Criterion; @@ -43,11 +43,11 @@ public class TagService { DependencyInjectionService.getInstance().inject(this); } + /** * Property for retrieving count of aggregated rows */ private static final CountProperty COUNT = new CountProperty(); - public static final Order GROUPED_TAGS_BY_ALPHA = Order.asc(Metadata.VALUE); public static final Order GROUPED_TAGS_BY_SIZE = Order.desc(COUNT); diff --git a/astrid/src/com/todoroo/astrid/dao/IntegerJoinProperty.java b/astrid/src/com/todoroo/astrid/dao/IntegerJoinProperty.java new file mode 100644 index 000000000..a2c488cb9 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/dao/IntegerJoinProperty.java @@ -0,0 +1,22 @@ +package com.todoroo.astrid.dao; + +import com.todoroo.andlib.data.Property.IntegerProperty; +import com.todoroo.astrid.model.Metadata; + +/** + * Helper class for representing string columns from joined metadata + */ +public class IntegerJoinProperty extends IntegerProperty implements JoinProperty { + + public IntegerJoinProperty(String name) { + super(null, name); + } + + @SuppressWarnings("nls") + public String joinTable() { + return String.format("SELECT %s,%s AS %s FROM %s WHERE %s='%s'", + Metadata.TASK, Metadata.VALUE, name, + Metadata.TABLE, Metadata.KEY, name); + } + +} \ No newline at end of file diff --git a/astrid/src/com/todoroo/astrid/dao/JoinProperty.java b/astrid/src/com/todoroo/astrid/dao/JoinProperty.java new file mode 100644 index 000000000..44ee9914f --- /dev/null +++ b/astrid/src/com/todoroo/astrid/dao/JoinProperty.java @@ -0,0 +1,14 @@ +/** + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.dao; + +public interface JoinProperty { + + /** + * @return SQL select statement describing how to load this property + * in a join statement + */ + public String joinTable(); + +} diff --git a/astrid/src/com/todoroo/astrid/dao/StringJoinProperty.java b/astrid/src/com/todoroo/astrid/dao/StringJoinProperty.java new file mode 100644 index 000000000..c47a6e972 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/dao/StringJoinProperty.java @@ -0,0 +1,21 @@ +package com.todoroo.astrid.dao; + +import com.todoroo.andlib.data.Property.StringProperty; +import com.todoroo.astrid.model.Metadata; + +/** + * Helper class for representing string columns from another table + */ +public class StringJoinProperty extends StringProperty implements JoinProperty { + + public StringJoinProperty(String name) { + super(null, name); + } + + @SuppressWarnings("nls") + public String joinTable() { + return String.format("SELECT %s,%s AS %s FROM %s WHERE %s='%s'", + Metadata.TASK, Metadata.VALUE, name, + Metadata.TABLE, Metadata.KEY, name); + } +} \ No newline at end of file