Special sync-on-complete hooks for completing tasks that remember the milk is handling the repeat for.

pull/14/head
Tim Su 16 years ago
parent 74b5ff1f95
commit e80e062735

@ -22,127 +22,132 @@ package com.mdt.rtm.data;
import java.util.Date; import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import android.util.Log;
/** /**
* *
* @author Will Ross Jun 22, 2007 * @author Will Ross Jun 22, 2007
*/ */
public class RtmTaskSeries extends RtmData { public class RtmTaskSeries extends RtmData {
private static final Logger log = Logger.getLogger("TaskSeries"); private final String id;
private final String id; private final Date created;
private final Date created; private final Date modified;
private final Date modified; private final String name;
private final String name; private final String source;
private final String source; private final RtmTask task;
private final RtmTask task; private final LinkedList<String> tags;
private final LinkedList<String> tags; private final RtmTaskNotes notes;
private final RtmTaskNotes notes; private final String locationId;
private final String locationId; private final String url;
private final String url; private final boolean hasRecurrence;
public RtmTaskSeries(String id, Date created, Date modified, String name, String source, RtmTask task) { public RtmTaskSeries(String id, Date created, Date modified, String name,
this.id = id; String source, RtmTask task) {
this.created = created; this.id = id;
this.modified = modified; this.created = created;
this.name = name; this.modified = modified;
this.source = source; this.name = name;
this.task = task; this.source = source;
this.locationId = null; this.task = task;
notes = null; this.locationId = null;
url = null; notes = null;
tags = null; url = null;
} tags = null;
hasRecurrence = false;
}
public RtmTaskSeries(Element elt) { public RtmTaskSeries(Element elt) {
id = elt.getAttribute("id"); id = elt.getAttribute("id");
created = parseDate(elt.getAttribute("created")); created = parseDate(elt.getAttribute("created"));
modified = parseDate(elt.getAttribute("modified")); modified = parseDate(elt.getAttribute("modified"));
name = elt.getAttribute("name"); name = elt.getAttribute("name");
source = elt.getAttribute("source"); source = elt.getAttribute("source");
task = new RtmTask(child(elt, "task")); task = new RtmTask(child(elt, "task"));
if (children(elt, "task").size() > 1) {
Log.e("rtmsync", "WARANING: Assumption incorrect: found a " +
"TaskSeries with more than one child Task.");
}
notes = new RtmTaskNotes(child(elt, "notes"));
locationId = elt.getAttribute("location_id");
url = elt.getAttribute("url");
hasRecurrence = children(elt, "rrule").size() > 0;
Element elementTags = child(elt, "tags");
if (elementTags.getChildNodes().getLength() > 0) {
List<Element> elementTagList = children(elementTags, "tag");
tags = new LinkedList<String>();
for (Element elementTag : elementTagList) {
String tag = text(elementTag);
if (tag != null)
tags.add(tag);
}
} else {
tags = null;
}
}
if (children(elt, "task").size() > 1) { public String getId() {
log.severe("WARANING: Assumption incorrect: found a TaskSeries with more than one child Task."); return id;
} }
notes = new RtmTaskNotes(child(elt, "notes"));
locationId = elt.getAttribute("location_id"); public Date getCreated() {
url = elt.getAttribute("url"); return created;
}
Element elementTags = child(elt, "tags");
if(elementTags.getChildNodes().getLength() > 0) { public Date getModified() {
List<Element> elementTagList = children(elementTags, "tag"); return modified;
tags = new LinkedList<String>(); }
for (Element elementTag : elementTagList) {
String tag = text(elementTag); public String getName() {
if(tag != null) return name;
tags.add(tag); }
}
} else { public String getSource() {
tags = null; return source;
}
public RtmTask getTask() {
return task;
}
public LinkedList<String> getTags() {
return tags;
}
public RtmTaskNotes getNotes() {
return notes;
}
public String getLocationId() {
return locationId;
}
@Override
public String toString() {
return "TaskSeries<" + id + "," + name + ">";
}
public String getURL() {
return url;
}
public boolean hasRecurrence() {
return hasRecurrence;
} }
}
public String getId() {
return id;
}
public Date getCreated() {
return created;
}
public Date getModified() {
return modified;
}
public String getName() {
return name;
}
public String getSource() {
return source;
}
public RtmTask getTask() {
return task;
}
public LinkedList<String> getTags() {
return tags;
}
public RtmTaskNotes getNotes()
{
return notes;
}
public String getLocationId()
{
return locationId;
}
@Override
public String toString()
{
return "TaskSeries<" + id + "," + name + ">";
}
public String getURL()
{
return url;
}
} }

