mirror of https://github.com/tasks/tasks
Gtasks V2 sync provider
parent
d5b704badf
commit
c498eabba6
@ -1,49 +0,0 @@
|
||||
package com.todoroo.astrid.gtasks;
|
||||
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.data.Metadata;
|
||||
|
||||
/**
|
||||
* Metadata entries for synchronizing a GTasks Task
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class GtasksSyncMetadata {
|
||||
|
||||
/** metadata key */
|
||||
public static final String METADATA_KEY = "gtasks-sync"; //$NON-NLS-1$
|
||||
|
||||
/** last sync date*/
|
||||
public static final LongProperty LAST_SYNC = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE1.name);
|
||||
|
||||
/**
|
||||
* Helper to set value
|
||||
* @param metadataDao
|
||||
* @param id
|
||||
* @param property
|
||||
* @param now
|
||||
*/
|
||||
public static <T> void set(MetadataDao metadataDao, long taskId,
|
||||
Property<T> property, T value) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(MetadataCriteria.byTaskAndwithKey(taskId, METADATA_KEY)));
|
||||
Metadata metadata = new Metadata();
|
||||
if(cursor.getCount() == 0) {
|
||||
metadata.setValue(Metadata.TASK, taskId);
|
||||
metadata.setValue(Metadata.KEY, METADATA_KEY);
|
||||
} else {
|
||||
cursor.moveToFirst();
|
||||
metadata.readFromCursor(cursor);
|
||||
}
|
||||
|
||||
metadata.setValue(property, value);
|
||||
metadataDao.persist(metadata);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,274 @@
|
||||
package com.todoroo.astrid.gtasks.sync;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.google.api.services.tasks.model.Tasks;
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Join;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.core.PluginServices;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.dao.StoreObjectDao;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.data.Metadata;
|
||||
import com.todoroo.astrid.data.StoreObject;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.gtasks.GtasksList;
|
||||
import com.todoroo.astrid.gtasks.GtasksListService;
|
||||
import com.todoroo.astrid.gtasks.GtasksMetadata;
|
||||
import com.todoroo.astrid.gtasks.GtasksMetadataService;
|
||||
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
|
||||
import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
|
||||
import com.todoroo.astrid.gtasks.api.GoogleTasksException;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
|
||||
import com.todoroo.astrid.gtasks.auth.GtasksTokenValidator;
|
||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||
import com.todoroo.astrid.service.StatisticsConstants;
|
||||
import com.todoroo.astrid.service.StatisticsService;
|
||||
import com.todoroo.astrid.service.SyncV2Service.SyncResultCallback;
|
||||
import com.todoroo.astrid.service.SyncV2Service.SyncV2Provider;
|
||||
import com.todoroo.astrid.service.TaskService;
|
||||
import com.todoroo.astrid.utility.Flags;
|
||||
|
||||
public class GtasksSyncV2Provider extends SyncV2Provider {
|
||||
|
||||
@Autowired TaskService taskService;
|
||||
@Autowired StoreObjectDao storeObjectDao;
|
||||
@Autowired GtasksPreferenceService gtasksPreferenceService;
|
||||
@Autowired GtasksSyncService gtasksSyncService;
|
||||
@Autowired GtasksListService gtasksListService;
|
||||
@Autowired GtasksMetadataService gtasksMetadataService;
|
||||
@Autowired GtasksTaskListUpdater gtasksTaskListUpdater;
|
||||
|
||||
static {
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
public GtasksSyncV2Provider() {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ContextManager.getString(R.string.gtasks_GPr_header);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return gtasksPreferenceService.isLoggedIn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void synchronizeActiveTasks(boolean manual, final SyncResultCallback callback) {
|
||||
|
||||
callback.started();
|
||||
callback.incrementMax(100);
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
callback.incrementProgress(50);
|
||||
String authToken = getValidatedAuthToken();
|
||||
final GtasksInvoker invoker = new GtasksInvoker(authToken);
|
||||
try {
|
||||
gtasksListService.updateLists(invoker.allGtaskLists());
|
||||
} catch (IOException e) {
|
||||
// error updating lists
|
||||
} finally {
|
||||
callback.incrementMax(25);
|
||||
}
|
||||
StoreObject[] lists = gtasksListService.getLists();
|
||||
final AtomicInteger finisher = new AtomicInteger(lists.length);
|
||||
|
||||
pushUpdated(invoker, callback);
|
||||
|
||||
for (final StoreObject list : lists) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronizeListHelper(list, invoker, callback);
|
||||
if (finisher.decrementAndGet() == 0) {
|
||||
callback.finished();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void pushUpdated(GtasksInvoker invoker, SyncResultCallback callback) {
|
||||
TodorooCursor<Task> queued = taskService.query(Query.select(Task.PROPERTIES).join(Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK))).where(
|
||||
Criterion.or(
|
||||
Criterion.and(MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY),
|
||||
Task.MODIFICATION_DATE.gt(GtasksMetadata.LAST_SYNC)),
|
||||
Metadata.KEY.isNull())));
|
||||
callback.incrementMax(queued.getCount() * 10);
|
||||
try {
|
||||
Task task = new Task();
|
||||
for (queued.moveToFirst(); !queued.isAfterLast(); queued.moveToNext()) {
|
||||
task.readFromCursor(queued);
|
||||
try {
|
||||
gtasksSyncService.pushTaskOnSave(task, task.getMergedValues(), invoker, false);
|
||||
} catch (IOException e) {
|
||||
// Eh
|
||||
} finally {
|
||||
callback.incrementProgress(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
queued.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void synchronizeList(Object list, boolean manual, final SyncResultCallback callback) {
|
||||
if (!(list instanceof StoreObject))
|
||||
return;
|
||||
final StoreObject gtasksList = (StoreObject) list;
|
||||
if (!GtasksList.TYPE.equals(gtasksList.getValue(StoreObject.TYPE)))
|
||||
return;
|
||||
|
||||
callback.started();
|
||||
callback.incrementMax(100);
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
callback.incrementProgress(50);
|
||||
try {
|
||||
String authToken = getValidatedAuthToken();
|
||||
callback.incrementProgress(25);
|
||||
final GtasksInvoker service = new GtasksInvoker(authToken);
|
||||
synchronizeListHelper(gtasksList, service, callback);
|
||||
} finally {
|
||||
callback.incrementProgress(25);
|
||||
callback.finished();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private String getValidatedAuthToken() {
|
||||
String authToken = gtasksPreferenceService.getToken();
|
||||
try {
|
||||
authToken = GtasksTokenValidator.validateAuthToken(ContextManager.getContext(), authToken);
|
||||
if (authToken != null)
|
||||
gtasksPreferenceService.setToken(authToken);
|
||||
} catch (GoogleTasksException e) {
|
||||
authToken = null;
|
||||
}
|
||||
return authToken;
|
||||
}
|
||||
|
||||
|
||||
private void synchronizeListHelper(StoreObject list, GtasksInvoker invoker, SyncResultCallback callback) {
|
||||
// Do stuff
|
||||
String listId = list.getValue(GtasksList.REMOTE_ID);
|
||||
long lastSyncDate;
|
||||
if (list.containsNonNullValue(GtasksList.LAST_SYNC)) {
|
||||
lastSyncDate = list.getValue(GtasksList.LAST_SYNC);
|
||||
} else {
|
||||
lastSyncDate = 0;
|
||||
}
|
||||
boolean includeDeletedAndHidden = lastSyncDate != 0;
|
||||
try {
|
||||
Tasks taskList = invoker.getAllGtasksFromListId(listId, includeDeletedAndHidden, includeDeletedAndHidden, lastSyncDate);
|
||||
List<com.google.api.services.tasks.model.Task> tasks = taskList.getItems();
|
||||
if (tasks != null) {
|
||||
callback.incrementMax(tasks.size() * 10);
|
||||
for (com.google.api.services.tasks.model.Task t : tasks) {
|
||||
GtasksTaskContainer container = parseRemoteTask(t, listId);
|
||||
gtasksMetadataService.findLocalMatch(container);
|
||||
container.gtaskMetadata.setValue(GtasksMetadata.GTASKS_ORDER, Long.parseLong(t.getPosition()));
|
||||
container.gtaskMetadata.setValue(GtasksMetadata.PARENT_TASK, gtasksMetadataService.localIdForGtasksId(t.getParent()));
|
||||
container.gtaskMetadata.setValue(GtasksMetadata.LAST_SYNC, DateUtilities.now());
|
||||
write(container);
|
||||
callback.incrementProgress(10);
|
||||
}
|
||||
list.setValue(GtasksList.LAST_SYNC, DateUtilities.now());
|
||||
storeObjectDao.persist(list);
|
||||
|
||||
gtasksTaskListUpdater.correctOrderAndIndentForList(listId);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Stuff
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a task container for the given remote task
|
||||
* @throws JSONException */
|
||||
private GtasksTaskContainer parseRemoteTask(com.google.api.services.tasks.model.Task remoteTask, String listId) {
|
||||
Task task = new Task();
|
||||
|
||||
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
|
||||
|
||||
task.setValue(Task.TITLE, remoteTask.getTitle());
|
||||
task.setValue(Task.CREATION_DATE, DateUtilities.now());
|
||||
task.setValue(Task.COMPLETION_DATE, GtasksApiUtilities.gtasksCompletedTimeToUnixTime(remoteTask.getCompleted(), 0));
|
||||
if (remoteTask.getDeleted() == null || !remoteTask.getDeleted().booleanValue())
|
||||
task.setValue(Task.DELETION_DATE, 0L);
|
||||
else if (remoteTask.getDeleted().booleanValue())
|
||||
task.setValue(Task.DELETION_DATE, DateUtilities.now());
|
||||
if (remoteTask.getHidden() != null && remoteTask.getHidden().booleanValue())
|
||||
task.setValue(Task.DELETION_DATE, DateUtilities.now());
|
||||
|
||||
long dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0);
|
||||
long createdDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||
task.setValue(Task.DUE_DATE, createdDate);
|
||||
task.setValue(Task.NOTES, remoteTask.getNotes());
|
||||
|
||||
Metadata gtasksMetadata = GtasksMetadata.createEmptyMetadata(AbstractModel.NO_ID);
|
||||
gtasksMetadata.setValue(GtasksMetadata.ID, remoteTask.getId());
|
||||
gtasksMetadata.setValue(GtasksMetadata.LIST_ID, listId);
|
||||
|
||||
GtasksTaskContainer container = new GtasksTaskContainer(task, metadata,
|
||||
gtasksMetadata);
|
||||
return container;
|
||||
}
|
||||
|
||||
private void write(GtasksTaskContainer task) throws IOException {
|
||||
// merge astrid dates with google dates
|
||||
if(task.task.isSaved()) {
|
||||
Task local = PluginServices.getTaskService().fetchById(task.task.getId(), Task.DUE_DATE, Task.COMPLETION_DATE);
|
||||
mergeDates(task.task, local);
|
||||
if(task.task.isCompleted() && !local.isCompleted())
|
||||
StatisticsService.reportEvent(StatisticsConstants.GTASKS_TASK_COMPLETED);
|
||||
} else { // Set default reminders for remotely created tasks
|
||||
TaskDao.setDefaultReminders(task.task);
|
||||
}
|
||||
if (!TextUtils.isEmpty(task.task.getValue(Task.TITLE))) {
|
||||
Flags.set(Flags.GTASKS_SUPPRESS_SYNC);
|
||||
gtasksMetadataService.saveTaskAndMetadata(task);
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeDates(Task remote, Task local) {
|
||||
if(remote.hasDueDate() && local.hasDueTime()) {
|
||||
Date newDate = new Date(remote.getValue(Task.DUE_DATE));
|
||||
Date oldDate = new Date(local.getValue(Task.DUE_DATE));
|
||||
newDate.setHours(oldDate.getHours());
|
||||
newDate.setMinutes(oldDate.getMinutes());
|
||||
newDate.setSeconds(oldDate.getSeconds());
|
||||
long setDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME,
|
||||
newDate.getTime());
|
||||
remote.setValue(Task.DUE_DATE, setDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue