Fixed up RTM stuff... now we synchronize tags and lists! but currently no display for notes other than the first one. Getting there :)

pull/14/head
Tim Su 16 years ago
parent f6faf9c1fa
commit 38ab72af9f

@ -131,7 +131,13 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
public void synchronize(final Context context) {
// display toast
if(context instanceof Activity) {
Toast.makeText(context, R.string.SyP_progress_toast, Toast.LENGTH_LONG).show();
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, R.string.SyP_progress_toast,
Toast.LENGTH_LONG).show();
}
});
}
// display notification
@ -184,14 +190,14 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
*
* @param data synchronization data structure
*/
protected void synchronizeTasks(SyncData data) throws IOException {
protected void synchronizeTasks(SyncData<TYPE> data) throws IOException {
int length;
// create internal data structures
HashMap<String, Integer> remoteNewTaskNameMap = new HashMap<String, Integer>();
length = data.remoteUpdated.size();
for(int i = 0; i < length; i++) {
TaskContainer remote = data.remoteUpdated.get(i);
TYPE remote = data.remoteUpdated.get(i);
if(remote.task.getId() != Task.NO_ID)
continue;
remoteNewTaskNameMap.put(remote.task.getValue(Task.TITLE), i);
@ -201,7 +207,7 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
length = data.localCreated.getCount();
for(int i = 0; i < length; i++) {
data.localCreated.moveToNext();
TaskContainer local = read(data.localCreated);
TYPE local = read(data.localCreated);
String taskTitle = local.task.getValue(Task.TITLE);
@ -212,36 +218,39 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
*/
if (remoteNewTaskNameMap.containsKey(taskTitle)) {
int remoteIndex = remoteNewTaskNameMap.remove(taskTitle);
TaskContainer remote = data.remoteUpdated.get(remoteIndex);
remote.task.setId(local.task.getId());
TYPE remote = data.remoteUpdated.get(remoteIndex);
transferIdentifiers((TYPE)remote, (TYPE)local);
push((TYPE)local, (TYPE)remote);
transferIdentifiers(remote, local);
push(local, remote);
// re-read remote task after merge
data.remoteUpdated.set(remoteIndex, pull((TYPE)remote));
// re-read remote task after merge, update remote task list
remote = pull(remote);
remote.task.setId(local.task.getId());
data.remoteUpdated.set(remoteIndex, remote);
} else {
create((TYPE)local);
create(local);
}
write((TYPE)local);
write(local);
}
// 2. UPDATE: for each updated local task
length = data.localUpdated.getCount();
for(int i = 0; i < length; i++) {
data.localUpdated.moveToNext();
TaskContainer local = read(data.localUpdated);
TYPE local = read(data.localUpdated);
// if there is a conflict, merge
int remoteIndex = matchTask((ArrayList<TYPE>)data.remoteUpdated, (TYPE)local);
int remoteIndex = matchTask((ArrayList<TYPE>)data.remoteUpdated, local);
if(remoteIndex != -1) {
TaskContainer remote = data.remoteUpdated.get(remoteIndex);
push((TYPE)local, (TYPE)remote);
TYPE remote = data.remoteUpdated.get(remoteIndex);
push(local, remote);
// re-read remote task after merge
data.remoteUpdated.set(remoteIndex, pull((TYPE)remote));
remote = pull(remote);
remote.task.setId(local.task.getId());
data.remoteUpdated.set(remoteIndex, remote);
} else {
push((TYPE)local, null);
push(local, null);
}
}
@ -252,9 +261,9 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
// the wire, the new version and the completed old version. The new
// version would get merged, then completed, if done in the wrong order.
Collections.sort(data.remoteUpdated, new Comparator<TaskContainer>() {
Collections.sort(data.remoteUpdated, new Comparator<TYPE>() {
private static final int SENTINEL = -2;
private final int check(TaskContainer o1, TaskContainer o2, LongProperty property) {
private final int check(TYPE o1, TYPE o2, LongProperty property) {
long o1Property = o1.task.getValue(property);
long o2Property = o2.task.getValue(property);
if(o1Property != 0 && o2Property != 0)
@ -265,7 +274,7 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
return 1;
return SENTINEL;
}
public int compare(TaskContainer o1, TaskContainer o2) {
public int compare(TYPE o1, TYPE o2) {
int comparison = check(o1, o2, Task.DELETION_DATE);
if(comparison != SENTINEL)
return comparison;
@ -278,21 +287,21 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
length = data.remoteUpdated.size();
for(int i = 0; i < length; i++) {
TaskContainer remote = data.remoteUpdated.get(i);
write((TYPE)remote);
TYPE remote = data.remoteUpdated.get(i);
write(remote);
}
}
// --- helper classes
/** data structure builder */
protected static class SyncData {
public final ArrayList<TaskContainer> remoteUpdated;
protected static class SyncData<TYPE extends TaskContainer> {
public final ArrayList<TYPE> remoteUpdated;
public final TodorooCursor<Task> localCreated;
public final TodorooCursor<Task> localUpdated;
public SyncData(ArrayList<TaskContainer> remoteUpdated,
public SyncData(ArrayList<TYPE> remoteUpdated,
TodorooCursor<Task> localCreated,
TodorooCursor<Task> localUpdated) {
super();

@ -6,7 +6,7 @@
<intAttribute key="ch.zork.quicklaunch.index" value="0"/>
<stringAttribute key="ch.zork.quicklaunch.mode" value="debug"/>
<intAttribute key="com.android.ide.eclipse.adt.action" value="0"/>
<stringAttribute key="com.android.ide.eclipse.adt.avd" value="android-22"/>
<stringAttribute key="com.android.ide.eclipse.adt.avd" value="evo-8-google"/>
<stringAttribute key="com.android.ide.eclipse.adt.commandline" value="-scale 0.7"/>
<intAttribute key="com.android.ide.eclipse.adt.delay" value="0"/>
<booleanAttribute key="com.android.ide.eclipse.adt.nobootanim" value="true"/>

@ -65,7 +65,7 @@ public class GenericDao<TYPE extends AbstractModel> {
public TodorooCursor<TYPE> query(Query query) {
query.from(table);
if(Constants.DEBUG)
Log.d("SQL-" + modelClass.getSimpleName(), query.toString()); //$NON-NLS-1$
Log.i("SQL-" + modelClass.getSimpleName(), query.toString()); //$NON-NLS-1$
Cursor cursor = database.rawQuery(query.toString(), null);
return new TodorooCursor<TYPE>(cursor, query.getFields());
}

@ -142,8 +142,11 @@ public final class MilkDataService {
Log.e("SAV", "saving " + task.task.getSetValues());
taskDao.save(task.task, true);
metadataDao.deleteWhere(MetadataCriteria.byTaskAndwithKey(task.task.getId(),
MilkTask.METADATA_KEY));
metadataDao.deleteWhere(Criterion.and(MetadataCriteria.byTask(task.task.getId()),
Criterion.or(MetadataCriteria.withKey(MilkTask.METADATA_KEY),
MetadataCriteria.withKey(MilkNote.METADATA_KEY),
MetadataCriteria.withKey(TagService.KEY))));
task.metadata.add(MilkTask.create(task));
for(Metadata metadata : task.metadata) {
metadata.setValue(Metadata.TASK, task.task.getId());
metadataDao.persist(metadata);
@ -166,8 +169,6 @@ public final class MilkDataService {
MetadataCriteria.withKey(MilkTask.METADATA_KEY),
MetadataCriteria.withKey(MilkNote.METADATA_KEY)))));
try {
if(metadataCursor.getCount() == 0)
return null;
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
metadata.add(new Metadata(metadataCursor));
}

@ -3,6 +3,7 @@ package com.todoroo.astrid.rmilk.data;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.rmilk.sync.RTMTaskContainer;
/**
* Metadata entries for a Remember The Milk Task
@ -30,4 +31,20 @@ public class MilkTask {
public static final IntegerProperty REPEATING = new IntegerProperty(Metadata.TABLE,
Metadata.VALUE4.name);
/**
* Creates a piece of metadata from a remote task
* @param rtmTaskSeries
* @return
*/
public static Metadata create(RTMTaskContainer container) {
Metadata metadata = new Metadata();
metadata.setValue(Metadata.KEY, METADATA_KEY);
metadata.setValue(MilkTask.LIST_ID, container.listId);
metadata.setValue(MilkTask.TASK_SERIES_ID, container.taskSeriesId);
metadata.setValue(MilkTask.TASK_ID, container.taskId);
metadata.setValue(MilkTask.REPEATING, container.repeating ? 1 : 0);
return metadata;
}
}

@ -47,7 +47,6 @@ import com.todoroo.astrid.rmilk.api.data.RtmTaskSeries;
import com.todoroo.astrid.rmilk.api.data.RtmTasks;
import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkNote;
import com.todoroo.astrid.rmilk.data.MilkTask;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.tags.TagService;
@ -234,7 +233,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
dataService.setLists(lists);
// read all tasks
ArrayList<TaskContainer> remoteChanges = new ArrayList<TaskContainer>();
ArrayList<RTMTaskContainer> remoteChanges = new ArrayList<RTMTaskContainer>();
Date lastSyncDate = new Date(Utilities.getLastSyncDate());
boolean shouldSyncIndividualLists = false;
String filter = null;
@ -268,7 +267,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
}
}
SyncData syncData = populateSyncData(remoteChanges);
SyncData<RTMTaskContainer> syncData = populateSyncData(remoteChanges);
try {
synchronizeTasks(syncData);
} finally {
@ -305,20 +304,20 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
/**
* Populate SyncData data structure
*/
private SyncData populateSyncData(ArrayList<TaskContainer> remoteTasks) {
private SyncData<RTMTaskContainer> populateSyncData(ArrayList<RTMTaskContainer> remoteTasks) {
// fetch locally created tasks
TodorooCursor<Task> localCreated = dataService.getLocallyCreated(PROPERTIES);
// fetch locally updated tasks
TodorooCursor<Task> localUpdated = dataService.getLocallyUpdated(PROPERTIES);
return new SyncData(remoteTasks, localCreated, localUpdated);
return new SyncData<RTMTaskContainer>(remoteTasks, localCreated, localUpdated);
}
/**
* Add the tasks read from RTM to the given list
*/
private void addTasksToList(RtmTasks tasks, ArrayList<TaskContainer> list) {
private void addTasksToList(RtmTasks tasks, ArrayList<RTMTaskContainer> list) {
for (RtmTaskList taskList : tasks.getLists()) {
for (RtmTaskSeries taskSeries : taskList.getSeries()) {
RTMTaskContainer remoteTask = parseRemoteTask(taskSeries);
@ -408,13 +407,13 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
// tags
HashSet<String> localTags = new HashSet<String>();
HashSet<String> remoteTags = new HashSet<String>();
for(Metadata metadatum : local.metadata)
if(TagService.KEY.equals(metadatum.getValue(Metadata.KEY)))
localTags.add(metadatum.getValue(TagService.TAG));
if(remote != null) {
for(Metadata metadatum : remote.metadata)
if(TagService.KEY.equals(metadatum.getValue(Metadata.KEY)))
remoteTags.add(metadatum.getValue(TagService.TAG));
for(Metadata item : local.metadata)
if(TagService.KEY.equals(item.getValue(Metadata.KEY)))
localTags.add(item.getValue(TagService.TAG));
if(remote != null && remote.metadata != null) {
for(Metadata item : remote.metadata)
if(TagService.KEY.equals(item.getValue(Metadata.KEY)))
remoteTags.add(item.getValue(TagService.TAG));
}
if(!localTags.equals(remoteTags)) {
String[] tags = localTags.toArray(new String[localTags.size()]);
@ -426,7 +425,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
if(shouldTransmit(local, Task.NOTES, remote)) {
String[] titleAndText = MilkNote.fromNoteField(local.task.getValue(Task.NOTES));
List<RtmTaskNote> notes = null;
if(remote != null)
if(remote != null && remote.remote.getNotes() != null)
notes = remote.remote.getNotes().getNotes();
if(notes != null && notes.size() > 0) {
String remoteNoteId = notes.get(0).getId();
@ -440,19 +439,12 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
}
}
/** Create a task proxy for the given RtmTaskSeries */
/** Create a task container for the given RtmTaskSeries */
private RTMTaskContainer parseRemoteTask(RtmTaskSeries rtmTaskSeries) {
Task task = new Task();
RtmTask rtmTask = rtmTaskSeries.getTask();
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
Metadata rtmMetadata = new Metadata();
metadata.add(rtmMetadata);
rtmMetadata.setValue(MilkTask.LIST_ID, Long.parseLong(rtmTaskSeries.getList().getId()));
rtmMetadata.setValue(MilkTask.TASK_SERIES_ID, Long.parseLong(rtmTaskSeries.getId()));
rtmMetadata.setValue(MilkTask.REPEATING, rtmTaskSeries.hasRecurrence() ? 1 : 0);
rtmMetadata.setValue(MilkTask.TASK_ID, Long.parseLong(rtmTask.getId()));
task.setValue(Task.TITLE, rtmTaskSeries.getName());
task.setValue(Task.CREATION_DATE, DateUtilities.dateToUnixtime(rtmTask.getAdded()));
task.setValue(Task.COMPLETION_DATE, DateUtilities.dateToUnixtime(rtmTask.getCompleted()));
@ -466,20 +458,25 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
}
task.setValue(Task.IMPORTANCE, rtmTask.getPriority().ordinal());
for(String tag : rtmTaskSeries.getTags()) {
Metadata tagData = new Metadata();
tagData.setValue(Metadata.KEY, TagService.KEY);
tagData.setValue(TagService.TAG, tag);
metadata.add(tagData);
if(rtmTaskSeries.getTags() != null) {
for(String tag : rtmTaskSeries.getTags()) {
Metadata tagData = new Metadata();
tagData.setValue(Metadata.KEY, TagService.KEY);
tagData.setValue(TagService.TAG, tag);
metadata.add(tagData);
}
}
boolean firstNote = true;
for(RtmTaskNote note : rtmTaskSeries.getNotes().getNotes()) {
if(firstNote) {
firstNote = false;
task.setValue(Task.NOTES, MilkNote.toNoteField(note));
} else
metadata.add(MilkNote.create(note));
task.setValue(Task.NOTES, ""); //$NON-NLS-1$
if(rtmTaskSeries.getNotes() != null) {
boolean firstNote = true;
for(RtmTaskNote note : rtmTaskSeries.getNotes().getNotes()) {
if(firstNote) {
firstNote = false;
task.setValue(Task.NOTES, MilkNote.toNoteField(note));
} else
metadata.add(MilkNote.create(note));
}
}
RTMTaskContainer container = new RTMTaskContainer(task, metadata, rtmTaskSeries);

@ -1,6 +1,7 @@
package com.todoroo.astrid.rmilk.sync;
import java.util.ArrayList;
import java.util.Iterator;
import com.todoroo.astrid.api.TaskContainer;
import com.todoroo.astrid.model.Metadata;
@ -16,31 +17,38 @@ import com.todoroo.astrid.rmilk.data.MilkTask;
*/
public class RTMTaskContainer extends TaskContainer {
public long listId, taskSeriesId, taskId;
public RtmTaskSeries remote = null;
public boolean repeating;
public RtmTaskSeries remote;
public RTMTaskContainer(Task task, ArrayList<Metadata> metadata,
long listId, long taskSeriesId, long taskId) {
long listId, long taskSeriesId, long taskId, boolean repeating,
RtmTaskSeries remote) {
this.task = task;
this.metadata = metadata;
this.listId = listId;
this.taskSeriesId = taskSeriesId;
this.taskId = taskId;
this.repeating = repeating;
this.remote = remote;
}
public RTMTaskContainer(Task task, ArrayList<Metadata> metadata,
RtmTaskSeries rtmTaskSeries) {
this(task, metadata, Long.parseLong(rtmTaskSeries.getList().getId()),
Long.parseLong(rtmTaskSeries.getId()), Long.parseLong(rtmTaskSeries.getTask().getId()));
remote = rtmTaskSeries;
Long.parseLong(rtmTaskSeries.getId()), Long.parseLong(rtmTaskSeries.getTask().getId()),
rtmTaskSeries.hasRecurrence(), rtmTaskSeries);
}
public RTMTaskContainer(Task task, ArrayList<Metadata> metadata) {
this(task, metadata, 0, 0, 0);
for(Metadata metadatum : metadata) {
if(MilkTask.METADATA_KEY.equals(metadatum.getValue(Metadata.KEY))) {
listId = metadatum.getValue(MilkTask.LIST_ID);
taskSeriesId = metadatum.getValue(MilkTask.TASK_SERIES_ID);
taskId = metadatum.getValue(MilkTask.TASK_ID);
this(task, metadata, 0, 0, 0, false, null);
for(Iterator<Metadata> iterator = metadata.iterator(); iterator.hasNext(); ) {
Metadata item = iterator.next();
if(MilkTask.METADATA_KEY.equals(item.getValue(Metadata.KEY))) {
listId = item.getValue(MilkTask.LIST_ID);
taskSeriesId = item.getValue(MilkTask.TASK_SERIES_ID);
taskId = item.getValue(MilkTask.TASK_ID);
repeating = item.getValue(MilkTask.REPEATING) == 1;
iterator.remove();
break;
}
}

@ -127,6 +127,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
protected TaskAdapter taskAdapter = null;
protected DetailReceiver detailReceiver = new DetailReceiver();
ImageButton quickAddButton;
EditText quickAddBox;
Filter filter;
@ -261,7 +262,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
}
});
final ImageButton quickAddButton = ((ImageButton)findViewById(R.id.quickAddButton));
quickAddButton = ((ImageButton)findViewById(R.id.quickAddButton));
quickAddBox.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
@ -327,6 +328,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
TextView quickAdd = (TextView)findViewById(R.id.quickAddText);
quickAdd.setText(""); //$NON-NLS-1$
quickAddButton.setVisibility(View.GONE);
if(selectNewTask) {
loadTaskListContent(true);

@ -146,7 +146,7 @@ public class TaskDao extends GenericDao<Task> {
saveSuccessful = createNew(task);
} else {
ContentValues values = task.getSetValues();
if(values.size() == 0)
if(values == null || values.size() == 0)
return true;
beforeSave(task, values, skipHooks);
saveSuccessful = saveExisting(task);

@ -29,8 +29,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TimePicker;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;
import com.timsu.astrid.R;
@ -107,7 +107,6 @@ public class DeadlineTimePickerDialog extends AlertDialog implements OnClickList
mDateFormat = DateFormat.getTimeFormat(context);
mCalendar = Calendar.getInstance();
updateTitle(mInitialHourOfDay, mInitialMinute);
setButton(context.getText(android.R.string.ok), this);
setButton2(context.getText(android.R.string.cancel), (OnClickListener) null);
@ -125,7 +124,7 @@ public class DeadlineTimePickerDialog extends AlertDialog implements OnClickList
boolean isChecked) {
mTimePicker.setEnabled(isChecked);
if(isChecked)
updateTitle(mTimePicker.getCurrentHour(), mTimePicker.getCurrentMinute());
updateTitle();
else
setTitle(R.string.TEA_urgency_time_none);
}
@ -137,6 +136,8 @@ public class DeadlineTimePickerDialog extends AlertDialog implements OnClickList
mTimePicker.setCurrentMinute(mInitialMinute);
mTimePicker.setIs24HourView(mIs24HourView);
mTimePicker.setOnTimeChangedListener(this);
updateTitle();
}
public void onClick(DialogInterface dialog, int which) {
@ -150,7 +151,7 @@ public class DeadlineTimePickerDialog extends AlertDialog implements OnClickList
}
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
updateTitle(hourOfDay, minute);
updateTitle();
}
public void updateTime(int hourOfDay, int minutOfHour) {
@ -158,7 +159,9 @@ public class DeadlineTimePickerDialog extends AlertDialog implements OnClickList
mTimePicker.setCurrentMinute(minutOfHour);
}
private void updateTitle(int hour, int minute) {
private void updateTitle() {
int hour = mTimePicker.getCurrentHour();
int minute = mTimePicker.getCurrentMinute();
mCalendar.set(Calendar.HOUR_OF_DAY, hour);
mCalendar.set(Calendar.MINUTE, minute);
setTitle(mDateFormat.format(mCalendar.getTime()));
@ -182,6 +185,6 @@ public class DeadlineTimePickerDialog extends AlertDialog implements OnClickList
mTimePicker.setCurrentMinute(minute);
mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR));
mTimePicker.setOnTimeChangedListener(this);
updateTitle(hour, minute);
updateTitle();
}
}

Loading…
Cancel
Save