@ -131,7 +131,7 @@ public class TaskListSubActivity extends SubActivity {
// indicator flag set if task list should be refreshed (something changed // indicator flag set if task list should be refreshed (something changed
// in another activity) // in another activity)
static boolean shouldRefreshTaskList = false; public static boolean shouldRefreshTaskList = false;
// indicator flag set if synchronization window has been opened & closed // indicator flag set if synchronization window has been opened & closed
static boolean syncPreferencesOpened = false; static boolean syncPreferencesOpened = false;

@ -59,7 +59,7 @@ public class SyncDataController extends AbstractController {
// --- sync mapping // --- sync mapping
/** Get all mappings for the given synchronization service */ /** Get all mappings for the given synchronization service */
public HashSet<SyncMapping> getSyncMapping(int syncServiceId) throws SQLException { public HashSet<SyncMapping> getSyncMappings(int syncServiceId) throws SQLException {
HashSet<SyncMapping> list = new HashSet<SyncMapping>(); HashSet<SyncMapping> list = new HashSet<SyncMapping>();
Cursor cursor = syncDatabase.query(SYNC_TABLE_NAME, Cursor cursor = syncDatabase.query(SYNC_TABLE_NAME,
SyncMapping.FIELD_LIST, SyncMapping.FIELD_LIST,
@ -80,6 +80,26 @@ public class SyncDataController extends AbstractController {
} }
} }
/** Get mapping for given task */
public SyncMapping getSyncMapping(int syncServiceId, TaskIdentifier taskId)
throws SQLException {
Cursor cursor = syncDatabase.query(SYNC_TABLE_NAME,
SyncMapping.FIELD_LIST,
SyncMapping.SYNC_SERVICE + " = ? AND " +
SyncMapping.TASK + " = ?",
new String[] { "" + syncServiceId, "" + taskId.getId() },
null, null, null);
try {
if(cursor.getCount() == 0)
return null;
cursor.moveToNext();
return new SyncMapping(cursor);
} finally {
cursor.close();
}
}
/** Saves the given task to the database. Returns true on success. */ /** Saves the given task to the database. Returns true on success. */
public boolean saveSyncMapping(SyncMapping mapping) { public boolean saveSyncMapping(SyncMapping mapping) {
long newRow = syncDatabase.insert(SYNC_TABLE_NAME, SyncMapping.TASK, long newRow = syncDatabase.insert(SYNC_TABLE_NAME, SyncMapping.TASK,

@ -45,7 +45,7 @@ import com.timsu.astrid.utilities.Preferences;
public abstract class AbstractTaskModel extends AbstractModel { public abstract class AbstractTaskModel extends AbstractModel {
/** Version number of this model */ /** Version number of this model */
static final int VERSION = 5; static final int VERSION = 6;
public static final int COMPLETE_PERCENTAGE = 100; public static final int COMPLETE_PERCENTAGE = 100;
@ -69,6 +69,7 @@ public abstract class AbstractTaskModel extends AbstractModel {
static final String CREATION_DATE = "creationDate"; static final String CREATION_DATE = "creationDate";
static final String COMPLETION_DATE = "completionDate"; static final String COMPLETION_DATE = "completionDate";
static final String CALENDAR_URI = "calendarUri"; static final String CALENDAR_URI = "calendarUri";
static final String FLAGS = "flags";
// reserved fields --- // reserved fields ---
static final String BLOCKING_ON = "blockingOn"; static final String BLOCKING_ON = "blockingOn";
@ -78,6 +79,9 @@ public abstract class AbstractTaskModel extends AbstractModel {
public static final int NOTIFY_AFTER_DEADLINE = 1 << 2; public static final int NOTIFY_AFTER_DEADLINE = 1 << 2;
public static final int NOTIFY_NONSTOP = 1 << 3; public static final int NOTIFY_NONSTOP = 1 << 3;
// other flags
public static final int FLAG_SYNC_ON_COMPLETE = 1 << 0;
/** Number of bits to shift repeat value by */ /** Number of bits to shift repeat value by */
public static final int REPEAT_VALUE_OFFSET = 3; public static final int REPEAT_VALUE_OFFSET = 3;
@ -103,6 +107,7 @@ public abstract class AbstractTaskModel extends AbstractModel {
defaultValues.put(REPEAT, 0); defaultValues.put(REPEAT, 0);
defaultValues.put(COMPLETION_DATE, (Long)null); defaultValues.put(COMPLETION_DATE, (Long)null);
defaultValues.put(CALENDAR_URI, (String)null); defaultValues.put(CALENDAR_URI, (String)null);
defaultValues.put(FLAGS, 0);
} }
// --- database helper // --- database helper
@ -137,6 +142,7 @@ public abstract class AbstractTaskModel extends AbstractModel {
append(NOTIFICATION_FLAGS).append(" integer,"). append(NOTIFICATION_FLAGS).append(" integer,").
append(LAST_NOTIFIED).append(" integer,"). append(LAST_NOTIFIED).append(" integer,").
append(REPEAT).append(" integer,"). append(REPEAT).append(" integer,").
append(FLAGS).append(" integer,").
append(CREATION_DATE).append(" integer,"). append(CREATION_DATE).append(" integer,").
append(COMPLETION_DATE).append(" integer,"). append(COMPLETION_DATE).append(" integer,").
append(CALENDAR_URI).append(" text"). append(CALENDAR_URI).append(" text").
@ -202,6 +208,15 @@ public abstract class AbstractTaskModel extends AbstractModel {
Log.e("astrid", "Error updating table!", e); Log.e("astrid", "Error updating table!", e);
} }
case 5:
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(FLAGS).append(" integer").toString();
try {
db.execSQL(sql);
} catch (Exception e) {
Log.e("astrid", "Error updating table!", e);
}
break; break;
default: default:
@ -282,6 +297,8 @@ public abstract class AbstractTaskModel extends AbstractModel {
getLastNotificationDate(); getLastNotificationDate();
else if(field.equals(REPEAT)) else if(field.equals(REPEAT))
getRepeat(); getRepeat();
else if(field.equals(FLAGS))
getFlags();
} }
} }
@ -451,6 +468,10 @@ public abstract class AbstractTaskModel extends AbstractModel {
return uri; return uri;
} }
protected int getFlags() {
return retrieveInteger(FLAGS);
}
// --- setters // --- setters
protected void setName(String name) { protected void setName(String name) {
@ -542,6 +563,10 @@ public abstract class AbstractTaskModel extends AbstractModel {
putIfChangedFromDatabase(CALENDAR_URI, uri); putIfChangedFromDatabase(CALENDAR_URI, uri);
} }
protected void setFlags(int flags) {
putIfChangedFromDatabase(FLAGS, flags);
}
// --- utility methods // --- utility methods
protected void putDate(String fieldName, Date date) { protected void putDate(String fieldName, Date date) {

@ -36,11 +36,14 @@ import android.net.Uri;
import android.util.Log; import android.util.Log;
import com.timsu.astrid.activities.TaskEdit; import com.timsu.astrid.activities.TaskEdit;
import com.timsu.astrid.activities.TaskListSubActivity;
import com.timsu.astrid.data.AbstractController; import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.AlertController; import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.sync.SyncDataController; import com.timsu.astrid.data.sync.SyncDataController;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo; import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper; import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
import com.timsu.astrid.sync.Synchronizer;
import com.timsu.astrid.sync.Synchronizer.SynchronizerListener;
import com.timsu.astrid.utilities.Notifications; import com.timsu.astrid.utilities.Notifications;
/** /**
@ -239,6 +242,13 @@ public class TaskController extends AbstractController {
saveSucessful = database.update(TASK_TABLE_NAME, values, saveSucessful = database.update(TASK_TABLE_NAME, values,
KEY_ROWID + "=" + id, null) > 0; KEY_ROWID + "=" + id, null) > 0;
// task was completed
if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) &&
values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE)
== AbstractTaskModel.COMPLETE_PERCENTAGE) {
onTaskSetCompleted(task, values);
}
if(!(task instanceof TaskModelForSync)) { if(!(task instanceof TaskModelForSync)) {
SyncDataController syncController = new SyncDataController(context); SyncDataController syncController = new SyncDataController(context);
syncController.open(); syncController.open();
@ -258,13 +268,6 @@ public class TaskController extends AbstractController {
*/ */
private void onTaskSave(AbstractTaskModel task, ContentValues values) { private void onTaskSave(AbstractTaskModel task, ContentValues values) {
// task was completed
if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) &&
values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE)
== AbstractTaskModel.COMPLETE_PERCENTAGE) {
onTaskSetCompleted(task, values);
}
// task timer was updated, update notification bar // task timer was updated, update notification bar
if(values.containsKey(AbstractTaskModel.TIMER_START)) { if(values.containsKey(AbstractTaskModel.TIMER_START)) {
// show notification bar if timer was started // show notification bar if timer was started
@ -322,16 +325,26 @@ public class TaskController extends AbstractController {
*/ */
private void onTaskSetCompleted(AbstractTaskModel task, ContentValues values) { private void onTaskSetCompleted(AbstractTaskModel task, ContentValues values) {
values.put(AbstractTaskModel.COMPLETION_DATE, System.currentTimeMillis()); values.put(AbstractTaskModel.COMPLETION_DATE, System.currentTimeMillis());
Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(),
TaskModelForHandlers.FIELD_LIST);
TaskModelForHandlers model = new TaskModelForHandlers(cursor, values);
// handle repeat // handle repeat
Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(), RepeatInfo repeatInfo = model.getRepeat();
TaskModelForRepeat.FIELD_LIST);
TaskModelForRepeat repeatModel = new TaskModelForRepeat(cursor, values);
RepeatInfo repeatInfo = repeatModel.getRepeat();
if(repeatInfo != null) if(repeatInfo != null)
repeatModel.repeatTaskBy(context, this, repeatInfo); model.repeatTaskBy(context, this, repeatInfo);
cursor.close();
// handle sync-on-complete
if((model.getFlags() & TaskModelForHandlers.FLAG_SYNC_ON_COMPLETE) > 0) {
Synchronizer synchronizer = new Synchronizer(model.getTaskIdentifier());
synchronizer.synchronize(context, new SynchronizerListener() {
public void onSynchronizerFinished(int numServicesSynced) {
TaskListSubActivity.shouldRefreshTaskList = true;
}
});
}
cursor.close();
cleanupTask(task.getTaskIdentifier(), repeatInfo != null); cleanupTask(task.getTaskIdentifier(), repeatInfo != null);
} }

@ -33,8 +33,9 @@ import com.timsu.astrid.utilities.Notifications.Notifiable;
/** Fields that you would want to edit pertaining to repeats */ /** Fields that you would want to read or edit in the onTaskSave and onTaskComplete
public class TaskModelForRepeat extends AbstractTaskModel implements Notifiable { * event handlers */
public class TaskModelForHandlers extends AbstractTaskModel implements Notifiable {
static String[] FIELD_LIST = new String[] { static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID, AbstractController.KEY_ROWID,
@ -47,6 +48,7 @@ public class TaskModelForRepeat extends AbstractTaskModel implements Notifiable
LAST_NOTIFIED, LAST_NOTIFIED,
NOTIFICATIONS, NOTIFICATIONS,
NOTIFICATION_FLAGS, NOTIFICATION_FLAGS,
FLAGS,
}; };
/** /**
@ -96,7 +98,7 @@ public class TaskModelForRepeat extends AbstractTaskModel implements Notifiable
// --- constructors // --- constructors
public TaskModelForRepeat(Cursor cursor, ContentValues setValues) { public TaskModelForHandlers(Cursor cursor, ContentValues setValues) {
super(cursor); super(cursor);
this.setValues = setValues; this.setValues = setValues;
} }
@ -147,6 +149,11 @@ public class TaskModelForRepeat extends AbstractTaskModel implements Notifiable
return super.getLastNotificationDate(); return super.getLastNotificationDate();
} }
@Override
public int getFlags() {
return super.getFlags();
}
@Override @Override
public void setDefiniteDueDate(Date definiteDueDate) { public void setDefiniteDueDate(Date definiteDueDate) {
super.setDefiniteDueDate(definiteDueDate); super.setDefiniteDueDate(definiteDueDate);

@ -50,6 +50,7 @@ public class TaskModelForSync extends AbstractTaskModel implements Notifiable {
LAST_NOTIFIED, LAST_NOTIFIED,
NOTIFICATIONS, NOTIFICATIONS,
NOTIFICATION_FLAGS, NOTIFICATION_FLAGS,
FLAGS,
}; };
// --- constructors // --- constructors
@ -151,6 +152,11 @@ public class TaskModelForSync extends AbstractTaskModel implements Notifiable {
return super.getLastNotificationDate(); return super.getLastNotificationDate();
} }
@Override
public int getFlags() {
return super.getFlags();
}
// --- setters // --- setters
@Override @Override
@ -222,5 +228,10 @@ public class TaskModelForSync extends AbstractTaskModel implements Notifiable {
public void setNotificationIntervalSeconds(Integer intervalInSeconds) { public void setNotificationIntervalSeconds(Integer intervalInSeconds) {
super.setNotificationIntervalSeconds(intervalInSeconds); super.setNotificationIntervalSeconds(intervalInSeconds);
} }
@Override
public void setFlags(int flags) {
super.setFlags(flags);
}
} }

@ -174,6 +174,23 @@ public class RTMSyncProvider extends SynchronizationProvider {
final String timeline = rtmService.timelines_create(); final String timeline = rtmService.timelines_create();
postUpdate(new ProgressUpdater(1, 5)); postUpdate(new ProgressUpdater(1, 5));
// push task if single task sync is requested
if(getSingleTaskForSync() != null) {
SyncMapping mapping = synchronizer.getSyncController(context).
getSyncMapping(getId(), getSingleTaskForSync());
if(mapping == null) {
Log.w("astrid-rtm", "Couldn't find sync mapping for updated task");
return;
}
TaskProxy localTask = new TaskProxy(getId(), mapping.getRemoteId());
TaskModelForSync task = synchronizer.getTaskController(context).
fetchTaskForSync(getSingleTaskForSync());
localTask.readFromTaskModel(task);
postUpdate(new ProgressLabelUpdater("Synchronizing repeating task"));
pushLocalTask(timeline, localTask, null, mapping);
}
// load RTM lists // load RTM lists
RtmLists lists = rtmService.lists_getList(); RtmLists lists = rtmService.lists_getList();
for(RtmList list : lists.getLists().values()) { for(RtmList list : lists.getLists().values()) {
@ -238,11 +255,12 @@ public class RTMSyncProvider extends SynchronizationProvider {
Date syncTime = new Date(System.currentTimeMillis() + 1000); Date syncTime = new Date(System.currentTimeMillis() + 1000);
Preferences.setSyncRTMLastSync(context, syncTime); Preferences.setSyncRTMLastSync(context, syncTime);
// on with the synchronization
synchronizer.continueSynchronization(context);
} catch (Exception e) { } catch (Exception e) {
showError(context, e, null); showError(context, e, null);
} finally {
// on with the synchronization
synchronizer.continueSynchronization(context);
} }
} }
@ -261,7 +279,7 @@ public class RTMSyncProvider extends SynchronizationProvider {
/** Get a task proxy with default RTM values */ /** Get a task proxy with default RTM values */
private TaskProxy getDefaultTaskProxy() { private TaskProxy getDefaultTaskProxy() {
TaskProxy taskProxy = new TaskProxy(0, "", false); TaskProxy taskProxy = new TaskProxy(0, "");
taskProxy.progressPercentage = 0; taskProxy.progressPercentage = 0;
taskProxy.tags = new LinkedList<String>(); taskProxy.tags = new LinkedList<String>();
taskProxy.notes = ""; taskProxy.notes = "";
@ -350,8 +368,7 @@ public class RTMSyncProvider extends SynchronizationProvider {
/** Create a task proxy for the given RtmTaskSeries */ /** Create a task proxy for the given RtmTaskSeries */
private TaskProxy parseRemoteTask(String listId, RtmTaskSeries rtmTaskSeries) { private TaskProxy parseRemoteTask(String listId, RtmTaskSeries rtmTaskSeries) {
TaskProxy task = new TaskProxy(getId(), TaskProxy task = new TaskProxy(getId(),
new RtmId(listId, rtmTaskSeries).toString(), new RtmId(listId, rtmTaskSeries).toString());
rtmTaskSeries.getTask().getDeleted() != null);
task.name = rtmTaskSeries.getName(); task.name = rtmTaskSeries.getName();
@ -363,6 +380,10 @@ public class RTMSyncProvider extends SynchronizationProvider {
if(sb.length() > 0) if(sb.length() > 0)
task.notes = sb.toString().trim(); task.notes = sb.toString().trim();
// repeat
if(rtmTaskSeries.hasRecurrence())
task.syncOnComplete = true;
// list / tags // list / tags
LinkedList<String> tagsList = rtmTaskSeries.getTags(); LinkedList<String> tagsList = rtmTaskSeries.getTags();
String listName = listIdToNameMap.get(listId); String listName = listIdToNameMap.get(listId);
@ -381,6 +402,7 @@ public class RTMSyncProvider extends SynchronizationProvider {
} }
task.creationDate = rtmTaskSeries.getCreated(); task.creationDate = rtmTaskSeries.getCreated();
task.completionDate = rtmTask.getCompleted(); task.completionDate = rtmTask.getCompleted();
task.isDeleted = rtmTask.getDeleted() != null;
if(rtmTask.getDue() != null) { if(rtmTask.getDue() != null) {
Date due = rtmTask.getDue(); Date due = rtmTask.getDue();
@ -392,7 +414,6 @@ public class RTMSyncProvider extends SynchronizationProvider {
task.dueDate = due; task.dueDate = due;
} }
task.progressPercentage = (rtmTask.getCompleted() == null) ? 0 : 100; task.progressPercentage = (rtmTask.getCompleted() == null) ? 0 : 100;
task.importance = Importance.values()[rtmTask.getPriority().ordinal()]; task.importance = Importance.values()[rtmTask.getPriority().ordinal()];
return task; return task;

@ -108,6 +108,12 @@ public abstract class SynchronizationProvider {
return synchronizer.isService(); return synchronizer.isService();
} }
/** Check whether the synchronization request wants to only transmit
* one specific task. Returns null if this is not the case */
protected TaskIdentifier getSingleTaskForSync() {
return synchronizer.getSingleTaskForSync();
}
/** Utility method for showing synchronization errors. If message is null, /** Utility method for showing synchronization errors. If message is null,
* the contents of the throwable is displayed. * the contents of the throwable is displayed.
*/ */
@ -232,7 +238,7 @@ public abstract class SynchronizationProvider {
syncController.saveSyncMapping(mapping); syncController.saveSyncMapping(mapping);
data.localIdToSyncMapping.put(taskId, mapping); data.localIdToSyncMapping.put(taskId, mapping);
TaskProxy localTask = new TaskProxy(getId(), remoteId, false); TaskProxy localTask = new TaskProxy(getId(), remoteId);
localTask.readFromTaskModel(task); localTask.readFromTaskModel(task);
localTask.readTagsFromController(taskId, tagController, data.tags); localTask.readTagsFromController(taskId, tagController, data.tags);
helper.pushTask(localTask, null, mapping); helper.pushTask(localTask, null, mapping);
@ -264,8 +270,7 @@ public abstract class SynchronizationProvider {
// 3. UPDATE: for each updated local task // 3. UPDATE: for each updated local task
for(SyncMapping mapping : data.localChanges) { for(SyncMapping mapping : data.localChanges) {
TaskProxy localTask = new TaskProxy(getId(), mapping.getRemoteId(), TaskProxy localTask = new TaskProxy(getId(), mapping.getRemoteId());
false);
TaskModelForSync task = taskController.fetchTaskForSync( TaskModelForSync task = taskController.fetchTaskForSync(
mapping.getTask()); mapping.getTask());
localTask.readFromTaskModel(task); localTask.readFromTaskModel(task);
@ -298,7 +303,7 @@ public abstract class SynchronizationProvider {
} }
// re-fetch remote task // re-fetch remote task
if(remoteConflict != null) { if(remoteConflict != null || getSingleTaskForSync() != null) {
TaskProxy newTask = helper.refetchTask(remoteConflict); TaskProxy newTask = helper.refetchTask(remoteConflict);
remoteTasks.remove(remoteConflict); remoteTasks.remove(remoteConflict);
remoteTasks.add(newTask); remoteTasks.add(newTask);
@ -441,7 +446,7 @@ public abstract class SynchronizationProvider {
public SyncData(Context context, LinkedList<TaskProxy> remoteTasks) { public SyncData(Context context, LinkedList<TaskProxy> remoteTasks) {
// 1. get data out of the database // 1. get data out of the database
mappings = synchronizer.getSyncController(context).getSyncMapping(getId()); mappings = synchronizer.getSyncController(context).getSyncMappings(getId());
activeTasks = synchronizer.getTaskController(context).getActiveTaskIdentifiers(); activeTasks = synchronizer.getTaskController(context).getActiveTaskIdentifiers();
allTasks = synchronizer.getTaskController(context).getAllTaskIdentifiers(); allTasks = synchronizer.getTaskController(context).getAllTaskIdentifiers();
tags = synchronizer.getTagController(context).getAllTagsAsMap(); tags = synchronizer.getTagController(context).getAllTagsAsMap();
@ -449,11 +454,8 @@ public abstract class SynchronizationProvider {
// 2. build helper data structures // 2. build helper data structures
remoteIdToSyncMapping = new HashMap<String, SyncMapping>(); remoteIdToSyncMapping = new HashMap<String, SyncMapping>();
localIdToSyncMapping = new HashMap<TaskIdentifier, SyncMapping>(); localIdToSyncMapping = new HashMap<TaskIdentifier, SyncMapping>();
localChanges = new HashSet<SyncMapping>();
mappedTasks = new HashSet<TaskIdentifier>(); mappedTasks = new HashSet<TaskIdentifier>();
for(SyncMapping mapping : mappings) { for(SyncMapping mapping : mappings) {
if(mapping.isUpdated())
localChanges.add(mapping);
remoteIdToSyncMapping.put(mapping.getRemoteId(), mapping); remoteIdToSyncMapping.put(mapping.getRemoteId(), mapping);
localIdToSyncMapping.put(mapping.getTask(), mapping); localIdToSyncMapping.put(mapping.getTask(), mapping);
mappedTasks.add(mapping.getTask()); mappedTasks.add(mapping.getTask());
@ -475,10 +477,21 @@ public abstract class SynchronizationProvider {
} }
// 4. build data structures of things to do // 4. build data structures of things to do
newlyCreatedTasks = new HashSet<TaskIdentifier>(activeTasks); if(getSingleTaskForSync() != null) {
newlyCreatedTasks.removeAll(mappedTasks); newlyCreatedTasks = new HashSet<TaskIdentifier>();
deletedTasks = new HashSet<TaskIdentifier>(mappedTasks); deletedTasks = new HashSet<TaskIdentifier>();
deletedTasks.removeAll(allTasks); localChanges = new HashSet<SyncMapping>();
} else {
newlyCreatedTasks = new HashSet<TaskIdentifier>(activeTasks);
newlyCreatedTasks.removeAll(mappedTasks);
deletedTasks = new HashSet<TaskIdentifier>(mappedTasks);
deletedTasks.removeAll(allTasks);
localChanges = new HashSet<SyncMapping>();
for(SyncMapping mapping : localIdToSyncMapping.values()) {
if(mapping.isUpdated())
localChanges.add(mapping);
}
}
} }
} }
@ -500,7 +513,8 @@ public abstract class SynchronizationProvider {
progressDialog.hide(); progressDialog.hide();
Resources r = context.getResources(); Resources r = context.getResources();
if(Preferences.shouldSuppressSyncDialogs(context)) { if(Preferences.shouldSuppressSyncDialogs(context) ||
getSingleTaskForSync() != null) {
return; return;
} }

@ -31,6 +31,7 @@ import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.sync.SyncDataController; import com.timsu.astrid.data.sync.SyncDataController;
import com.timsu.astrid.data.tag.TagController; import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.task.TaskController; import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.utilities.Preferences; import com.timsu.astrid.utilities.Preferences;
/** /**
@ -50,8 +51,16 @@ public class Synchronizer {
// --- public interface // --- public interface
/** Synchronize all tasks */
public Synchronizer(boolean isService) { public Synchronizer(boolean isService) {
this.isService = isService; this.isService = isService;
singleTaskForSync = null;
}
/** Synchronize a specific task only */
public Synchronizer(TaskIdentifier task) {
isService = false;
singleTaskForSync = task;
} }
public interface SynchronizerListener { public interface SynchronizerListener {
@ -122,20 +131,28 @@ public class Synchronizer {
// Internal state for the synchronization process // Internal state for the synchronization process
/** Current step in the sync process */ /** Current step in the sync process */
private int currentStep; private int currentStep = 0;
/** # of services synchronized */ /** # of services synchronized */
private int servicesSynced; private int servicesSynced = 0;
/** On finished callback */ /** On finished callback */
private SynchronizerListener callback; private SynchronizerListener callback = null;
/** Whether this sync is initiated by a background service */
private final boolean isService;
private boolean isService; /** The single task to synchronize, if applicable */
private final TaskIdentifier singleTaskForSync;
boolean isService() { boolean isService() {
return isService; return isService;
} }
TaskIdentifier getSingleTaskForSync() {
return singleTaskForSync;
}
/** Called to do the next step of synchronization. */ /** Called to do the next step of synchronization. */
void continueSynchronization(Context context) { void continueSynchronization(Context context) {
ServiceWrapper serviceWrapper = ServiceWrapper serviceWrapper =
@ -161,12 +178,13 @@ public class Synchronizer {
/** Called at the end of sync. */ /** Called at the end of sync. */
private void finishSynchronization(final Context context) { private void finishSynchronization(final Context context) {
closeControllers(); closeControllers();
Preferences.setSyncLastSync(context, new Date());
if(callback != null) if(callback != null)
callback.onSynchronizerFinished(servicesSynced); callback.onSynchronizerFinished(servicesSynced);
if(getSingleTaskForSync() != null)
Preferences.setSyncLastSync(context, new Date());
if(!isService) if(!isService)
SynchronizationService.start(); SynchronizationService.start();
} }
// --- controller stuff // --- controller stuff

@ -41,10 +41,12 @@ import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
*/ */
public class TaskProxy { public class TaskProxy {
TaskProxy(int syncServiceId, String syncTaskId, boolean isDeleted) { public static final Date NO_DATE_SET = new Date(0);
public static final RepeatInfo NO_REPEAT_SET = new RepeatInfo(RepeatInterval.DAYS, 0);
TaskProxy(int syncServiceId, String syncTaskId) {
this.syncServiceId = syncServiceId; this.syncServiceId = syncServiceId;
this.syncTaskId = syncTaskId; this.syncTaskId = syncTaskId;
this.isDeleted = isDeleted;
} }
// --- fill these out // --- fill these out
@ -67,7 +69,12 @@ public class TaskProxy {
Integer estimatedSeconds = null; Integer estimatedSeconds = null;
Integer elapsedSeconds = null; Integer elapsedSeconds = null;
Integer repeatEveryNSeconds = null; RepeatInfo repeatInfo = null;
Boolean syncOnComplete = null;
/** was the task deleted on the remote server */
boolean isDeleted = false;
// --- internal state // --- internal state
@ -77,8 +84,6 @@ public class TaskProxy {
/** id of this particular remote task */ /** id of this particular remote task */
private String syncTaskId; private String syncTaskId;
/** was the task deleted on the remote server */
private boolean isDeleted = false;
public int getSyncServiceId() { public int getSyncServiceId() {
return syncServiceId; return syncServiceId;
@ -125,8 +130,10 @@ public class TaskProxy {
estimatedSeconds = other.estimatedSeconds; estimatedSeconds = other.estimatedSeconds;
if(other.elapsedSeconds != null) if(other.elapsedSeconds != null)
elapsedSeconds = other.elapsedSeconds; elapsedSeconds = other.elapsedSeconds;
if(other.repeatEveryNSeconds != null) if(other.repeatInfo != null)
repeatEveryNSeconds = other.repeatEveryNSeconds; repeatInfo = other.repeatInfo;
if(other.syncOnComplete != null)
syncOnComplete = other.syncOnComplete;
} }
/** Read from the given task model */ /** Read from the given task model */
@ -143,10 +150,8 @@ public class TaskProxy {
hiddenUntil = task.getHiddenUntil(); hiddenUntil = task.getHiddenUntil();
estimatedSeconds = task.getEstimatedSeconds(); estimatedSeconds = task.getEstimatedSeconds();
elapsedSeconds = task.getElapsedSeconds(); elapsedSeconds = task.getElapsedSeconds();
RepeatInfo repeatInfo = task.getRepeat(); syncOnComplete = (task.getFlags() & TaskModelForSync.FLAG_SYNC_ON_COMPLETE) > 0;
if(repeatInfo != null) { repeatInfo = task.getRepeat();
repeatEveryNSeconds = (int)(repeatInfo.shiftDate(new Date(0)).getTime()/1000);
}
} }
/** Read tags from the given tag controller */ /** Read tags from the given tag controller */
@ -199,22 +204,15 @@ public class TaskProxy {
task.setEstimatedSeconds(estimatedSeconds); task.setEstimatedSeconds(estimatedSeconds);
if(elapsedSeconds != null) if(elapsedSeconds != null)
task.setElapsedSeconds(elapsedSeconds); task.setElapsedSeconds(elapsedSeconds);
if(syncOnComplete != null)
task.setFlags(task.getFlags() | TaskModelForSync.FLAG_SYNC_ON_COMPLETE);
// this is inaccurate. =/ // this is inaccurate. =/
if(repeatEveryNSeconds != null) { if(repeatInfo != null) {
RepeatInterval repeatInterval; if(repeatInfo == NO_REPEAT_SET)
int repeatValue; task.setRepeat(null);
if(repeatEveryNSeconds < 7 * 24 * 3600) { else
repeatInterval = RepeatInterval.DAYS; task.setRepeat(repeatInfo);
repeatValue = repeatEveryNSeconds / (24 * 3600);
} else if(repeatEveryNSeconds < 30 * 24 * 3600) {
repeatInterval = RepeatInterval.WEEKS;
repeatValue = repeatEveryNSeconds / (7 * 24 * 3600);
} else {
repeatInterval = RepeatInterval.MONTHS;
repeatValue = repeatEveryNSeconds / (30 * 24 * 3600);
}
task.setRepeat(new RepeatInfo(repeatInterval, repeatValue));
} }
} }
} }

Loading…
Cancel
Save