mirror of https://github.com/tasks/tasks
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
6.4 KiB
Java
206 lines
6.4 KiB
Java
/*
|
|
* Copyright (c) 2012 Todoroo Inc
|
|
*
|
|
* See the file "LICENSE" for the full license governing this code.
|
|
*/
|
|
|
|
package com.todoroo.astrid.gtasks.sync;
|
|
|
|
import android.text.TextUtils;
|
|
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
|
|
import com.todoroo.andlib.utility.AndroidUtilities;
|
|
import com.todoroo.astrid.dao.TaskDao;
|
|
import com.todoroo.astrid.data.Task;
|
|
import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
|
|
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
|
|
import com.todoroo.astrid.gtasks.api.MoveRequest;
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
import javax.inject.Inject;
|
|
import org.tasks.analytics.Tracker;
|
|
import org.tasks.data.GoogleTask;
|
|
import org.tasks.data.GoogleTaskDao;
|
|
import org.tasks.data.GoogleTaskList;
|
|
import org.tasks.data.GoogleTaskListDao;
|
|
import org.tasks.gtasks.GoogleAccountManager;
|
|
import org.tasks.gtasks.GtaskSyncAdapterHelper;
|
|
import org.tasks.injection.ApplicationScope;
|
|
import org.tasks.preferences.Preferences;
|
|
import timber.log.Timber;
|
|
|
|
@ApplicationScope
|
|
public class GtasksSyncService {
|
|
|
|
private final TaskDao taskDao;
|
|
private final Preferences preferences;
|
|
private final LinkedBlockingQueue<SyncOnSaveOperation> operationQueue =
|
|
new LinkedBlockingQueue<>();
|
|
private final GtaskSyncAdapterHelper gtaskSyncAdapterHelper;
|
|
private final Tracker tracker;
|
|
private final GoogleTaskDao googleTaskDao;
|
|
private final GoogleAccountManager googleAccountManager;
|
|
|
|
@Inject
|
|
public GtasksSyncService(
|
|
TaskDao taskDao,
|
|
Preferences preferences,
|
|
GtaskSyncAdapterHelper gtaskSyncAdapterHelper,
|
|
Tracker tracker,
|
|
GoogleTaskDao googleTaskDao,
|
|
GoogleTaskListDao googleTaskListDao,
|
|
GoogleAccountManager googleAccountManager) {
|
|
this.taskDao = taskDao;
|
|
this.preferences = preferences;
|
|
this.gtaskSyncAdapterHelper = gtaskSyncAdapterHelper;
|
|
this.tracker = tracker;
|
|
this.googleTaskDao = googleTaskDao;
|
|
this.googleAccountManager = googleAccountManager;
|
|
new OperationPushThread(operationQueue).start();
|
|
}
|
|
|
|
public void triggerMoveForMetadata(GoogleTaskList googleTaskList, GoogleTask googleTask) {
|
|
if (googleTask == null) {
|
|
return;
|
|
}
|
|
if (googleTask.isSuppressSync()) {
|
|
googleTask.setSuppressSync(false);
|
|
return;
|
|
}
|
|
if (preferences.isSyncOngoing()) {
|
|
return;
|
|
}
|
|
if (!gtaskSyncAdapterHelper.isEnabled()) {
|
|
return;
|
|
}
|
|
|
|
operationQueue.offer(new MoveOp(googleTaskList, googleTask));
|
|
}
|
|
|
|
private void pushMetadataOnSave(GoogleTask model, GtasksInvoker invoker) throws IOException {
|
|
AndroidUtilities.sleepDeep(1000L);
|
|
|
|
String taskId = model.getRemoteId();
|
|
String listId = model.getListId();
|
|
String parent = getRemoteParentId(model);
|
|
String priorSibling = getRemoteSiblingId(listId, model);
|
|
|
|
MoveRequest move = new MoveRequest(invoker, taskId, listId, parent, priorSibling);
|
|
com.google.api.services.tasks.model.Task result = move.push();
|
|
// Update order googleTask from result
|
|
if (result != null) {
|
|
model.setRemoteOrder(Long.parseLong(result.getPosition()));
|
|
model.setSuppressSync(true);
|
|
googleTaskDao.update(model);
|
|
}
|
|
}
|
|
|
|
public void iterateThroughList(
|
|
String listId,
|
|
final GtasksTaskListUpdater.OrderedListIterator iterator,
|
|
long startAtOrder,
|
|
boolean reverse) {
|
|
List<GoogleTask> tasks =
|
|
reverse
|
|
? googleTaskDao.getTasksFromReverse(listId, startAtOrder)
|
|
: googleTaskDao.getTasksFrom(listId, startAtOrder);
|
|
for (GoogleTask entry : tasks) {
|
|
iterator.processTask(entry.getTask(), entry);
|
|
}
|
|
}
|
|
|
|
/** Gets the remote id string of the parent task */
|
|
public String getRemoteParentId(GoogleTask googleTask) {
|
|
String parent = null;
|
|
long parentId = googleTask.getParent();
|
|
GoogleTask parentTask = googleTaskDao.getByTaskId(parentId);
|
|
if (parentTask != null) {
|
|
parent = parentTask.getRemoteId();
|
|
if (TextUtils.isEmpty(parent)) {
|
|
parent = null;
|
|
}
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
/** Gets the remote id string of the previous sibling task */
|
|
public String getRemoteSiblingId(String listId, GoogleTask gtasksMetadata) {
|
|
final AtomicInteger indentToMatch = new AtomicInteger(gtasksMetadata.getIndent());
|
|
final AtomicLong parentToMatch = new AtomicLong(gtasksMetadata.getParent());
|
|
final AtomicReference<String> sibling = new AtomicReference<>();
|
|
GtasksTaskListUpdater.OrderedListIterator iterator =
|
|
(taskId, googleTask) -> {
|
|
Task t = taskDao.fetch(taskId);
|
|
if (t == null || t.isDeleted()) {
|
|
return;
|
|
}
|
|
int currIndent = googleTask.getIndent();
|
|
long currParent = googleTask.getParent();
|
|
|
|
if (currIndent == indentToMatch.get() && currParent == parentToMatch.get()) {
|
|
if (sibling.get() == null) {
|
|
sibling.set(googleTask.getRemoteId());
|
|
}
|
|
}
|
|
};
|
|
|
|
iterateThroughList(listId, iterator, gtasksMetadata.getOrder(), true);
|
|
return sibling.get();
|
|
}
|
|
|
|
interface SyncOnSaveOperation {
|
|
|
|
void op() throws IOException;
|
|
}
|
|
|
|
private class MoveOp implements SyncOnSaveOperation {
|
|
|
|
final GoogleTask googleTask;
|
|
private final GoogleTaskList googleTaskList;
|
|
|
|
MoveOp(GoogleTaskList googleTaskList, GoogleTask googleTask) {
|
|
this.googleTaskList = googleTaskList;
|
|
this.googleTask = googleTask;
|
|
}
|
|
|
|
@Override
|
|
public void op() throws IOException {
|
|
GtasksInvoker invoker = new GtasksInvoker(googleTaskList.getAccount(), googleAccountManager);
|
|
pushMetadataOnSave(googleTask, invoker);
|
|
}
|
|
}
|
|
|
|
private class OperationPushThread extends Thread {
|
|
|
|
private final LinkedBlockingQueue<SyncOnSaveOperation> queue;
|
|
|
|
OperationPushThread(LinkedBlockingQueue<SyncOnSaveOperation> queue) {
|
|
this.queue = queue;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
//noinspection InfiniteLoopStatement
|
|
while (true) {
|
|
SyncOnSaveOperation op;
|
|
try {
|
|
op = queue.take();
|
|
} catch (InterruptedException e) {
|
|
Timber.e(e);
|
|
continue;
|
|
}
|
|
try {
|
|
op.op();
|
|
} catch (UserRecoverableAuthIOException ignored) {
|
|
|
|
} catch (IOException e) {
|
|
tracker.reportException(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|