Remove GtasksMetadataService

pull/437/head
Alex Baker 10 years ago
parent 7c84c3c1b6
commit 4ba4ce9ba4

@ -22,7 +22,6 @@ import javax.inject.Inject;
@SuppressWarnings("nls") @SuppressWarnings("nls")
public class GtasksIndentActionTest extends DatabaseTestCase { public class GtasksIndentActionTest extends DatabaseTestCase {
@Inject GtasksMetadataService gtasksMetadataService;
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject GtasksTaskListUpdater gtasksTaskListUpdater; @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
@Inject MetadataDao metadataDao; @Inject MetadataDao metadataDao;
@ -173,7 +172,7 @@ public class GtasksIndentActionTest extends DatabaseTestCase {
} }
private void thenExpectIndentationLevel(Task targetTask, int expected) { private void thenExpectIndentationLevel(Task targetTask, int expected) {
Metadata metadata = gtasksMetadataService.getActiveTaskMetadata(targetTask.getId()); Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(targetTask.getId(), GtasksMetadata.METADATA_KEY);
assertNotNull("task has metadata", metadata); assertNotNull("task has metadata", metadata);
int indentation = metadata.getValue(GtasksMetadata.INDENT); int indentation = metadata.getValue(GtasksMetadata.INDENT);
assertTrue("indentation: " + indentation, assertTrue("indentation: " + indentation,

@ -50,7 +50,6 @@ public class GtasksMetadataServiceTest extends DatabaseTestCase {
} }
@Inject GtasksTestPreferenceService preferences; @Inject GtasksTestPreferenceService preferences;
@Inject GtasksMetadataService gtasksMetadataService;
@Inject MetadataDao metadataDao; @Inject MetadataDao metadataDao;
@Inject TaskService taskService; @Inject TaskService taskService;
@Inject GtasksMetadata gtasksMetadata; @Inject GtasksMetadata gtasksMetadata;
@ -101,7 +100,7 @@ public class GtasksMetadataServiceTest extends DatabaseTestCase {
} }
private void whenSearchForMetadata() { private void whenSearchForMetadata() {
metadata = gtasksMetadataService.getActiveTaskMetadata(task.getId()); metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY);
} }
private Task taskWithMetadata(String id) { private Task taskWithMetadata(String id) {

@ -26,7 +26,6 @@ public class GtasksTaskListUpdaterTest extends DatabaseTestCase {
@Inject GtasksTaskListUpdater gtasksTaskListUpdater; @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject GtasksMetadataService gtasksMetadataService;
@Inject MetadataDao metadataDao; @Inject MetadataDao metadataDao;
@Inject TaskService taskService; @Inject TaskService taskService;
@Inject GtasksMetadata gtasksMetadata; @Inject GtasksMetadata gtasksMetadata;
@ -87,14 +86,14 @@ public class GtasksTaskListUpdaterTest extends DatabaseTestCase {
// --- helpers // --- helpers
private void thenExpectMetadataIndentAndOrder(Task task, long order, int indent) { private void thenExpectMetadataIndentAndOrder(Task task, long order, int indent) {
Metadata metadata = gtasksMetadataService.getActiveTaskMetadata(task.getId()); Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY);
assertNotNull("metadata was found", metadata); assertNotNull("metadata was found", metadata);
assertEquals("order", order, metadata.getValue(GtasksMetadata.ORDER).longValue()); assertEquals("order", order, metadata.getValue(GtasksMetadata.ORDER).longValue());
assertEquals("indentation", indent, (int)metadata.getValue(GtasksMetadata.INDENT)); assertEquals("indentation", indent, (int)metadata.getValue(GtasksMetadata.INDENT));
} }
private void thenExpectMetadataParent(Task task, Task expectedParent) { private void thenExpectMetadataParent(Task task, Task expectedParent) {
Metadata metadata = gtasksMetadataService.getActiveTaskMetadata(task.getId()); Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY);
long parent = metadata.getValue(GtasksMetadata.PARENT_TASK); long parent = metadata.getValue(GtasksMetadata.PARENT_TASK);
if(expectedParent == null) if(expectedParent == null)
assertEquals("Task " + task.getTitle() + " parent none", 0, parent); assertEquals("Task " + task.getTitle() + " parent none", 0, parent);

@ -25,7 +25,6 @@ public class GtasksTaskMovingTest extends DatabaseTestCase {
private static final int VALUE_UNSET = -1; private static final int VALUE_UNSET = -1;
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject GtasksMetadataService gtasksMetadataService;
@Inject GtasksTaskListUpdater gtasksTaskListUpdater; @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
@Inject MetadataDao metadataDao; @Inject MetadataDao metadataDao;
@Inject TaskService taskService; @Inject TaskService taskService;
@ -237,7 +236,7 @@ public class GtasksTaskMovingTest extends DatabaseTestCase {
} }
private void thenExpectMetadataOrderAndIndent(Task task, long order, int indent) { private void thenExpectMetadataOrderAndIndent(Task task, long order, int indent) {
Metadata metadata = gtasksMetadataService.getActiveTaskMetadata(task.getId()); Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY);
assertNotNull("metadata was found", metadata); assertNotNull("metadata was found", metadata);
assertEquals("order", order, metadata.getValue(GtasksMetadata.ORDER).longValue()); assertEquals("order", order, metadata.getValue(GtasksMetadata.ORDER).longValue());
assertEquals("indentation", indent, (int)metadata.getValue(GtasksMetadata.INDENT)); assertEquals("indentation", indent, (int)metadata.getValue(GtasksMetadata.INDENT));

@ -1,229 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.gtasks;
import android.content.ContentValues;
import android.text.TextUtils;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Callback;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.sync.GtasksTaskContainer;
import com.todoroo.astrid.gtasks.OrderedMetadataListUpdater.OrderedListIterator;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Service for working with GTasks metadata
*
* @author Tim Su <tim@todoroo.com>
*
*/
@Singleton
public final class GtasksMetadataService {
private final TaskDao taskDao;
private final MetadataDao metadataDao;
@Inject
public GtasksMetadataService(TaskDao taskDao, MetadataDao metadataDao) {
this.taskDao = taskDao;
this.metadataDao = metadataDao;
}
/**
* Clears metadata information. Used when user logs out of sync provider
*/
public void clearMetadata() {
metadataDao.deleteWhere(Metadata.KEY.eq(GtasksMetadata.METADATA_KEY));
}
/**
* Saves a task and its metadata
*/
public void saveTaskAndMetadata(GtasksTaskContainer task) {
task.prepareForSaving();
taskDao.save(task.task);
synchronizeMetadata(task.task.getId(), task.metadata, GtasksMetadata.METADATA_KEY);
}
/**
* Reads metadata out of a task
* @return null if no metadata found
*/
public Metadata getActiveTaskMetadata(long taskId) {
return metadataDao.getFirst(Query.select(Metadata.PROPERTIES).where(Criterion.and(
MetadataCriteria.byTaskAndwithKey(taskId, GtasksMetadata.METADATA_KEY),
MetadataCriteria.isActive())));
}
public List<Metadata> getDeleted(long taskId) {
return metadataDao.toList(Criterion.and(
MetadataCriteria.byTaskAndwithKey(taskId, GtasksMetadata.METADATA_KEY),
MetadataCriteria.isDeleted()));
}
/**
* Synchronize metadata for given task id. Deletes rows in database that
* are not identical to those in the metadata list, creates rows that
* have no match.
*
* @param taskId id of task to perform synchronization on
* @param metadata list of new metadata items to save
* @param metadataKey metadata key
*/
private void synchronizeMetadata(long taskId, ArrayList<Metadata> metadata, String metadataKey) {
final Set<ContentValues> newMetadataValues = new HashSet<>();
for(Metadata metadatum : metadata) {
metadatum.setTask(taskId);
metadatum.clearValue(Metadata.ID);
newMetadataValues.add(metadatum.getMergedValues());
}
metadataDao.byTaskAndKey(taskId, metadataKey, new Callback<Metadata>() {
@Override
public void apply(Metadata item) {
long id = item.getId();
// clear item id when matching with incoming values
item.clearValue(Metadata.ID);
ContentValues itemMergedValues = item.getMergedValues();
if(newMetadataValues.contains(itemMergedValues)) {
newMetadataValues.remove(itemMergedValues);
} else {
// not matched. cut it
metadataDao.delete(id);
}
}
});
// everything that remains shall be written
for(ContentValues values : newMetadataValues) {
Metadata item = new Metadata();
item.mergeWith(values);
metadataDao.persist(item);
}
}
public synchronized void findLocalMatch(GtasksTaskContainer remoteTask) {
if(remoteTask.task.getId() != Task.NO_ID) {
return;
}
Metadata metadata = getMetadataByGtaskId(remoteTask.gtaskMetadata.getValue(GtasksMetadata.ID));
if (metadata != null) {
remoteTask.task.setId(metadata.getValue(Metadata.TASK));
remoteTask.task.setUuid(taskDao.uuidFromLocalId(remoteTask.task.getId()));
remoteTask.gtaskMetadata = metadata;
}
}
public long localIdForGtasksId(String gtasksId) {
Metadata metadata = getMetadataByGtaskId(gtasksId);
return metadata == null ? AbstractModel.NO_ID : metadata.getTask();
}
private Metadata getMetadataByGtaskId(String gtaskId) {
return metadataDao.getFirst(Query.select(Metadata.PROPERTIES).where(Criterion.and(
Metadata.KEY.eq(GtasksMetadata.METADATA_KEY),
GtasksMetadata.ID.eq(gtaskId))));
}
// --- list iterating helpers
public void iterateThroughList(GtasksList list, OrderedListIterator iterator) {
String listId = list.getRemoteId();
iterateThroughList(listId, iterator, 0, false);
}
private void iterateThroughList(String listId, final OrderedListIterator iterator, long startAtOrder, boolean reverse) {
Field orderField = Functions.cast(GtasksMetadata.ORDER, "LONG");
Order order = reverse ? Order.desc(orderField) : Order.asc(orderField);
Criterion startAtCriterion = reverse ? Functions.cast(GtasksMetadata.ORDER, "LONG").lt(startAtOrder) :
Functions.cast(GtasksMetadata.ORDER, "LONG").gt(startAtOrder - 1);
Query query = Query.select(Metadata.PROPERTIES).where(Criterion.and(
MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY),
GtasksMetadata.LIST_ID.eq(listId),
startAtCriterion)).
orderBy(order);
metadataDao.query(query, new Callback<Metadata>() {
@Override
public void apply(Metadata entry) {
long taskId = entry.getValue(Metadata.TASK);
Metadata metadata = getActiveTaskMetadata(taskId);
if(metadata != null) {
iterator.processTask(taskId, metadata);
}
}
});
}
/**
* Gets the remote id string of the parent task
*/
public String getRemoteParentId(Metadata gtasksMetadata) {
String parent = null;
if (gtasksMetadata.containsNonNullValue(GtasksMetadata.PARENT_TASK)) {
long parentId = gtasksMetadata.getValue(GtasksMetadata.PARENT_TASK);
Metadata parentMetadata = getActiveTaskMetadata(parentId);
if (parentMetadata != null && parentMetadata.containsNonNullValue(GtasksMetadata.ID)) {
parent = parentMetadata.getValue(GtasksMetadata.ID);
if (TextUtils.isEmpty(parent)) {
parent = null;
}
}
}
return parent;
}
/**
* Gets the remote id string of the previous sibling task
*/
public String getRemoteSiblingId(String listId, Metadata gtasksMetadata) {
final AtomicInteger indentToMatch = new AtomicInteger(gtasksMetadata.getValue(GtasksMetadata.INDENT));
final AtomicLong parentToMatch = new AtomicLong(gtasksMetadata.getValue(GtasksMetadata.PARENT_TASK));
final AtomicReference<String> sibling = new AtomicReference<>();
OrderedListIterator iterator = new OrderedListIterator() {
@Override
public void processTask(long taskId, Metadata metadata) {
Task t = taskDao.fetch(taskId, Task.TITLE, Task.DELETION_DATE);
if (t == null || t.isDeleted()) {
return;
}
int currIndent = metadata.getValue(GtasksMetadata.INDENT);
long currParent = metadata.getValue(GtasksMetadata.PARENT_TASK);
if (currIndent == indentToMatch.get() && currParent == parentToMatch.get()) {
if (sibling.get() == null) {
sibling.set(metadata.getValue(GtasksMetadata.ID));
}
}
}
};
this.iterateThroughList(listId, iterator, gtasksMetadata.getValue(GtasksMetadata.ORDER), true);
return sibling.get();
}
}

@ -42,15 +42,12 @@ public class GtasksTaskListUpdater extends OrderedMetadataListUpdater<GtasksList
final HashMap<Long, String> localToRemoteIdMap = final HashMap<Long, String> localToRemoteIdMap =
new HashMap<>(); new HashMap<>();
private final GtasksMetadataService gtasksMetadataService;
private final GtasksSyncService gtasksSyncService; private final GtasksSyncService gtasksSyncService;
private final MetadataDao metadataDao; private final MetadataDao metadataDao;
@Inject @Inject
public GtasksTaskListUpdater(GtasksMetadataService gtasksMetadataService, GtasksSyncService gtasksSyncService, public GtasksTaskListUpdater(GtasksSyncService gtasksSyncService, MetadataDao metadataDao) {
MetadataDao metadataDao) {
super(metadataDao); super(metadataDao);
this.gtasksMetadataService = gtasksMetadataService;
this.gtasksSyncService = gtasksSyncService; this.gtasksSyncService = gtasksSyncService;
this.metadataDao = metadataDao; this.metadataDao = metadataDao;
} }
@ -74,7 +71,7 @@ public class GtasksTaskListUpdater extends OrderedMetadataListUpdater<GtasksList
@Override @Override
protected Metadata getTaskMetadata(long taskId) { protected Metadata getTaskMetadata(long taskId) {
return gtasksMetadataService.getActiveTaskMetadata(taskId); return metadataDao.getFirstActiveByTaskAndKey(taskId, GtasksMetadata.METADATA_KEY);
} }
@Override @Override
protected Metadata createEmptyMetadata(GtasksList list, long taskId) { protected Metadata createEmptyMetadata(GtasksList list, long taskId) {
@ -90,7 +87,8 @@ public class GtasksTaskListUpdater extends OrderedMetadataListUpdater<GtasksList
@Override @Override
protected void iterateThroughList(GtasksList list, OrderedListIterator iterator) { protected void iterateThroughList(GtasksList list, OrderedListIterator iterator) {
gtasksMetadataService.iterateThroughList(list, iterator); String listId = list.getRemoteId();
gtasksSyncService.iterateThroughList(listId, iterator, 0, false);
} }
@Override @Override
@ -131,7 +129,7 @@ public class GtasksTaskListUpdater extends OrderedMetadataListUpdater<GtasksList
final AtomicLong previousTask = new AtomicLong(Task.NO_ID); final AtomicLong previousTask = new AtomicLong(Task.NO_ID);
final AtomicInteger previousIndent = new AtomicInteger(-1); final AtomicInteger previousIndent = new AtomicInteger(-1);
gtasksMetadataService.iterateThroughList(list, new OrderedListIterator() { iterateThroughList(list, new OrderedListIterator() {
@Override @Override
public void processTask(long taskId, Metadata metadata) { public void processTask(long taskId, Metadata metadata) {
int indent = metadata.getValue(GtasksMetadata.INDENT); int indent = metadata.getValue(GtasksMetadata.INDENT);

@ -8,6 +8,12 @@ package com.todoroo.astrid.gtasks.sync;
import android.content.ContentValues; import android.content.ContentValues;
import android.text.TextUtils; import android.text.TextUtils;
import com.todoroo.andlib.data.Callback;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.MetadataDao;
@ -16,8 +22,8 @@ import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksMetadata; import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksMetadataService;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.OrderedMetadataListUpdater;
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities; import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
import com.todoroo.astrid.gtasks.api.GtasksInvoker; import com.todoroo.astrid.gtasks.api.GtasksInvoker;
import com.todoroo.astrid.gtasks.api.HttpNotFoundException; import com.todoroo.astrid.gtasks.api.HttpNotFoundException;
@ -26,7 +32,11 @@ import com.todoroo.astrid.gtasks.api.MoveRequest;
import org.tasks.gtasks.SyncAdapterHelper; import org.tasks.gtasks.SyncAdapterHelper;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue; 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 javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -39,7 +49,6 @@ public class GtasksSyncService {
private static final String DEFAULT_LIST = "@default"; //$NON-NLS-1$ private static final String DEFAULT_LIST = "@default"; //$NON-NLS-1$
private final MetadataDao metadataDao; private final MetadataDao metadataDao;
private final GtasksMetadataService gtasksMetadataService;
private final TaskDao taskDao; private final TaskDao taskDao;
private final GtasksPreferenceService gtasksPreferenceService; private final GtasksPreferenceService gtasksPreferenceService;
private final GtasksMetadata gtasksMetadataFactory; private final GtasksMetadata gtasksMetadataFactory;
@ -48,12 +57,11 @@ public class GtasksSyncService {
private final SyncAdapterHelper syncAdapterHelper; private final SyncAdapterHelper syncAdapterHelper;
@Inject @Inject
public GtasksSyncService(MetadataDao metadataDao, GtasksMetadataService gtasksMetadataService, public GtasksSyncService(MetadataDao metadataDao, TaskDao taskDao,
TaskDao taskDao, GtasksPreferenceService gtasksPreferenceService, GtasksPreferenceService gtasksPreferenceService,
GtasksMetadata gtasksMetadataFactory, GtasksInvoker gtasksInvoker, GtasksMetadata gtasksMetadataFactory, GtasksInvoker gtasksInvoker,
SyncAdapterHelper syncAdapterHelper) { SyncAdapterHelper syncAdapterHelper) {
this.metadataDao = metadataDao; this.metadataDao = metadataDao;
this.gtasksMetadataService = gtasksMetadataService;
this.taskDao = taskDao; this.taskDao = taskDao;
this.gtasksPreferenceService = gtasksPreferenceService; this.gtasksPreferenceService = gtasksPreferenceService;
this.gtasksMetadataFactory = gtasksMetadataFactory; this.gtasksMetadataFactory = gtasksMetadataFactory;
@ -152,12 +160,12 @@ public class GtasksSyncService {
* Synchronize with server when data changes * Synchronize with server when data changes
*/ */
public void pushTaskOnSave(Task task, ContentValues values, GtasksInvoker invoker) throws IOException { public void pushTaskOnSave(Task task, ContentValues values, GtasksInvoker invoker) throws IOException {
for (Metadata deleted : gtasksMetadataService.getDeleted(task.getId())) { for (Metadata deleted : getDeleted(task.getId())) {
gtasksInvoker.deleteGtask(deleted.getValue(GtasksMetadata.LIST_ID), deleted.getValue(GtasksMetadata.ID)); gtasksInvoker.deleteGtask(deleted.getValue(GtasksMetadata.LIST_ID), deleted.getValue(GtasksMetadata.ID));
metadataDao.delete(deleted.getId()); metadataDao.delete(deleted.getId());
} }
Metadata gtasksMetadata = gtasksMetadataService.getActiveTaskMetadata(task.getId()); Metadata gtasksMetadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY);
com.google.api.services.tasks.model.Task remoteModel; com.google.api.services.tasks.model.Task remoteModel;
boolean newlyCreated = false; boolean newlyCreated = false;
@ -232,8 +240,8 @@ public class GtasksSyncService {
return; return;
} }
} else { } else {
String parent = gtasksMetadataService.getRemoteParentId(gtasksMetadata); String parent = getRemoteParentId(gtasksMetadata);
String priorSibling = gtasksMetadataService.getRemoteSiblingId(listId, gtasksMetadata); String priorSibling = getRemoteSiblingId(listId, gtasksMetadata);
com.google.api.services.tasks.model.Task created = invoker.createGtask(listId, remoteModel, parent, priorSibling); com.google.api.services.tasks.model.Task created = invoker.createGtask(listId, remoteModel, parent, priorSibling);
@ -258,8 +266,8 @@ public class GtasksSyncService {
String taskId = model.getValue(GtasksMetadata.ID); String taskId = model.getValue(GtasksMetadata.ID);
String listId = model.getValue(GtasksMetadata.LIST_ID); String listId = model.getValue(GtasksMetadata.LIST_ID);
String parent = gtasksMetadataService.getRemoteParentId(model); String parent = getRemoteParentId(model);
String priorSibling = gtasksMetadataService.getRemoteSiblingId(listId, model); String priorSibling = getRemoteSiblingId(listId, model);
MoveRequest move = new MoveRequest(invoker, taskId, listId, parent, priorSibling); MoveRequest move = new MoveRequest(invoker, taskId, listId, parent, priorSibling);
com.google.api.services.tasks.model.Task result = move.push(); com.google.api.services.tasks.model.Task result = move.push();
@ -270,4 +278,81 @@ public class GtasksSyncService {
metadataDao.saveExisting(model); metadataDao.saveExisting(model);
} }
} }
public void iterateThroughList(String listId, final OrderedMetadataListUpdater.OrderedListIterator iterator, long startAtOrder, boolean reverse) {
Field orderField = Functions.cast(GtasksMetadata.ORDER, "LONG");
Order order = reverse ? Order.desc(orderField) : Order.asc(orderField);
Criterion startAtCriterion = reverse ? Functions.cast(GtasksMetadata.ORDER, "LONG").lt(startAtOrder) :
Functions.cast(GtasksMetadata.ORDER, "LONG").gt(startAtOrder - 1);
Query query = Query.select(Metadata.PROPERTIES).where(Criterion.and(
MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY),
GtasksMetadata.LIST_ID.eq(listId),
startAtCriterion)).
orderBy(order);
metadataDao.query(query, new Callback<Metadata>() {
@Override
public void apply(Metadata entry) {
long taskId = entry.getValue(Metadata.TASK);
Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(taskId, GtasksMetadata.METADATA_KEY);
if(metadata != null) {
iterator.processTask(taskId, metadata);
}
}
});
}
private List<Metadata> getDeleted(long taskId) {
return metadataDao.toList(Criterion.and(
MetadataDao.MetadataCriteria.byTaskAndwithKey(taskId, GtasksMetadata.METADATA_KEY),
MetadataDao.MetadataCriteria.isDeleted()));
}
/**
* Gets the remote id string of the parent task
*/
private String getRemoteParentId(Metadata gtasksMetadata) {
String parent = null;
if (gtasksMetadata.containsNonNullValue(GtasksMetadata.PARENT_TASK)) {
long parentId = gtasksMetadata.getValue(GtasksMetadata.PARENT_TASK);
Metadata parentMetadata = metadataDao.getFirstActiveByTaskAndKey(parentId, GtasksMetadata.METADATA_KEY);
if (parentMetadata != null && parentMetadata.containsNonNullValue(GtasksMetadata.ID)) {
parent = parentMetadata.getValue(GtasksMetadata.ID);
if (TextUtils.isEmpty(parent)) {
parent = null;
}
}
}
return parent;
}
/**
* Gets the remote id string of the previous sibling task
*/
private String getRemoteSiblingId(String listId, Metadata gtasksMetadata) {
final AtomicInteger indentToMatch = new AtomicInteger(gtasksMetadata.getValue(GtasksMetadata.INDENT));
final AtomicLong parentToMatch = new AtomicLong(gtasksMetadata.getValue(GtasksMetadata.PARENT_TASK));
final AtomicReference<String> sibling = new AtomicReference<>();
OrderedMetadataListUpdater.OrderedListIterator iterator = new OrderedMetadataListUpdater.OrderedListIterator() {
@Override
public void processTask(long taskId, Metadata metadata) {
Task t = taskDao.fetch(taskId, Task.TITLE, Task.DELETION_DATE);
if (t == null || t.isDeleted()) {
return;
}
int currIndent = metadata.getValue(GtasksMetadata.INDENT);
long currParent = metadata.getValue(GtasksMetadata.PARENT_TASK);
if (currIndent == indentToMatch.get() && currParent == parentToMatch.get()) {
if (sibling.get() == null) {
sibling.set(metadata.getValue(GtasksMetadata.ID));
}
}
}
};
iterateThroughList(listId, iterator, gtasksMetadata.getValue(GtasksMetadata.ORDER), true);
return sibling.get();
}
} }

@ -3,7 +3,9 @@ package org.tasks.activities;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import com.todoroo.astrid.gtasks.GtasksMetadataService; import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import org.tasks.R; import org.tasks.R;
@ -17,7 +19,7 @@ public class ClearGtaskDataActivity extends InjectingAppCompatActivity {
@Inject DialogBuilder dialogBuilder; @Inject DialogBuilder dialogBuilder;
@Inject GtasksPreferenceService gtasksPreferenceService; @Inject GtasksPreferenceService gtasksPreferenceService;
@Inject GtasksMetadataService gtasksMetadataService; @Inject MetadataDao metadataDao;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -29,7 +31,7 @@ public class ClearGtaskDataActivity extends InjectingAppCompatActivity {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
gtasksPreferenceService.clearLastSyncDate(); gtasksPreferenceService.clearLastSyncDate();
gtasksPreferenceService.setUserName(null); gtasksPreferenceService.setUserName(null);
gtasksMetadataService.clearMetadata(); metadataDao.deleteWhere(Metadata.KEY.eq(GtasksMetadata.METADATA_KEY));
setResult(RESULT_OK); setResult(RESULT_OK);
} }
}) })

@ -19,6 +19,7 @@ package org.tasks.gtasks;
import android.accounts.Account; import android.accounts.Account;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.SyncResult; import android.content.SyncResult;
import android.os.Bundle; import android.os.Bundle;
@ -28,6 +29,7 @@ import com.google.api.services.tasks.model.TaskList;
import com.google.api.services.tasks.model.TaskLists; import com.google.api.services.tasks.model.TaskLists;
import com.google.api.services.tasks.model.Tasks; import com.google.api.services.tasks.model.Tasks;
import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Callback;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Join;
@ -42,7 +44,6 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList; import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksListService; import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata; import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksMetadataService;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.GtasksTaskListUpdater; import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
import com.todoroo.astrid.gtasks.api.GtasksInvoker; import com.todoroo.astrid.gtasks.api.GtasksInvoker;
@ -60,7 +61,9 @@ import org.tasks.time.DateTime;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
@ -85,10 +88,11 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
@Inject StoreObjectDao storeObjectDao; @Inject StoreObjectDao storeObjectDao;
@Inject GtasksSyncService gtasksSyncService; @Inject GtasksSyncService gtasksSyncService;
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject GtasksMetadataService gtasksMetadataService;
@Inject GtasksTaskListUpdater gtasksTaskListUpdater; @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
@Inject Preferences preferences; @Inject Preferences preferences;
@Inject GtasksInvoker gtasksInvoker; @Inject GtasksInvoker gtasksInvoker;
@Inject TaskDao taskDao;
@Inject MetadataDao metadataDao;
public GoogleTaskSyncAdapter(Context context, boolean autoInitialize) { public GoogleTaskSyncAdapter(Context context, boolean autoInitialize) {
@ -234,9 +238,9 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
if (!tasks.isEmpty()) { if (!tasks.isEmpty()) {
for (com.google.api.services.tasks.model.Task t : tasks) { for (com.google.api.services.tasks.model.Task t : tasks) {
GtasksTaskContainer container = new GtasksTaskContainer(t, listId, GtasksMetadata.createEmptyMetadataWithoutList(AbstractModel.NO_ID)); GtasksTaskContainer container = new GtasksTaskContainer(t, listId, GtasksMetadata.createEmptyMetadataWithoutList(AbstractModel.NO_ID));
gtasksMetadataService.findLocalMatch(container); findLocalMatch(container);
container.gtaskMetadata.setValue(GtasksMetadata.GTASKS_ORDER, Long.parseLong(t.getPosition())); container.gtaskMetadata.setValue(GtasksMetadata.GTASKS_ORDER, Long.parseLong(t.getPosition()));
container.gtaskMetadata.setValue(GtasksMetadata.PARENT_TASK, gtasksMetadataService.localIdForGtasksId(t.getParent())); container.gtaskMetadata.setValue(GtasksMetadata.PARENT_TASK, localIdForGtasksId(t.getParent()));
container.gtaskMetadata.setValue(GtasksMetadata.LAST_SYNC, DateUtilities.now() + 1000L); container.gtaskMetadata.setValue(GtasksMetadata.LAST_SYNC, DateUtilities.now() + 1000L);
write(container); write(container);
lastSyncDate = Math.max(lastSyncDate, container.getUpdateTime()); lastSyncDate = Math.max(lastSyncDate, container.getUpdateTime());
@ -250,6 +254,29 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
} }
} }
private long localIdForGtasksId(String gtasksId) {
Metadata metadata = getMetadataByGtaskId(gtasksId);
return metadata == null ? AbstractModel.NO_ID : metadata.getTask();
}
private void findLocalMatch(GtasksTaskContainer remoteTask) {
if(remoteTask.task.getId() != Task.NO_ID) {
return;
}
Metadata metadata = getMetadataByGtaskId(remoteTask.gtaskMetadata.getValue(GtasksMetadata.ID));
if (metadata != null) {
remoteTask.task.setId(metadata.getValue(Metadata.TASK));
remoteTask.task.setUuid(taskDao.uuidFromLocalId(remoteTask.task.getId()));
remoteTask.gtaskMetadata = metadata;
}
}
private Metadata getMetadataByGtaskId(String gtaskId) {
return metadataDao.getFirst(Query.select(Metadata.PROPERTIES).where(Criterion.and(
Metadata.KEY.eq(GtasksMetadata.METADATA_KEY),
GtasksMetadata.ID.eq(gtaskId))));
}
private void write(GtasksTaskContainer task) { private void write(GtasksTaskContainer task) {
// merge astrid dates with google dates // merge astrid dates with google dates
@ -269,10 +296,62 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
if (!TextUtils.isEmpty(task.task.getTitle())) { if (!TextUtils.isEmpty(task.task.getTitle())) {
task.task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true); task.task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
task.task.putTransitory(TaskDao.TRANS_SUPPRESS_REFRESH, true); task.task.putTransitory(TaskDao.TRANS_SUPPRESS_REFRESH, true);
gtasksMetadataService.saveTaskAndMetadata(task); saveTaskAndMetadata(task);
} }
} }
/**
* Saves a task and its metadata
*/
private void saveTaskAndMetadata(GtasksTaskContainer task) {
task.prepareForSaving();
taskDao.save(task.task);
synchronizeMetadata(task.task.getId(), task.metadata, GtasksMetadata.METADATA_KEY);
}
/**
* Synchronize metadata for given task id. Deletes rows in database that
* are not identical to those in the metadata list, creates rows that
* have no match.
*
* @param taskId id of task to perform synchronization on
* @param metadata list of new metadata items to save
* @param metadataKey metadata key
*/
private void synchronizeMetadata(long taskId, ArrayList<Metadata> metadata, String metadataKey) {
final Set<ContentValues> newMetadataValues = new HashSet<>();
for(Metadata metadatum : metadata) {
metadatum.setTask(taskId);
metadatum.clearValue(Metadata.ID);
newMetadataValues.add(metadatum.getMergedValues());
}
metadataDao.byTaskAndKey(taskId, metadataKey, new Callback<Metadata>() {
@Override
public void apply(Metadata item) {
long id = item.getId();
// clear item id when matching with incoming values
item.clearValue(Metadata.ID);
ContentValues itemMergedValues = item.getMergedValues();
if(newMetadataValues.contains(itemMergedValues)) {
newMetadataValues.remove(itemMergedValues);
} else {
// not matched. cut it
metadataDao.delete(id);
}
}
});
// everything that remains shall be written
for(ContentValues values : newMetadataValues) {
Metadata item = new Metadata();
item.mergeWith(values);
metadataDao.persist(item);
}
}
static void mergeDates(Task remote, Task local) { static void mergeDates(Task remote, Task local) {
if (remote.hasDueDate() && local.hasDueTime()) { if (remote.hasDueDate() && local.hasDueTime()) {
DateTime oldDate = newDateTime(local.getDueDate()); DateTime oldDate = newDateTime(local.getDueDate());

@ -16,7 +16,6 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList; import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksListService; import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata; import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksMetadataService;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import org.tasks.R; import org.tasks.R;
@ -45,7 +44,6 @@ public class GoogleTaskListFragment extends TaskEditControlFragment {
@Inject GtasksPreferenceService gtasksPreferenceService; @Inject GtasksPreferenceService gtasksPreferenceService;
@Inject GtasksListService gtasksListService; @Inject GtasksListService gtasksListService;
@Inject GtasksMetadataService gtasksMetadataService;
@Inject MetadataDao metadataDao; @Inject MetadataDao metadataDao;
@Inject Tracker tracker; @Inject Tracker tracker;
@ -69,7 +67,7 @@ public class GoogleTaskListFragment extends TaskEditControlFragment {
selectedList = new GtasksList(selectedStoreObject); selectedList = new GtasksList(selectedStoreObject);
} }
} else { } else {
Metadata metadata = gtasksMetadataService.getActiveTaskMetadata(taskId); Metadata metadata = metadataDao.getFirstActiveByTaskAndKey(taskId, GtasksMetadata.METADATA_KEY);
if (metadata != null) { if (metadata != null) {
originalList = gtasksListService.getList(metadata.getValue(GtasksMetadata.LIST_ID)); originalList = gtasksListService.getList(metadata.getValue(GtasksMetadata.LIST_ID));
} }
@ -132,7 +130,7 @@ public class GoogleTaskListFragment extends TaskEditControlFragment {
return; return;
} }
Metadata taskMetadata = gtasksMetadataService.getActiveTaskMetadata(task.getId()); Metadata taskMetadata = metadataDao.getFirstActiveByTaskAndKey(task.getId(), GtasksMetadata.METADATA_KEY);
if (taskMetadata == null) { if (taskMetadata == null) {
taskMetadata = GtasksMetadata.createEmptyMetadataWithoutList(task.getId()); taskMetadata = GtasksMetadata.createEmptyMetadataWithoutList(task.getId());
} else if (!taskMetadata.getValue(GtasksMetadata.LIST_ID).equals(selectedList.getRemoteId())) { } else if (!taskMetadata.getValue(GtasksMetadata.LIST_ID).equals(selectedList.getRemoteId())) {

@ -48,6 +48,12 @@ public class MetadataDao {
return dao.getFirst(query); return dao.getFirst(query);
} }
public Metadata getFirstActiveByTaskAndKey(long taskId, String key) {
return getFirst(Query.select(Metadata.PROPERTIES).where(Criterion.and(
MetadataCriteria.byTaskAndwithKey(taskId, key),
MetadataCriteria.isActive())));
}
public int update(Criterion where, Metadata template) { public int update(Criterion where, Metadata template) {
return dao.update(where, template); return dao.update(where, template);
} }

Loading…
Cancel
Save