Remove setValues

pull/618/head
Alex Baker 8 years ago
parent 29b9aea056
commit 8a2cbbd91a

@ -12,10 +12,6 @@ import org.tasks.time.DateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.TreeSet; import java.util.TreeSet;
import static com.todoroo.astrid.data.Task.COMPLETION_DATE;
import static com.todoroo.astrid.data.Task.DELETION_DATE;
import static com.todoroo.astrid.data.Task.DUE_DATE;
import static com.todoroo.astrid.data.Task.HIDE_UNTIL;
import static com.todoroo.astrid.data.Task.URGENCY_DAY_AFTER; import static com.todoroo.astrid.data.Task.URGENCY_DAY_AFTER;
import static com.todoroo.astrid.data.Task.URGENCY_IN_TWO_WEEKS; import static com.todoroo.astrid.data.Task.URGENCY_IN_TWO_WEEKS;
import static com.todoroo.astrid.data.Task.URGENCY_NEXT_MONTH; import static com.todoroo.astrid.data.Task.URGENCY_NEXT_MONTH;
@ -115,7 +111,7 @@ public class TaskTest {
@Test @Test
public void testTaskHasDueTime() { public void testTaskHasDueTime() {
Task task = new Task(); Task task = new Task();
task.setValue(DUE_DATE, 1388516076000L); task.setDueDate(1388516076000L);
assertTrue(task.hasDueTime()); assertTrue(task.hasDueTime());
assertTrue(task.hasDueDate()); assertTrue(task.hasDueDate());
} }
@ -123,7 +119,7 @@ public class TaskTest {
@Test @Test
public void testTaskHasDueDate() { public void testTaskHasDueDate() {
Task task = new Task(); Task task = new Task();
task.setValue(DUE_DATE, 1388469600000L); task.setDueDate(1388469600000L);
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertTrue(task.hasDueDate()); assertTrue(task.hasDueDate());
} }
@ -175,7 +171,7 @@ public class TaskTest {
@Test @Test
public void testTaskIsCompleted() { public void testTaskIsCompleted() {
Task task = new Task(); Task task = new Task();
task.setValue(COMPLETION_DATE, 1L); task.setCompletionDate(1L);
assertTrue(task.isCompleted()); assertTrue(task.isCompleted());
} }
@ -184,7 +180,7 @@ public class TaskTest {
final long now = currentTimeMillis(); final long now = currentTimeMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now).thawAfter(new Snippet() {{
Task task = new Task(); Task task = new Task();
task.setValue(HIDE_UNTIL, now); task.setHideUntil(now);
assertFalse(task.isHidden()); assertFalse(task.isHidden());
}}); }});
} }
@ -194,7 +190,7 @@ public class TaskTest {
final long now = currentTimeMillis(); final long now = currentTimeMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now).thawAfter(new Snippet() {{
Task task = new Task(); Task task = new Task();
task.setValue(HIDE_UNTIL, now + 1); task.setHideUntil(now + 1);
assertTrue(task.isHidden()); assertTrue(task.isHidden());
}}); }});
} }
@ -202,7 +198,7 @@ public class TaskTest {
@Test @Test
public void testTaskIsDeleted() { public void testTaskIsDeleted() {
Task task = new Task(); Task task = new Task();
task.setValue(DELETION_DATE, 1L); task.setDeletionDate(1L);
assertTrue(task.isDeleted()); assertTrue(task.isDeleted());
} }
@ -216,7 +212,7 @@ public class TaskTest {
final long now = currentTimeMillis(); final long now = currentTimeMillis();
freezeAt(now).thawAfter(new Snippet() {{ freezeAt(now).thawAfter(new Snippet() {{
Task task = new Task(); Task task = new Task();
task.setValue(DUE_DATE, now); task.setDueDate(now);
assertFalse(task.isOverdue()); assertFalse(task.isOverdue());
}}); }});
} }
@ -226,7 +222,7 @@ public class TaskTest {
final long dueDate = currentTimeMillis(); final long dueDate = currentTimeMillis();
freezeAt(dueDate + 1).thawAfter(new Snippet() {{ freezeAt(dueDate + 1).thawAfter(new Snippet() {{
Task task = new Task(); Task task = new Task();
task.setValue(DUE_DATE, dueDate); task.setDueDate(dueDate);
assertTrue(task.isOverdue()); assertTrue(task.isOverdue());
}}); }});
} }
@ -236,7 +232,7 @@ public class TaskTest {
final DateTime dueDate = new DateTime().startOfDay(); final DateTime dueDate = new DateTime().startOfDay();
freezeAt(dueDate.plusHours(12).minusMillis(1)).thawAfter(new Snippet() {{ freezeAt(dueDate.plusHours(12).minusMillis(1)).thawAfter(new Snippet() {{
Task task = new Task(); Task task = new Task();
task.setValue(DUE_DATE, dueDate.getMillis()); task.setDueDate(dueDate.getMillis());
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertFalse(task.isOverdue()); assertFalse(task.isOverdue());
}}); }});
@ -247,7 +243,7 @@ public class TaskTest {
final DateTime dueDate = new DateTime().startOfDay(); final DateTime dueDate = new DateTime().startOfDay();
freezeAt(dueDate.plusHours(12)).thawAfter(new Snippet() {{ freezeAt(dueDate.plusHours(12)).thawAfter(new Snippet() {{
Task task = new Task(); Task task = new Task();
task.setValue(DUE_DATE, dueDate.getMillis()); task.setDueDate(dueDate.getMillis());
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertFalse(task.isOverdue()); assertFalse(task.isOverdue());
}}); }});
@ -258,7 +254,7 @@ public class TaskTest {
final DateTime dueDate = new DateTime().startOfDay(); final DateTime dueDate = new DateTime().startOfDay();
freezeAt(dueDate.plusDays(1)).thawAfter(new Snippet() {{ freezeAt(dueDate.plusDays(1)).thawAfter(new Snippet() {{
Task task = new Task(); Task task = new Task();
task.setValue(DUE_DATE, dueDate.getMillis()); task.setDueDate(dueDate.getMillis());
assertFalse(task.hasDueTime()); assertFalse(task.hasDueTime());
assertTrue(task.isOverdue()); assertTrue(task.isOverdue());
}}); }});

@ -8,6 +8,8 @@ package com.todoroo.astrid.service;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.TitleParser;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -25,7 +27,7 @@ import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class QuickAddMarkupTest extends InjectingTestCase { public class QuickAddMarkupTest extends InjectingTestCase {
@Inject TaskCreator taskCreator; @Inject TagService tagService;
@Override @Override
protected void inject(TestComponent component) { protected void inject(TestComponent component) {
@ -102,7 +104,7 @@ public class QuickAddMarkupTest extends InjectingTestCase {
task = new Task(); task = new Task();
task.setTitle(title); task.setTitle(title);
tags.clear(); tags.clear();
taskCreator.parseQuickAddMarkup(task, tags); TitleParser.parse(tagService, task, tags);
} }
private void assertImportanceIs(int importance) { private void assertImportanceIs(int importance) {

@ -31,7 +31,6 @@ 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.google.common.base.Strings; import com.google.common.base.Strings;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Join;
@ -74,7 +73,6 @@ import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
import static com.todoroo.andlib.data.AbstractModel.NO_ID;
import static com.todoroo.astrid.data.Task.NO_UUID; import static com.todoroo.astrid.data.Task.NO_UUID;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
@ -297,7 +295,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
task.setModificationDate(DateUtilities.now()); task.setModificationDate(DateUtilities.now());
gtasksMetadata.setLastSync(DateUtilities.now() + 1000L); gtasksMetadata.setLastSync(DateUtilities.now() + 1000L);
if (gtasksMetadata.getId() == NO_ID) { if (gtasksMetadata.getId() == Task.NO_ID) {
googleTaskDao.insert(gtasksMetadata); googleTaskDao.insert(gtasksMetadata);
} else { } else {
googleTaskDao.update(gtasksMetadata); googleTaskDao.update(gtasksMetadata);
@ -357,7 +355,7 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
private long localIdForGtasksId(String gtasksId) { private long localIdForGtasksId(String gtasksId) {
GoogleTask metadata = getMetadataByGtaskId(gtasksId); GoogleTask metadata = getMetadataByGtaskId(gtasksId);
return metadata == null ? AbstractModel.NO_ID : metadata.getTask(); return metadata == null ? Task.NO_ID : metadata.getTask();
} }
private GoogleTask getMetadataByGtaskId(String gtaskId) { private GoogleTask getMetadataByGtaskId(String gtaskId) {
@ -370,15 +368,15 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
if(task.task.isSaved()) { if(task.task.isSaved()) {
Task local = taskDao.fetch(task.task.getId()); Task local = taskDao.fetch(task.task.getId());
if (local == null) { if (local == null) {
task.task.setId(NO_ID); task.task.setId(Task.NO_ID);
task.task.setUuid(NO_UUID); task.task.setUuid(NO_UUID);
} else { } else {
mergeDates(task.task, local); mergeDates(task.task, local);
} }
} else { // Set default importance and reminders for remotely created tasks } else { // Set default importance and reminders for remotely created tasks
task.task.setImportance(preferences.getIntegerFromString( task.task.setImportance(preferences.getIntegerFromString(
R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO)); R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO)); // TODO: can probably remove this
TaskCreator.setDefaultReminders(preferences, task.task); TaskCreator.setDefaultReminders(preferences, task.task); // TODO: can probably remove this too
task.task.setUuid(UUIDHelper.newUUID()); task.task.setUuid(UUIDHelper.newUUID());
taskDao.createNew(task.task); taskDao.createNew(task.task);
} }

@ -1,20 +1,15 @@
package org.tasks.receivers; package org.tasks.receivers;
import com.todoroo.andlib.data.Property; import com.google.common.base.Strings;
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 org.tasks.gtasks.SyncAdapterHelper; import org.tasks.gtasks.SyncAdapterHelper;
import java.util.ArrayList;
import javax.inject.Inject; import javax.inject.Inject;
public class GoogleTaskPusher { public class GoogleTaskPusher {
private static final Property<?>[] GOOGLE_TASK_PROPERTIES = { Task.ID, Task.TITLE,
Task.NOTES, Task.DUE_DATE, Task.COMPLETION_DATE, Task.DELETION_DATE };
private final SyncAdapterHelper syncAdapterHelper; private final SyncAdapterHelper syncAdapterHelper;
@Inject @Inject
@ -22,7 +17,7 @@ public class GoogleTaskPusher {
this.syncAdapterHelper = syncAdapterHelper; this.syncAdapterHelper = syncAdapterHelper;
} }
void push(Task task, ArrayList<String> modifiedValues) { void push(Task task, Task original) {
if(!syncAdapterHelper.isEnabled()) { if(!syncAdapterHelper.isEnabled()) {
return; return;
} }
@ -31,20 +26,16 @@ public class GoogleTaskPusher {
return; return;
} }
if (checkValuesForProperties(modifiedValues, GOOGLE_TASK_PROPERTIES) || task.checkTransitory(SyncFlags.FORCE_SYNC)) { if (original == null ||
!task.getTitle().equals(original.getTitle()) ||
(Strings.isNullOrEmpty(task.getNotes())
? !Strings.isNullOrEmpty(original.getNotes())
: !task.getNotes().equals(original.getNotes())) ||
!task.getDueDate().equals(original.getDueDate()) ||
!task.getCompletionDate().equals(original.getCompletionDate()) ||
!task.getDeletionDate().equals(original.getDeletionDate()) ||
task.checkAndClearTransitory(SyncFlags.FORCE_SYNC)) {
syncAdapterHelper.requestSynchronization(); syncAdapterHelper.requestSynchronization();
} }
} }
private boolean checkValuesForProperties(ArrayList<String> values, Property<?>[] properties) {
if (values == null) {
return false;
}
for (Property<?> property : properties) {
if (property != Task.ID && values.contains(property.name)) {
return true;
}
}
return false;
}
} }

@ -15,10 +15,10 @@ import javax.inject.Inject;
public class PushReceiver extends InjectingBroadcastReceiver { public class PushReceiver extends InjectingBroadcastReceiver {
public static void broadcast(Context context, Task task, ArrayList<String> values) { public static void broadcast(Context context, Task task, Task original) {
Intent intent = new Intent(context, PushReceiver.class); Intent intent = new Intent(context, PushReceiver.class);
intent.putExtra(AstridApiConstants.EXTRAS_TASK, task); intent.putExtra(AstridApiConstants.EXTRAS_TASK, task);
intent.putStringArrayListExtra(AstridApiConstants.EXTRAS_VALUES, values); intent.putExtra(AstridApiConstants.EXTRAS_ORIGINAL, original);
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
@ -30,7 +30,7 @@ public class PushReceiver extends InjectingBroadcastReceiver {
googleTaskPusher.push( googleTaskPusher.push(
intent.getParcelableExtra(AstridApiConstants.EXTRAS_TASK), intent.getParcelableExtra(AstridApiConstants.EXTRAS_TASK),
intent.getStringArrayListExtra(AstridApiConstants.EXTRAS_VALUES)); intent.getParcelableExtra(AstridApiConstants.EXTRAS_ORIGINAL));
} }
@Override @Override

@ -1,183 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.andlib.data;
import android.arch.persistence.room.Ignore;
import android.content.ContentValues;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.astrid.data.Task;
import org.tasks.data.Tag;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import static com.google.common.collect.Sets.newHashSet;
/**
* <code>AbstractModel</code> represents a row in a database.
* <p>
* A single database can be represented by multiple <code>AbstractModel</code>s
* corresponding to different queries that return a different set of columns.
* Each model exposes a set of properties that it contains.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public abstract class AbstractModel {
/** id property common to all models */
protected static final String ID_PROPERTY_NAME = "_id"; //$NON-NLS-1$
/** id field common to all models */
public static final LongProperty ID_PROPERTY = new LongProperty(null, ID_PROPERTY_NAME);
/** sentinel for objects without an id */
public static final long NO_ID = 0;
// --- abstract methods
public interface ValueWriter<TYPE> {
void setValue(Task instance, TYPE value);
}
// --- data store variables and management
/* Data Source Ordering:
*
* In order to return the best data, we want to check first what the user
* has explicitly set (setValues), then the values we have read out of
* the database (values), then defaults (getRoomGetters)
*/
/** User set values */
@Ignore
protected final Set<String> setValues = new HashSet<>();
/** Transitory Metadata (not saved in database) */
@Ignore
protected HashMap<String, Object> transitoryData = null;
/** Get the user-set values for this object */
public Set<String> getSetValues() {
return newHashSet(setValues);
}
/**
* Transfers all set values into values. This occurs when a task is
* saved - future saves will not need to write all the data as before.
*/
public void markSaved() {
setValues.clear();
}
private void setValue(String columnName, Object value) {
ValueWriter<Object> writer = Task.roomSetters.get(columnName);
if (writer == null) {
throw new RuntimeException();
}
writer.setValue((Task) this, value);
setValues.add(columnName);
}
/**
* Utility method to get the identifier of the model, if it exists.
*
* @return {@value #NO_ID} if this model was not added to the database
*/
abstract public long getId();
public void setId(long id) {
setValue(ID_PROPERTY, id);
}
/**
* @return true if this model has found Jesus (i.e. the database)
*/
public boolean isSaved() {
return getId() != NO_ID;
}
/**
* @return true if setValues or values contains this property
*/
public boolean isModified(Property<?> property) {
return setValues.contains(property.getColumnName());
}
// --- data storage
/**
* Sets the given property. Make sure this model has this property!
*/
public synchronized <TYPE> void setValue(Property<TYPE> property, TYPE value) {
setValue(property.getColumnName(), value);
}
/**
* Merges set values with those coming from another source,
* keeping the existing value if one already exists
*/
public synchronized void mergeWithoutReplacement(ContentValues other) {
for (Entry<String, Object> item : other.valueSet()) {
String columnName = item.getKey();
if (setValues.add(columnName)) {
setValue(columnName, item.getValue());
}
}
}
// --- setting and retrieving flags
public synchronized void putTransitory(String key, Object value) {
if(transitoryData == null) {
transitoryData = new HashMap<>();
}
transitoryData.put(key, value);
}
public void setTags(ArrayList<String> tags) {
if (transitoryData == null) {
transitoryData = new HashMap<>();
}
transitoryData.put(Tag.KEY, tags);
}
public ArrayList<String> getTags() {
Object tags = getTransitory(Tag.KEY);
return tags == null ? new ArrayList<>() : (ArrayList<String>) tags;
}
public <T> T getTransitory(String key) {
if(transitoryData == null) {
return null;
}
return (T) transitoryData.get(key);
}
private Object clearTransitory(String key) {
if (transitoryData == null) {
return null;
}
return transitoryData.remove(key);
}
// --- Convenience wrappers for using transitories as flags
public boolean checkTransitory(String flag) {
Object trans = getTransitory(flag);
return trans != null;
}
public boolean checkAndClearTransitory(String flag) {
Object trans = clearTransitory(flag);
return trans != null;
}
}

@ -16,17 +16,15 @@ import com.todoroo.andlib.sql.SqlTable;
*/ */
public final class Table extends SqlTable { public final class Table extends SqlTable {
public final String name; public final String name;
private final Class<? extends AbstractModel> modelClass;
public Table(String name, Class<? extends AbstractModel> modelClass) { public Table(String name) {
this(name, modelClass, null); this(name, null);
} }
private Table(String name, Class<? extends AbstractModel> modelClass, String alias) { private Table(String name, String alias) {
super(name); super(name);
this.name = name; this.name = name;
this.alias = alias; this.alias = alias;
this.modelClass = modelClass;
} }
/** /**
@ -34,7 +32,7 @@ public final class Table extends SqlTable {
*/ */
@Override @Override
public Table as(String newAlias) { public Table as(String newAlias) {
return new Table(name, modelClass, newAlias); return new Table(name, newAlias);
} }
@Override @Override

@ -6,7 +6,6 @@
package com.todoroo.andlib.utility; package com.todoroo.andlib.utility;
import android.app.Activity; import android.app.Activity;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.text.InputType; import android.text.InputType;
@ -51,32 +50,6 @@ public class AndroidUtilities {
}); });
} }
/**
* Put an arbitrary object into a {@link ContentValues}
*/
public static void putInto(ContentValues target, String key, Object value) {
if (value instanceof Boolean) {
target.put(key, (Boolean) value);
} else if (value instanceof Byte) {
target.put(key, (Byte) value);
} else if (value instanceof Double) {
target.put(key, (Double) value);
} else if (value instanceof Float) {
target.put(key, (Float) value);
} else if (value instanceof Integer) {
target.put(key, (Integer) value);
} else if (value instanceof Long) {
target.put(key, (Long) value);
} else if (value instanceof Short) {
target.put(key, (Short) value);
} else if (value instanceof String) {
target.put(key, (String) value);
} else {
throw new UnsupportedOperationException("Could not handle type " + //$NON-NLS-1$
value.getClass());
}
}
// --- serialization // --- serialization
/** /**

@ -206,7 +206,7 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar
for (TaskEditControlFragment fragment : fragments) { for (TaskEditControlFragment fragment : fragments) {
fragment.apply(model); fragment.apply(model);
} }
taskDao.save(model); taskDao.save(model, null);
if (Flags.checkAndClear(Flags.TAGS_CHANGED)) { if (Flags.checkAndClear(Flags.TAGS_CHANGED)) {
localBroadcastManager.broadcastRefreshList(); localBroadcastManager.broadcastRefreshList();

@ -25,8 +25,6 @@ import org.tasks.data.TaskAttachment;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.todoroo.andlib.data.AbstractModel.NO_ID;
/** /**
* Adapter for displaying a user's tasks as a list * Adapter for displaying a user's tasks as a list
* *
@ -107,7 +105,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
return c.get(Task.ID); return c.get(Task.ID);
} }
} }
return NO_ID; return Task.NO_ID;
} }
public Task getTask(int position) { public Task getTask(int position) {

@ -23,7 +23,7 @@ public class AstridApiConstants {
public static final String EXTRAS_TASK_ID = "task_id"; public static final String EXTRAS_TASK_ID = "task_id";
public static final String EXTRAS_TASK = "task"; public static final String EXTRAS_TASK = "task";
public static final String EXTRAS_VALUES = "values"; public static final String EXTRAS_ORIGINAL = "original";
/** /**
* Extras name for old task due date * Extras name for old task due date
*/ */

@ -13,9 +13,6 @@ import android.support.annotation.Nullable;
import android.util.Xml; import android.util.Xml;
import android.widget.Toast; import android.widget.Toast;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.PropertyVisitor;
import com.todoroo.andlib.sql.Order; import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;

@ -18,16 +18,12 @@ import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskApiDao;
import org.tasks.BuildConfig; import org.tasks.BuildConfig;
import org.tasks.jobs.AfterSaveIntentService; import org.tasks.jobs.AfterSaveIntentService;
import org.tasks.receivers.PushReceiver;
import java.util.List; import java.util.List;
import java.util.Set;
import timber.log.Timber; import timber.log.Timber;
@ -131,9 +127,6 @@ public abstract class TaskDao {
} }
} }
@android.arch.persistence.room.Query("SELECT remoteId FROM tasks WHERE _id = :localId")
public abstract String uuidFromLocalId(long localId);
@android.arch.persistence.room.Query("UPDATE tasks SET calendarUri = '' " + @android.arch.persistence.room.Query("UPDATE tasks SET calendarUri = '' " +
"WHERE calendarUri NOT NULL AND calendarUri != ''") "WHERE calendarUri NOT NULL AND calendarUri != ''")
public abstract void clearAllCalendarEvents(); public abstract void clearAllCalendarEvents();
@ -156,11 +149,13 @@ public abstract class TaskDao {
* *
*/ */
public void save(Task task) { public void save(Task task) {
Set<String> modifiedValues = saveExisting(task); save(task, fetch(task.getId()));
if (modifiedValues != null) { }
AfterSaveIntentService.enqueue(context, task.getId(), modifiedValues);
} else if (task.checkTransitory(SyncFlags.FORCE_SYNC)) { // TODO: get rid of this super-hack
PushReceiver.broadcast(context, task, null); public void save(Task task, Task original) {
if (saveExisting(task, original)) {
AfterSaveIntentService.enqueue(context, task.getId(), original);
} }
} }
@ -177,23 +172,16 @@ public abstract class TaskDao {
task.setId(insert); task.setId(insert);
} }
private Set<String> saveExisting(Task item) { private boolean saveExisting(Task item, Task original) {
Set<String> values = item.getSetValues(); if (!item.insignificantChange(original)) {
if (values == null || values.size() == 0) { item.setModificationDate(now());
return null;
}
if (!TaskApiDao.insignificantChange(values)) {
if (!values.contains(Task.MODIFICATION_DATE.name)) {
item.setModificationDate(now());
}
} }
int updated = update(item); int updated = update(item);
if (updated == 1) { if (updated == 1) {
item.markSaved();
database.onDatabaseUpdated(); database.onDatabaseUpdated();
return values; return true;
} }
return null; return false;
} }
/** /**

@ -12,32 +12,30 @@ import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index; import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey; import android.arch.persistence.room.PrimaryKey;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.IntegerProperty; import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.data.Table; import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import org.tasks.backup.XmlReader; import org.tasks.backup.XmlReader;
import org.tasks.backup.XmlWriter; import org.tasks.backup.XmlWriter;
import org.tasks.data.GoogleTask; import org.tasks.data.Tag;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import timber.log.Timber; import timber.log.Timber;
import static com.google.common.collect.Lists.newArrayList;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
/** /**
@ -48,12 +46,14 @@ import static org.tasks.date.DateTimeUtils.newDateTime;
*/ */
@Entity(tableName = "tasks", @Entity(tableName = "tasks",
indices = @Index(name = "t_rid", value = "remoteId", unique = true)) indices = @Index(name = "t_rid", value = "remoteId", unique = true))
public class Task extends AbstractModel implements Parcelable { public class Task implements Parcelable {
// --- table and uri // --- table and uri
/** table for this model */ /** table for this model */
public static final Table TABLE = new Table("tasks", Task.class); public static final Table TABLE = new Table("tasks");
public static final long NO_ID = 0;
// --- properties // --- properties
@ -62,7 +62,7 @@ public class Task extends AbstractModel implements Parcelable {
@ColumnInfo(name = "_id") @ColumnInfo(name = "_id")
public Long id = NO_ID; public Long id = NO_ID;
public static final LongProperty ID = new LongProperty( public static final LongProperty ID = new LongProperty(
TABLE, ID_PROPERTY_NAME); TABLE, "_id");
/** Name of Task */ /** Name of Task */
@ColumnInfo(name = "title") @ColumnInfo(name = "title")
@ -121,13 +121,9 @@ public class Task extends AbstractModel implements Parcelable {
@ColumnInfo(name = "estimatedSeconds") @ColumnInfo(name = "estimatedSeconds")
public Integer estimatedSeconds = 0; public Integer estimatedSeconds = 0;
public static final IntegerProperty ESTIMATED_SECONDS = new IntegerProperty(
TABLE, "estimatedSeconds");
@ColumnInfo(name = "elapsedSeconds") @ColumnInfo(name = "elapsedSeconds")
public Integer elapsedSeconds = 0; public Integer elapsedSeconds = 0;
public static final IntegerProperty ELAPSED_SECONDS = new IntegerProperty(
TABLE, "elapsedSeconds");
@ColumnInfo(name = "timerStart") @ColumnInfo(name = "timerStart")
public Long timerStart = 0L; public Long timerStart = 0L;
@ -149,14 +145,10 @@ public class Task extends AbstractModel implements Parcelable {
/** Unixtime the last reminder was triggered */ /** Unixtime the last reminder was triggered */
@ColumnInfo(name = "lastNotified") @ColumnInfo(name = "lastNotified")
public Long lastNotified = 0L; public Long lastNotified = 0L;
public static final LongProperty REMINDER_LAST = new LongProperty(
TABLE, "lastNotified");
/** Unixtime snooze is set (0 -> no snooze) */ /** Unixtime snooze is set (0 -> no snooze) */
@ColumnInfo(name = "snoozeTime") @ColumnInfo(name = "snoozeTime")
public Long snoozeTime = 0L; public Long snoozeTime = 0L;
public static final LongProperty REMINDER_SNOOZE = new LongProperty(
TABLE, "snoozeTime");
@ColumnInfo(name = "recurrence") @ColumnInfo(name = "recurrence")
public String recurrence = ""; public String recurrence = "";
@ -165,8 +157,6 @@ public class Task extends AbstractModel implements Parcelable {
@ColumnInfo(name = "repeatUntil") @ColumnInfo(name = "repeatUntil")
public Long repeatUntil = 0L; public Long repeatUntil = 0L;
public static final LongProperty REPEAT_UNTIL = new LongProperty(
TABLE, "repeatUntil");
@ColumnInfo(name = "calendarUri") @ColumnInfo(name = "calendarUri")
public String calendarUri = ""; public String calendarUri = "";
@ -191,8 +181,8 @@ public class Task extends AbstractModel implements Parcelable {
CREATION_DATE, CREATION_DATE,
DELETION_DATE, DELETION_DATE,
DUE_DATE, DUE_DATE,
ELAPSED_SECONDS, new IntegerProperty(TABLE, "elapsedSeconds"),
ESTIMATED_SECONDS, new IntegerProperty(TABLE, "estimatedSeconds"),
HIDE_UNTIL, HIDE_UNTIL,
ID, ID,
IMPORTANCE, IMPORTANCE,
@ -200,10 +190,10 @@ public class Task extends AbstractModel implements Parcelable {
NOTES, NOTES,
RECURRENCE, RECURRENCE,
REMINDER_FLAGS, REMINDER_FLAGS,
REMINDER_LAST, new LongProperty(TABLE, "lastNotified"),
REMINDER_PERIOD, REMINDER_PERIOD,
REMINDER_SNOOZE, new LongProperty(TABLE, "snoozeTime"),
REPEAT_UNTIL, new LongProperty(TABLE, "repeatUntil"),
TIMER_START, TIMER_START,
TITLE, TITLE,
UUID UUID
@ -230,54 +220,128 @@ public class Task extends AbstractModel implements Parcelable {
public static final int IMPORTANCE_SHOULD_DO = 2; public static final int IMPORTANCE_SHOULD_DO = 2;
public static final int IMPORTANCE_NONE = 3; public static final int IMPORTANCE_NONE = 3;
public static final Map<String, ValueWriter<Object>> roomSetters = new HashMap<>();
static {
roomSetters.put(CALENDAR_URI.name, (t, v) -> t.calendarUri = (String) v);
roomSetters.put(COMPLETION_DATE.name, (t, v) -> t.completed = (Long) v);
roomSetters.put(CREATION_DATE.name, (t, v) -> t.created = (Long) v);
roomSetters.put(DELETION_DATE.name, (t, v) -> t.deleted = (Long) v);
roomSetters.put(DUE_DATE.name, (t, v) -> t.dueDate = v instanceof String ? Long.valueOf((String) v) : (Long) v);
roomSetters.put(ELAPSED_SECONDS.name, (t, v) -> t.elapsedSeconds = (Integer) v);
roomSetters.put(ESTIMATED_SECONDS.name, (t, v) -> t.estimatedSeconds = (Integer) v);
roomSetters.put(HIDE_UNTIL.name, (t, v) -> t.hideUntil = (Long) v);
roomSetters.put(ID.name, (t, v) -> t.id = (Long) v);
roomSetters.put(IMPORTANCE.name, (t, v) -> t.importance = v instanceof String ? Integer.valueOf((String) v) : (Integer) v);
roomSetters.put(MODIFICATION_DATE.name, (t, v) -> t.modified = (Long) v);
roomSetters.put(NOTES.name, (t, v) -> t.notes = (String) v);
roomSetters.put(RECURRENCE.name, (t, v) -> t.recurrence = (String) v);
roomSetters.put(REMINDER_FLAGS.name, (t, v) -> t.notificationFlags = (Integer) v);
roomSetters.put(REMINDER_LAST.name, (t, v) -> t.lastNotified = (Long) v);
roomSetters.put(REMINDER_PERIOD.name, (t, v) -> t.notifications = (Long) v);
roomSetters.put(REMINDER_SNOOZE.name, (t, v) -> t.snoozeTime = (Long) v);
roomSetters.put(REPEAT_UNTIL.name, (t, v) -> t.repeatUntil = (Long) v);
roomSetters.put(TIMER_START.name, (t, v) -> t.timerStart = (Long) v);
roomSetters.put(TITLE.name, (t, v) -> t.title = (String) v);
roomSetters.put(UUID.name, (t, v) -> t.remoteId = (String) v);
roomSetters.put(GoogleTask.INDENT.name, (t, v) -> t.googleTaskIndent = (Integer) v);
}
@Ignore @Ignore
private int googleTaskIndent; private int googleTaskIndent;
@Ignore
private HashMap<String, Object> transitoryData = null;
// --- data access boilerplate // --- data access boilerplate
public Task() { public Task() {
super();
} }
@Ignore @Ignore
public Task(TodorooCursor cursor) { public Task(Cursor _cursor) {
for (Property<?> property : cursor.getProperties()) { final int _cursorIndexOfId = _cursor.getColumnIndexOrThrow("_id");
try { final int _cursorIndexOfTitle = _cursor.getColumnIndexOrThrow("title");
ValueWriter<?> writer = roomSetters.get(property.getColumnName()); final int _cursorIndexOfImportance = _cursor.getColumnIndexOrThrow("importance");
if (writer != null) { final int _cursorIndexOfDueDate = _cursor.getColumnIndexOrThrow("dueDate");
writer.setValue(this, cursor.get(property)); final int _cursorIndexOfHideUntil = _cursor.getColumnIndexOrThrow("hideUntil");
} final int _cursorIndexOfCreated = _cursor.getColumnIndexOrThrow("created");
} catch (IllegalArgumentException e) { final int _cursorIndexOfModified = _cursor.getColumnIndexOrThrow("modified");
// underlying cursor may have changed, suppress final int _cursorIndexOfCompleted = _cursor.getColumnIndexOrThrow("completed");
Timber.e(e, e.getMessage()); final int _cursorIndexOfDeleted = _cursor.getColumnIndexOrThrow("deleted");
} final int _cursorIndexOfNotes = _cursor.getColumnIndexOrThrow("notes");
final int _cursorIndexOfEstimatedSeconds = _cursor.getColumnIndexOrThrow("estimatedSeconds");
final int _cursorIndexOfElapsedSeconds = _cursor.getColumnIndexOrThrow("elapsedSeconds");
final int _cursorIndexOfTimerStart = _cursor.getColumnIndexOrThrow("timerStart");
final int _cursorIndexOfNotificationFlags = _cursor.getColumnIndexOrThrow("notificationFlags");
final int _cursorIndexOfNotifications = _cursor.getColumnIndexOrThrow("notifications");
final int _cursorIndexOfLastNotified = _cursor.getColumnIndexOrThrow("lastNotified");
final int _cursorIndexOfSnoozeTime = _cursor.getColumnIndexOrThrow("snoozeTime");
final int _cursorIndexOfRecurrence = _cursor.getColumnIndexOrThrow("recurrence");
final int _cursorIndexOfRepeatUntil = _cursor.getColumnIndexOrThrow("repeatUntil");
final int _cursorIndexOfCalendarUri = _cursor.getColumnIndexOrThrow("calendarUri");
final int _cursorIndexOfRemoteId = _cursor.getColumnIndexOrThrow("remoteId");
final int _cursorIndexOfIndent = _cursor.getColumnIndex("index");
if (_cursor.isNull(_cursorIndexOfId)) {
id = null;
} else {
id = _cursor.getLong(_cursorIndexOfId);
}
title = _cursor.getString(_cursorIndexOfTitle);
if (_cursor.isNull(_cursorIndexOfImportance)) {
importance = null;
} else {
importance = _cursor.getInt(_cursorIndexOfImportance);
}
if (_cursor.isNull(_cursorIndexOfDueDate)) {
dueDate = null;
} else {
dueDate = _cursor.getLong(_cursorIndexOfDueDate);
}
if (_cursor.isNull(_cursorIndexOfHideUntil)) {
hideUntil = null;
} else {
hideUntil = _cursor.getLong(_cursorIndexOfHideUntil);
}
if (_cursor.isNull(_cursorIndexOfCreated)) {
created = null;
} else {
created = _cursor.getLong(_cursorIndexOfCreated);
}
if (_cursor.isNull(_cursorIndexOfModified)) {
modified = null;
} else {
modified = _cursor.getLong(_cursorIndexOfModified);
}
if (_cursor.isNull(_cursorIndexOfCompleted)) {
completed = null;
} else {
completed = _cursor.getLong(_cursorIndexOfCompleted);
}
if (_cursor.isNull(_cursorIndexOfDeleted)) {
deleted = null;
} else {
deleted = _cursor.getLong(_cursorIndexOfDeleted);
}
notes = _cursor.getString(_cursorIndexOfNotes);
if (_cursor.isNull(_cursorIndexOfEstimatedSeconds)) {
estimatedSeconds = null;
} else {
estimatedSeconds = _cursor.getInt(_cursorIndexOfEstimatedSeconds);
}
if (_cursor.isNull(_cursorIndexOfElapsedSeconds)) {
elapsedSeconds = null;
} else {
elapsedSeconds = _cursor.getInt(_cursorIndexOfElapsedSeconds);
}
if (_cursor.isNull(_cursorIndexOfTimerStart)) {
timerStart = null;
} else {
timerStart = _cursor.getLong(_cursorIndexOfTimerStart);
}
if (_cursor.isNull(_cursorIndexOfNotificationFlags)) {
notificationFlags = null;
} else {
notificationFlags = _cursor.getInt(_cursorIndexOfNotificationFlags);
}
if (_cursor.isNull(_cursorIndexOfNotifications)) {
notifications = null;
} else {
notifications = _cursor.getLong(_cursorIndexOfNotifications);
}
if (_cursor.isNull(_cursorIndexOfLastNotified)) {
lastNotified = null;
} else {
lastNotified = _cursor.getLong(_cursorIndexOfLastNotified);
}
if (_cursor.isNull(_cursorIndexOfSnoozeTime)) {
snoozeTime = null;
} else {
snoozeTime = _cursor.getLong(_cursorIndexOfSnoozeTime);
}
recurrence = _cursor.getString(_cursorIndexOfRecurrence);
if (_cursor.isNull(_cursorIndexOfRepeatUntil)) {
repeatUntil = null;
} else {
repeatUntil = _cursor.getLong(_cursorIndexOfRepeatUntil);
}
calendarUri = _cursor.getString(_cursorIndexOfCalendarUri);
remoteId = _cursor.getString(_cursorIndexOfRemoteId);
if (_cursorIndexOfIndent >= 0) {
googleTaskIndent = _cursor.getInt(_cursorIndexOfIndent);
} }
} }
@ -351,11 +415,9 @@ public class Task extends AbstractModel implements Parcelable {
timerStart = parcel.readLong(); timerStart = parcel.readLong();
title = parcel.readString(); title = parcel.readString();
remoteId = parcel.readString(); remoteId = parcel.readString();
setValues.addAll(parcel.readArrayList(getClass().getClassLoader()));
transitoryData = parcel.readHashMap(ContentValues.class.getClassLoader()); transitoryData = parcel.readHashMap(ContentValues.class.getClassLoader());
} }
@Override
public long getId() { public long getId() {
return id == null ? NO_ID : id; return id == null ? NO_ID : id;
} }
@ -570,18 +632,16 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setDueDate(Long dueDate) { public void setDueDate(Long dueDate) {
setValue(DUE_DATE, dueDate); this.dueDate = dueDate;
} }
public void setDueDateAdjustingHideUntil(Long dueDate) { public void setDueDateAdjustingHideUntil(Long newDueDate) {
long oldDueDate = dueDate; if (dueDate > 0) {
if (oldDueDate > 0) {
long hideUntil = this.hideUntil;
if (hideUntil > 0) { if (hideUntil > 0) {
setHideUntil(dueDate > 0 ? hideUntil + dueDate - oldDueDate : 0); setHideUntil(newDueDate > 0 ? hideUntil + newDueDate - dueDate : 0);
} }
} }
setDueDate(dueDate); setDueDate(newDueDate);
} }
public String getRecurrence() { public String getRecurrence() {
@ -589,7 +649,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setRecurrence(String recurrence) { public void setRecurrence(String recurrence) {
setValue(RECURRENCE, recurrence); this.recurrence = recurrence;
} }
public void setRecurrence(RRule rrule, boolean afterCompletion) { public void setRecurrence(RRule rrule, boolean afterCompletion) {
@ -601,7 +661,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setCreationDate(Long creationDate) { public void setCreationDate(Long creationDate) {
setValue(CREATION_DATE, creationDate); created = creationDate;
} }
public String getTitle() { public String getTitle() {
@ -609,7 +669,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setTitle(String title) { public void setTitle(String title) {
setValue(TITLE, title); this.title = title;
} }
public Long getDeletionDate() { public Long getDeletionDate() {
@ -617,7 +677,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setDeletionDate(Long deletionDate) { public void setDeletionDate(Long deletionDate) {
setValue(DELETION_DATE, deletionDate); deleted = deletionDate;
} }
public Long getHideUntil() { public Long getHideUntil() {
@ -625,7 +685,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setHideUntil(Long hideUntil) { public void setHideUntil(Long hideUntil) {
setValue(HIDE_UNTIL, hideUntil); this.hideUntil = hideUntil;
} }
public Long getReminderLast() { public Long getReminderLast() {
@ -633,7 +693,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setReminderLast(Long reminderLast) { public void setReminderLast(Long reminderLast) {
setValue(REMINDER_LAST, reminderLast); lastNotified = reminderLast;
} }
public Long getReminderSnooze() { public Long getReminderSnooze() {
@ -641,7 +701,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setReminderSnooze(Long reminderSnooze) { public void setReminderSnooze(Long reminderSnooze) {
setValue(REMINDER_SNOOZE, reminderSnooze); snoozeTime = reminderSnooze;
} }
public Integer getElapsedSeconds() { public Integer getElapsedSeconds() {
@ -653,7 +713,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setTimerStart(Long timerStart) { public void setTimerStart(Long timerStart) {
setValue(TIMER_START, timerStart); this.timerStart = timerStart;
} }
public Long getRepeatUntil() { public Long getRepeatUntil() {
@ -661,7 +721,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setRepeatUntil(Long repeatUntil) { public void setRepeatUntil(Long repeatUntil) {
setValue(REPEAT_UNTIL, repeatUntil); this.repeatUntil = repeatUntil;
} }
public String getCalendarURI() { public String getCalendarURI() {
@ -673,7 +733,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setImportance(Integer importance) { public void setImportance(Integer importance) {
setValue(IMPORTANCE, importance); this.importance = importance;
} }
public Long getCompletionDate() { public Long getCompletionDate() {
@ -681,7 +741,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setCompletionDate(Long completionDate) { public void setCompletionDate(Long completionDate) {
setValue(COMPLETION_DATE, completionDate); completed = completionDate;
} }
public String getNotes() { public String getNotes() {
@ -693,11 +753,11 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setNotes(String notes) { public void setNotes(String notes) {
setValue(NOTES, notes); this.notes = notes;
} }
public void setModificationDate(Long modificationDate) { public void setModificationDate(Long modificationDate) {
setValue(MODIFICATION_DATE, modificationDate); modified = modificationDate;
} }
public Integer getReminderFlags() { public Integer getReminderFlags() {
@ -705,7 +765,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setReminderFlags(Integer reminderFlags) { public void setReminderFlags(Integer reminderFlags) {
setValue(REMINDER_FLAGS, reminderFlags); notificationFlags = reminderFlags;
} }
public Long getReminderPeriod() { public Long getReminderPeriod() {
@ -713,7 +773,7 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setReminderPeriod(Long reminderPeriod) { public void setReminderPeriod(Long reminderPeriod) {
setValue(REMINDER_PERIOD, reminderPeriod); notifications = reminderPeriod;
} }
public Integer getEstimatedSeconds() { public Integer getEstimatedSeconds() {
@ -721,15 +781,15 @@ public class Task extends AbstractModel implements Parcelable {
} }
public void setElapsedSeconds(Integer elapsedSeconds) { public void setElapsedSeconds(Integer elapsedSeconds) {
setValue(ELAPSED_SECONDS, elapsedSeconds); this.elapsedSeconds = elapsedSeconds;
} }
public void setEstimatedSeconds(Integer estimatedSeconds) { public void setEstimatedSeconds(Integer estimatedSeconds) {
setValue(ESTIMATED_SECONDS, estimatedSeconds); this.estimatedSeconds = estimatedSeconds;
} }
public void setCalendarUri(String calendarUri) { public void setCalendarUri(String calendarUri) {
setValue(CALENDAR_URI, calendarUri); this.calendarUri = calendarUri;
} }
public boolean isNotifyModeNonstop() { public boolean isNotifyModeNonstop() {
@ -766,8 +826,12 @@ public class Task extends AbstractModel implements Parcelable {
} }
} }
public void setId(long id) {
this.id = id;
}
public void setUuid(String uuid) { public void setUuid(String uuid) {
setValue(UUID, uuid); remoteId = uuid;
} }
public static boolean isUuidEmpty(String uuid) { public static boolean isUuidEmpty(String uuid) {
@ -808,7 +872,6 @@ public class Task extends AbstractModel implements Parcelable {
dest.writeLong(timerStart); dest.writeLong(timerStart);
dest.writeString(title); dest.writeString(title);
dest.writeString(remoteId); dest.writeString(remoteId);
dest.writeList(newArrayList(setValues));
dest.writeMap(transitoryData); dest.writeMap(transitoryData);
} }
@ -818,7 +881,6 @@ public class Task extends AbstractModel implements Parcelable {
"id=" + id + "id=" + id +
", title='" + title + '\'' + ", title='" + title + '\'' +
", importance=" + importance + ", importance=" + importance +
", setValues=" + setValues +
", dueDate=" + dueDate + ", dueDate=" + dueDate +
", transitoryData=" + transitoryData + ", transitoryData=" + transitoryData +
", hideUntil=" + hideUntil + ", hideUntil=" + hideUntil +
@ -844,4 +906,87 @@ public class Task extends AbstractModel implements Parcelable {
public int getGoogleTaskIndent() { public int getGoogleTaskIndent() {
return googleTaskIndent; return googleTaskIndent;
} }
public boolean insignificantChange(Task task) {
if (this == task) return true;
if (task == null) return false;
if (id != null ? !id.equals(task.id) : task.id != null) return false;
if (title != null ? !title.equals(task.title) : task.title != null) return false;
if (importance != null ? !importance.equals(task.importance) : task.importance != null)
return false;
if (dueDate != null ? !dueDate.equals(task.dueDate) : task.dueDate != null) return false;
if (hideUntil != null ? !hideUntil.equals(task.hideUntil) : task.hideUntil != null)
return false;
if (created != null ? !created.equals(task.created) : task.created != null) return false;
if (modified != null ? !modified.equals(task.modified) : task.modified != null)
return false;
if (completed != null ? !completed.equals(task.completed) : task.completed != null)
return false;
if (deleted != null ? !deleted.equals(task.deleted) : task.deleted != null) return false;
if (notes != null ? !notes.equals(task.notes) : task.notes != null) return false;
if (estimatedSeconds != null ? !estimatedSeconds.equals(task.estimatedSeconds) : task.estimatedSeconds != null)
return false;
if (elapsedSeconds != null ? !elapsedSeconds.equals(task.elapsedSeconds) : task.elapsedSeconds != null)
return false;
if (notificationFlags != null ? !notificationFlags.equals(task.notificationFlags) : task.notificationFlags != null)
return false;
if (notifications != null ? !notifications.equals(task.notifications) : task.notifications != null)
return false;
if (recurrence != null ? !recurrence.equals(task.recurrence) : task.recurrence != null)
return false;
if (repeatUntil != null ? !repeatUntil.equals(task.repeatUntil) : task.repeatUntil != null)
return false;
if (calendarUri != null ? !calendarUri.equals(task.calendarUri) : task.calendarUri != null)
return false;
return remoteId != null ? remoteId.equals(task.remoteId) : task.remoteId == null;
}
public boolean isSaved() {
return getId() != NO_ID;
}
public synchronized void putTransitory(String key, Object value) {
if(transitoryData == null) {
transitoryData = new HashMap<>();
}
transitoryData.put(key, value);
}
public void setTags(ArrayList<String> tags) {
if (transitoryData == null) {
transitoryData = new HashMap<>();
}
transitoryData.put(Tag.KEY, tags);
}
public ArrayList<String> getTags() {
Object tags = getTransitory(Tag.KEY);
return tags == null ? new ArrayList<>() : (ArrayList<String>) tags;
}
public <T> T getTransitory(String key) {
if(transitoryData == null) {
return null;
}
return (T) transitoryData.get(key);
}
private Object clearTransitory(String key) {
if (transitoryData == null) {
return null;
}
return transitoryData.remove(key);
}
// --- Convenience wrappers for using transitories as flags
public boolean checkTransitory(String flag) {
Object trans = getTransitory(flag);
return trans != null;
}
public boolean checkAndClearTransitory(String flag) {
Object trans = clearTransitory(flag);
return trans != null;
}
} }

@ -1,45 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.data;
import java.util.Collection;
import java.util.Set;
/**
* Data access object for accessing Astrid's {@link Task} table. If you
* are looking to store extended information about a Task, you probably
* want to use the MetadataApiDao object.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class TaskApiDao {
/** @return true if task change shouldn't be broadcast */
public static boolean insignificantChange(Collection<String> values) {
if(values == null || values.size() == 0) {
return true;
}
if(values.contains(Task.REMINDER_LAST.name) &&
values.size() <= 2) {
return true;
}
if(values.contains(Task.REMINDER_SNOOZE.name) &&
values.size() <= 2) {
return true;
}
if(values.contains(Task.TIMER_START.name) &&
values.size() <= 2) {
return true;
}
return false;
}
}

@ -5,7 +5,6 @@ import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
@ -72,7 +71,7 @@ public class TaskCreator {
googleTaskDao.insert(new GoogleTask(task.getId(), googleTaskList)); googleTaskDao.insert(new GoogleTask(task.getId(), googleTaskList));
} }
taskDao.save(task); taskDao.save(task, null);
return task; return task;
} }
@ -88,15 +87,17 @@ public class TaskCreator {
task.setUuid(UUIDHelper.newUUID()); task.setUuid(UUIDHelper.newUUID());
task.setImportance(preferences.getIntegerFromString(R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO));
task.setDueDate(Task.createDueDate(
preferences.getIntegerFromString(R.string.p_default_urgency_key, Task.URGENCY_NONE), 0));
int setting = preferences.getIntegerFromString(R.string.p_default_hideUntil_key,
Task.HIDE_UNTIL_NONE);
task.setHideUntil(task.createHideUntil(setting, 0));
setDefaultReminders(preferences, task);
ArrayList<String> tags = new ArrayList<>(); ArrayList<String> tags = new ArrayList<>();
try {
parseQuickAddMarkup(task, tags);
} catch (Throwable e) {
Timber.e(e, e.getMessage());
}
if (values != null && values.size() > 0) { if (values != null && values.size() > 0) {
ContentValues forTask = new ContentValues();
for (Map.Entry<String, Object> item : values.entrySet()) { for (Map.Entry<String, Object> item : values.entrySet()) {
String key = item.getKey(); String key = item.getKey();
Object value = item.getValue(); Object value = item.getValue();
@ -104,49 +105,37 @@ public class TaskCreator {
tags.add((String) value); tags.add((String) value);
} else if (key.equals(GoogleTask.KEY)) { } else if (key.equals(GoogleTask.KEY)) {
task.putTransitory(key, value); task.putTransitory(key, value);
} else { } else if (value instanceof String) {
if (value instanceof String) { value = PermaSql.replacePlaceholders((String) value);
value = PermaSql.replacePlaceholders((String) value); if (key.equals("dueDate")) {
task.setDueDate(Long.valueOf((String) value));
} else if (key.equals("importance")) {
task.setImportance(Integer.valueOf((String) value));
} else {
throw new RuntimeException("Unhandled key: " + key);
} }
} else {
AndroidUtilities.putInto(forTask, key, value); throw new RuntimeException("Unhandled key: " + key);
} }
} }
task.mergeWithoutReplacement(forTask);
}
if (!task.isModified(Task.IMPORTANCE)) {
task.setImportance(preferences.getIntegerFromString(R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO));
}
if(!task.isModified(Task.DUE_DATE)) {
task.setDueDate(Task.createDueDate(
preferences.getIntegerFromString(R.string.p_default_urgency_key, Task.URGENCY_NONE), 0));
} }
if(!task.isModified(Task.HIDE_UNTIL)) { try {
int setting = preferences.getIntegerFromString(R.string.p_default_hideUntil_key, TitleParser.parse(tagService, task, tags);
Task.HIDE_UNTIL_NONE); } catch (Throwable e) {
task.setHideUntil(task.createHideUntil(setting, 0)); Timber.e(e, e.getMessage());
} }
setDefaultReminders(preferences, task);
task.setTags(tags); task.setTags(tags);
return task; return task;
} }
public static void setDefaultReminders(Preferences preferences, Task task) { public static void setDefaultReminders(Preferences preferences, Task task) {
if(!task.isModified(Task.REMINDER_PERIOD)) { task.setReminderPeriod(DateUtilities.ONE_HOUR *
task.setReminderPeriod(DateUtilities.ONE_HOUR * preferences.getIntegerFromString(R.string.p_rmd_default_random_hours,
preferences.getIntegerFromString(R.string.p_rmd_default_random_hours, 0));
0)); task.setReminderFlags(preferences.getDefaultReminders() | preferences.getDefaultRingMode());
}
if(!task.isModified(Task.REMINDER_FLAGS)) {
task.setReminderFlags(preferences.getDefaultReminders() | preferences.getDefaultRingMode());
}
} }
public void createTags(Task task) { public void createTags(Task task) {
@ -161,12 +150,4 @@ public class TaskCreator {
tagDao.insert(link); tagDao.insert(link);
} }
} }
/**
* Parse quick add markup for the given task
* @param tags an empty array to apply tags to
*/
void parseQuickAddMarkup(Task task, ArrayList<String> tags) {
TitleParser.parse(tagService, task, tags);
}
} }

@ -73,7 +73,7 @@ public class TaskDuplicator {
gcalHelper.createTaskEventIfEnabled(clone); gcalHelper.createTaskEventIfEnabled(clone);
taskDao.save(clone); // TODO: delete me taskDao.save(clone, null); // TODO: delete me
return clone; return clone;
} }

@ -166,9 +166,6 @@ public class TitleParser {
//Day of week (e.g. Monday, Tuesday,..) is overridden by a set date (e.g. October 23 2013). //Day of week (e.g. Monday, Tuesday,..) is overridden by a set date (e.g. October 23 2013).
//Vague times (e.g. breakfast, night) are overridden by a set time (9 am, at 10, 17:00) //Vague times (e.g. breakfast, night) are overridden by a set time (9 am, at 10, 17:00)
private static boolean dayHelper(Task task ) { private static boolean dayHelper(Task task ) {
if (task.getDueDate() > 0) {
return false;
}
String inputText = task.getTitle(); String inputText = task.getTitle();
Calendar cal = null; Calendar cal = null;
Boolean containsSpecificTime = false; Boolean containsSpecificTime = false;
@ -373,9 +370,6 @@ public class TitleParser {
//Parses through the text and sets the frequency of the task. //Parses through the text and sets the frequency of the task.
private static boolean repeatHelper(Task task) { private static boolean repeatHelper(Task task) {
if (!Strings.isNullOrEmpty(task.getRecurrence())) {
return false;
}
String inputText = task.getTitle(); String inputText = task.getTitle();
HashMap<String, Frequency> repeatTimes = new HashMap<>(); HashMap<String, Frequency> repeatTimes = new HashMap<>();
repeatTimes.put("(?i)\\bevery ?\\w{0,6} days?\\b" , Frequency.DAILY); repeatTimes.put("(?i)\\bevery ?\\w{0,6} days?\\b" , Frequency.DAILY);

@ -18,7 +18,7 @@ public class GoogleTask {
public static final String KEY = "gtasks"; //$NON-NLS-1$ public static final String KEY = "gtasks"; //$NON-NLS-1$
@Deprecated @Deprecated
public static final Table TABLE = new Table("google_tasks", null); public static final Table TABLE = new Table("google_tasks");
@Deprecated @Deprecated
public static final Property.IntegerProperty INDENT = new Property.IntegerProperty(GoogleTask.TABLE, "indent"); public static final Property.IntegerProperty INDENT = new Property.IntegerProperty(GoogleTask.TABLE, "indent");

@ -17,7 +17,7 @@ public class Tag {
public static final String KEY = "tags-tag"; //$NON-NLS-1$ public static final String KEY = "tags-tag"; //$NON-NLS-1$
@Deprecated @Deprecated
public static final Table TABLE = new Table("tags", null); public static final Table TABLE = new Table("tags");
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id") @ColumnInfo(name = "_id")

@ -13,7 +13,7 @@ import com.todoroo.astrid.data.Task;
public final class TaskAttachment { public final class TaskAttachment {
@Deprecated @Deprecated
public static final Table TABLE = new Table("task_attachments", null); public static final Table TABLE = new Table("task_attachments");
@Deprecated @Deprecated
public static final Property.LongProperty ID = new Property.LongProperty( public static final Property.LongProperty ID = new Property.LongProperty(

@ -11,7 +11,6 @@ import android.text.TextUtils;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskApiDao;
import com.todoroo.astrid.reminders.ReminderService; import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.repeats.RepeatTaskHelper; import com.todoroo.astrid.repeats.RepeatTaskHelper;
import com.todoroo.astrid.timers.TimerPlugin; import com.todoroo.astrid.timers.TimerPlugin;
@ -26,9 +25,6 @@ import org.tasks.notifications.NotificationManager;
import org.tasks.receivers.PushReceiver; import org.tasks.receivers.PushReceiver;
import org.tasks.scheduling.RefreshScheduler; import org.tasks.scheduling.RefreshScheduler;
import java.util.ArrayList;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import timber.log.Timber; import timber.log.Timber;
@ -40,12 +36,12 @@ import static com.todoroo.astrid.dao.TaskDao.TRANS_SUPPRESS_REFRESH;
public class AfterSaveIntentService extends InjectingJobIntentService { public class AfterSaveIntentService extends InjectingJobIntentService {
private static final String EXTRA_TASK_ID = "extra_task_id"; private static final String EXTRA_TASK_ID = "extra_task_id";
private static final String EXTRA_MODIFIED_VALUES = "extra_modified_values"; private static final String EXTRA_ORIGINAL = "extra_original";
public static void enqueue(Context context, long taskId, Set<String> modifiedValues) { public static void enqueue(Context context, long taskId, Task original) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(EXTRA_TASK_ID, taskId); intent.putExtra(EXTRA_TASK_ID, taskId);
intent.putStringArrayListExtra(EXTRA_MODIFIED_VALUES, newArrayList(modifiedValues)); intent.putExtra(EXTRA_ORIGINAL, original);
AfterSaveIntentService.enqueueWork(context, AfterSaveIntentService.class, JobManager.JOB_ID_TASK_STATUS_CHANGE, intent); AfterSaveIntentService.enqueueWork(context, AfterSaveIntentService.class, JobManager.JOB_ID_TASK_STATUS_CHANGE, intent);
} }
@ -64,10 +60,10 @@ public class AfterSaveIntentService extends InjectingJobIntentService {
super.onHandleWork(intent); super.onHandleWork(intent);
long taskId = intent.getLongExtra(EXTRA_TASK_ID, -1); long taskId = intent.getLongExtra(EXTRA_TASK_ID, -1);
ArrayList<String> modifiedValues = intent.getStringArrayListExtra(EXTRA_MODIFIED_VALUES); Task original = intent.getParcelableExtra(EXTRA_ORIGINAL);
if (taskId == -1 || modifiedValues == null) { if (taskId == -1) {
Timber.e("Invalid extras, taskId=%s modifiedValues=%s", taskId, modifiedValues); Timber.e("Invalid taskId=%s", taskId);
return; return;
} }
@ -77,20 +73,17 @@ public class AfterSaveIntentService extends InjectingJobIntentService {
return; return;
} }
if(modifiedValues.contains(Task.DUE_DATE.name) || if(original == null ||
modifiedValues.contains(Task.REMINDER_FLAGS.name) || !task.getDueDate().equals(original.getDueDate()) ||
modifiedValues.contains(Task.REMINDER_PERIOD.name) || !task.getReminderFlags().equals(original.getReminderFlags()) ||
modifiedValues.contains(Task.REMINDER_LAST.name) || !task.getReminderPeriod().equals(original.getReminderPeriod()) ||
modifiedValues.contains(Task.REMINDER_SNOOZE.name)) { !task.getReminderLast().equals(original.getReminderLast()) ||
!task.getReminderSnooze().equals(original.getReminderSnooze())) {
reminderService.scheduleAlarm(task); reminderService.scheduleAlarm(task);
} }
if(TaskApiDao.insignificantChange(modifiedValues)) { boolean completionDateModified = original == null || !task.getCompletionDate().equals(original.getCompletionDate());
return; boolean deletionDateModified = original != null && !task.getDeletionDate().equals(original.getDeletionDate());
}
boolean completionDateModified = modifiedValues.contains(Task.COMPLETION_DATE.name);
boolean deletionDateModified = modifiedValues.contains(Task.DELETION_DATE.name);
boolean justCompleted = completionDateModified && task.isCompleted(); boolean justCompleted = completionDateModified && task.isCompleted();
boolean justDeleted = deletionDateModified && task.isDeleted(); boolean justDeleted = deletionDateModified && task.isDeleted();
@ -110,7 +103,7 @@ public class AfterSaveIntentService extends InjectingJobIntentService {
} }
} }
PushReceiver.broadcast(context, task, modifiedValues); PushReceiver.broadcast(context, task, original);
refreshScheduler.scheduleRefresh(task); refreshScheduler.scheduleRefresh(task);
if (!task.checkAndClearTransitory(TRANS_SUPPRESS_REFRESH)) { if (!task.checkAndClearTransitory(TRANS_SUPPRESS_REFRESH)) {
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();

@ -72,7 +72,7 @@ public class TaskerTaskCreator {
task.setNotes(bundle.getDescription()); task.setNotes(bundle.getDescription());
taskDao.createNew(task); taskDao.createNew(task);
taskDao.save(task); // TODO: delete me taskDao.save(task, null); // TODO: delete me
taskCreator.createTags(task); taskCreator.createTags(task);
} }

@ -161,15 +161,9 @@ public class CalendarControlSet extends TaskEditControlFragment {
ContentValues updateValues = new ContentValues(); ContentValues updateValues = new ContentValues();
// check if we need to update the item // check if we need to update the item
if(task.isModified(Task.TITLE)) { updateValues.put(CalendarContract.Events.TITLE, task.getTitle());
updateValues.put(CalendarContract.Events.TITLE, task.getTitle()); updateValues.put(CalendarContract.Events.DESCRIPTION, task.getNotes());
} gcalHelper.createStartAndEndDate(task, updateValues);
if(task.isModified(Task.NOTES)) {
updateValues.put(CalendarContract.Events.DESCRIPTION, task.getNotes());
}
if(task.isModified(Task.DUE_DATE) || task.isModified(Task.ESTIMATED_SECONDS)) {
gcalHelper.createStartAndEndDate(task, updateValues);
}
cr.update(Uri.parse(task.getCalendarURI()), updateValues, null, null); cr.update(Uri.parse(task.getCalendarURI()), updateValues, null, null);
} catch (Exception e) { } catch (Exception e) {

@ -204,7 +204,7 @@ class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private TodorooCursor getCursor() { private TodorooCursor getCursor() {
String query = getQuery(); String query = getQuery();
return taskDao.fetchFiltered(query, Task.ID, Task.TITLE, Task.DUE_DATE, Task.COMPLETION_DATE, Task.IMPORTANCE, Task.RECURRENCE); return taskDao.fetchFiltered(query, Task.PROPERTIES);
} }
private Task getTask(int position) { private Task getTask(int position) {

Loading…
Cancel
Save