diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml
index 89957c65d..cef991eb2 100644
--- a/astrid/AndroidManifest.xml
+++ b/astrid/AndroidManifest.xml
@@ -207,6 +207,14 @@
+
+
+
+
+
+
+
+
*
*/
-public final class EditOperation implements Parcelable {
-
- /**
- * Plugin Id
- */
- public final String plugin;
+public class TaskAction implements Parcelable {
/**
* Label
@@ -33,15 +28,13 @@ public final class EditOperation implements Parcelable {
/**
* Create an EditOperation object
*
- * @param plugin
- * {@link Addon} identifier that encompasses object
* @param text
* label to display
* @param intent
* intent to invoke. {@link EXTRAS_TASK_ID} will be passed
*/
- public EditOperation(String plugin, String text, Intent intent) {
- this.plugin = plugin;
+ public TaskAction(String text, Intent intent) {
+ super();
this.text = text;
this.intent = intent;
}
@@ -59,7 +52,6 @@ public final class EditOperation implements Parcelable {
* {@inheritDoc}
*/
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(plugin);
dest.writeString(text);
dest.writeParcelable(intent, 0);
}
@@ -67,20 +59,20 @@ public final class EditOperation implements Parcelable {
/**
* Parcelable creator
*/
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
/**
* {@inheritDoc}
*/
- public EditOperation createFromParcel(Parcel source) {
- return new EditOperation(source.readString(), source.readString(),
- (Intent)source.readParcelable(Intent.class.getClassLoader()));
+ public TaskAction createFromParcel(Parcel source) {
+ return new TaskAction(source.readString(), (Intent)source.readParcelable(
+ Intent.class.getClassLoader()));
}
/**
* {@inheritDoc}
*/
- public EditOperation[] newArray(int size) {
- return new EditOperation[size];
+ public TaskAction[] newArray(int size) {
+ return new TaskAction[size];
};
};
diff --git a/astrid/api-src/com/todoroo/astrid/api/TaskContainer.java b/astrid/api-src/com/todoroo/astrid/api/TaskContainer.java
index a12e08394..770bf51da 100644
--- a/astrid/api-src/com/todoroo/astrid/api/TaskContainer.java
+++ b/astrid/api-src/com/todoroo/astrid/api/TaskContainer.java
@@ -6,9 +6,10 @@ import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
/**
- * Container class for tasks. Synchronization Providers can subclass
- * this class if desired.
+ * Container class for transmitting tasks and including local and remote
+ * metadata. Synchronization Providers can subclass this class if desired.
*
+ * @see {@link SynchronizationProvider}
* @author Tim Su
*
*/
diff --git a/astrid/api-src/com/todoroo/astrid/api/TaskDecoration.java b/astrid/api-src/com/todoroo/astrid/api/TaskDecoration.java
new file mode 100644
index 000000000..91367fd53
--- /dev/null
+++ b/astrid/api-src/com/todoroo/astrid/api/TaskDecoration.java
@@ -0,0 +1,101 @@
+/**
+ * See the file "LICENSE" for the full license governing this code.
+ */
+package com.todoroo.astrid.api;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.RemoteViews;
+import android.widget.RemoteViews.RemoteView;
+
+/**
+ * Represents a line of text displayed in the Task List
+ *
+ * @author Tim Su
+ *
+ */
+public final class TaskDecoration implements Parcelable {
+
+ /**
+ * Place decoration between completion box and task title
+ */
+ public static final int POSITION_LEFT = 0;
+
+ /**
+ * Place decoration between task title and importance bar
+ */
+ public static final int POSITION_RIGHT = 1;
+
+ /**
+ * {@link RemoteView} decoration
+ */
+ public RemoteViews decoration = null;
+
+ /**
+ * Decoration update interval (minimum of 1000 millis), 0 to never update
+ */
+ public long updateInterval = 0;
+
+ /**
+ * Decoration position
+ */
+ public int position = POSITION_LEFT;
+
+ /**
+ * Decorated task background color. 0 is default
+ */
+ public int color = 0;
+
+ /**
+ * Creates a TaskDetail object
+ * @param text
+ * text to display
+ * @param color
+ * color to use for text. Use 0
for default color
+ */
+ public TaskDecoration(RemoteViews decoration, int position, int color) {
+ this.decoration = decoration;
+ this.position = position;
+ this.color = color;
+ }
+
+ // --- parcelable helpers
+
+ /**
+ * {@inheritDoc}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(decoration, 0);
+ dest.writeInt(position);
+ dest.writeInt(color);
+ }
+
+ /**
+ * Parcelable creator
+ */
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ /**
+ * {@inheritDoc}
+ */
+ public TaskDecoration createFromParcel(Parcel source) {
+ return new TaskDecoration((RemoteViews)source.readParcelable(
+ RemoteViews.class.getClassLoader()),
+ source.readInt(), source.readInt());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public TaskDecoration[] newArray(int size) {
+ return new TaskDecoration[size];
+ };
+ };
+
+}
diff --git a/astrid/api-src/com/todoroo/astrid/api/TaskDetail.java b/astrid/api-src/com/todoroo/astrid/api/TaskDetail.java
deleted file mode 100644
index 4d24501e8..000000000
--- a/astrid/api-src/com/todoroo/astrid/api/TaskDetail.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * See the file "LICENSE" for the full license governing this code.
- */
-package com.todoroo.astrid.api;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents a line of text displayed in the Task List
- *
- * @author Tim Su
- *
- */
-public final class TaskDetail implements Parcelable {
-
- /**
- * Text of detail
- */
- public String text = null;
-
- /**
- * Color to use for text. 0 is default
- */
- public int color = 0;
-
- /**
- * Creates a TaskDetail object
- * @param text
- * text to display
- * @param color
- * color to use for text. Use 0
for default color
- */
- public TaskDetail(String text, int color) {
- this.text = text;
- this.color = color;
- }
-
- /**
- * Convenience constructor to make a TaskDetail with default color
- * @param text
- * text to display
- */
- public TaskDetail(String text) {
- this(text, 0);
- }
-
- // --- parcelable helpers
-
- /**
- * {@inheritDoc}
- */
- public int describeContents() {
- return 0;
- }
-
- /**
- * {@inheritDoc}
- */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(text);
- dest.writeInt(color);
- }
-
- /**
- * Parcelable creator
- */
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- /**
- * {@inheritDoc}
- */
- public TaskDetail createFromParcel(Parcel source) {
- return new TaskDetail(source.readString(), source.readInt());
- }
-
- /**
- * {@inheritDoc}
- */
- public TaskDetail[] newArray(int size) {
- return new TaskDetail[size];
- };
- };
-
-}
diff --git a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java
index 894f87467..0a76591ec 100644
--- a/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java
+++ b/astrid/common-src/com/todoroo/andlib/utility/AndroidUtilities.java
@@ -214,12 +214,13 @@ public class AndroidUtilities {
/**
* Copy a file from one place to another
+ *
* @param in
* @param out
* @throws Exception
*/
public static void copyFile(File in, File out) throws Exception {
- FileInputStream fis = new FileInputStream(in);
+ FileInputStream fis = new FileInputStream(in);
FileOutputStream fos = new FileOutputStream(out);
try {
byte[] buf = new byte[1024];
@@ -227,13 +228,11 @@ public class AndroidUtilities {
while ((i = fis.read(buf)) != -1) {
fos.write(buf, 0, i);
}
- }
- catch (Exception e) {
+ } catch (Exception e) {
throw e;
+ } finally {
+ fis.close();
+ fos.close();
}
- finally {
- if (fis != null) fis.close();
- if (fos != null) fos.close();
- }
- }
+ }
}
diff --git a/astrid/plugin-src/com/todoroo/astrid/core/CorePlugin.java b/astrid/plugin-src/com/todoroo/astrid/core/CorePlugin.java
index c76847423..7f8848108 100644
--- a/astrid/plugin-src/com/todoroo/astrid/core/CorePlugin.java
+++ b/astrid/plugin-src/com/todoroo/astrid/core/CorePlugin.java
@@ -12,9 +12,10 @@ public class CorePlugin extends BroadcastReceiver {
static final String IDENTIFIER = "core"; //$NON-NLS-1$
@Override
+ @SuppressWarnings("nls")
public void onReceive(Context context, Intent intent) {
Addon plugin = new Addon(IDENTIFIER, "Core Filters", "Todoroo",
- "Provides 'Inbox' and 'All Tasks' Filters");
+ "Provides 'Inbox', 'Search', and 'More...' Filters");
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_ADDONS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, plugin);
diff --git a/astrid/plugin-src/com/todoroo/astrid/notes/NoteDetailExposer.java b/astrid/plugin-src/com/todoroo/astrid/notes/NoteDetailExposer.java
index f5ef99e88..55a73f62a 100644
--- a/astrid/plugin-src/com/todoroo/astrid/notes/NoteDetailExposer.java
+++ b/astrid/plugin-src/com/todoroo/astrid/notes/NoteDetailExposer.java
@@ -11,12 +11,11 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
-import com.todoroo.astrid.api.TaskDetail;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.TaskService;
/**
- * Exposes {@link TaskDetail} for tags, i.e. "Tags: frogs, animals"
+ * Exposes Task Detail for notes
*
* @author Tim Su
*
@@ -35,7 +34,8 @@ public class NoteDetailExposer extends BroadcastReceiver implements DetailExpose
if(taskId == -1)
return;
- TaskDetail taskDetail = getTaskDetails(context, taskId);
+ boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
+ String taskDetail = getTaskDetails(context, taskId, extended);
if(taskDetail == null)
return;
@@ -43,12 +43,16 @@ public class NoteDetailExposer extends BroadcastReceiver implements DetailExpose
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, NotesPlugin.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
@Override
- public TaskDetail getTaskDetails(Context context, long id) {
+ public String getTaskDetails(Context context, long id, boolean extended) {
+ if(!extended)
+ return null;
+
synchronized(NoteDetailExposer.class) {
if(staticTaskService == null) {
DependencyInjectionService.getInstance().inject(this);
@@ -65,7 +69,7 @@ public class NoteDetailExposer extends BroadcastReceiver implements DetailExpose
if(notes.length() == 0)
return null;
- return new TaskDetail(notes);
+ return notes;
}
}
diff --git a/astrid/plugin-src/com/todoroo/astrid/notes/NotesPlugin.java b/astrid/plugin-src/com/todoroo/astrid/notes/NotesPlugin.java
index 2948c27b8..88038e84f 100644
--- a/astrid/plugin-src/com/todoroo/astrid/notes/NotesPlugin.java
+++ b/astrid/plugin-src/com/todoroo/astrid/notes/NotesPlugin.java
@@ -12,6 +12,7 @@ public class NotesPlugin extends BroadcastReceiver {
static final String IDENTIFIER = "notes"; //$NON-NLS-1$
@Override
+ @SuppressWarnings("nls")
public void onReceive(Context context, Intent intent) {
Addon plugin = new Addon(IDENTIFIER, "Notes", "Todoroo",
"Lets you add and view notes for a task.");
diff --git a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatDetailExposer.java b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatDetailExposer.java
index 894643997..be7b51452 100644
--- a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatDetailExposer.java
+++ b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatDetailExposer.java
@@ -20,12 +20,11 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
-import com.todoroo.astrid.api.TaskDetail;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.TaskService;
/**
- * Exposes {@link TaskDetail} for tags, i.e. "Tags: frogs, animals"
+ * Exposes Task Detail for repeats, i.e. "Repeats every 2 days"
*
* @author Tim Su
*
@@ -44,7 +43,8 @@ public class RepeatDetailExposer extends BroadcastReceiver implements DetailExpo
if(taskId == -1)
return;
- TaskDetail taskDetail = getTaskDetails(context, taskId);
+ boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
+ String taskDetail = getTaskDetails(context, taskId, extended);
if(taskDetail == null)
return;
@@ -52,11 +52,15 @@ public class RepeatDetailExposer extends BroadcastReceiver implements DetailExpo
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, RepeatsPlugin.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
- public TaskDetail getTaskDetails(Context context, long id) {
+ public String getTaskDetails(Context context, long id, boolean extended) {
+ if(extended)
+ return null;
+
synchronized(RepeatDetailExposer.class) {
if(staticTaskService == null) {
DependencyInjectionService.getInstance().inject(this);
@@ -126,7 +130,7 @@ public class RepeatDetailExposer extends BroadcastReceiver implements DetailExpo
else
detail = context.getString(R.string.repeat_detail_duedate, interval);
- return new TaskDetail(detail);
+ return detail;
}
return null;
}
diff --git a/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkDetailExposer.java b/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkDetailExposer.java
index 60d1ee278..db816776d 100644
--- a/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkDetailExposer.java
+++ b/astrid/plugin-src/com/todoroo/astrid/rmilk/MilkDetailExposer.java
@@ -12,17 +12,16 @@ import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
-import com.todoroo.astrid.api.TaskDetail;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkNote;
import com.todoroo.astrid.rmilk.data.MilkTask;
/**
- * Exposes {@link TaskDetail}s for Remember the Milk:
+ * Exposes Task Details for Remember the Milk:
* - RTM list
* - RTM repeat information
- * - whether task has been changed
+ * - RTM notes
*
* @author Tim Su
*
@@ -39,49 +38,54 @@ public class MilkDetailExposer extends BroadcastReceiver implements DetailExpose
if(taskId == -1)
return;
- TaskDetail taskDetail = getTaskDetails(context, taskId);
+ boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
+ String taskDetail = getTaskDetails(context, taskId, extended);
if(taskDetail == null)
return;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, Utilities.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
@Override
- public TaskDetail getTaskDetails(Context context, long id) {
+ public String getTaskDetails(Context context, long id, boolean extended) {
Metadata metadata = MilkDataService.getInstance().getTaskMetadata(id);
if(metadata == null)
return null;
StringBuilder builder = new StringBuilder();
- long listId = metadata.getValue(MilkTask.LIST_ID);
- if(listId > 0) {
- builder.append(context.getString(R.string.rmilk_TLA_list,
- MilkDataService.getInstance().getListName(listId))).append(TaskAdapter.DETAIL_SEPARATOR);
- }
- int repeat = metadata.getValue(MilkTask.REPEATING);
- if(repeat != 0) {
- builder.append(context.getString(R.string.rmilk_TLA_repeat)).append(TaskAdapter.DETAIL_SEPARATOR);
- }
+ if(!extended) {
+ long listId = metadata.getValue(MilkTask.LIST_ID);
+ if(listId > 0) {
+ builder.append(context.getString(R.string.rmilk_TLA_list,
+ MilkDataService.getInstance().getListName(listId))).append(TaskAdapter.DETAIL_SEPARATOR);
+ }
- TodorooCursor notesCursor = MilkDataService.getInstance().getTaskNotesCursor(id);
- try {
- for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
- metadata.readFromCursor(notesCursor);
- builder.append(MilkNote.toTaskDetail(metadata)).append(TaskAdapter.DETAIL_SEPARATOR);
+ int repeat = metadata.getValue(MilkTask.REPEATING);
+ if(repeat != 0) {
+ builder.append(context.getString(R.string.rmilk_TLA_repeat)).append(TaskAdapter.DETAIL_SEPARATOR);
+ }
+ } else {
+ TodorooCursor notesCursor = MilkDataService.getInstance().getTaskNotesCursor(id);
+ try {
+ for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
+ metadata.readFromCursor(notesCursor);
+ builder.append(MilkNote.toTaskDetail(metadata)).append(TaskAdapter.DETAIL_SEPARATOR);
+ }
+ } finally {
+ notesCursor.close();
}
- } finally {
- notesCursor.close();
}
if(builder.length() == 0)
return null;
String result = builder.toString();
- return new TaskDetail(result.substring(0, result.length() - 3));
+ return result.substring(0, result.length() - TaskAdapter.DETAIL_SEPARATOR.length());
}
}
diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java
index 16a7b4668..a91ae0614 100644
--- a/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java
+++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java
@@ -10,10 +10,9 @@ import android.content.Intent;
import com.timsu.astrid.R;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
-import com.todoroo.astrid.api.TaskDetail;
/**
- * Exposes {@link TaskDetail} for tags, i.e. "Tags: frogs, animals"
+ * Exposes Task Detail for tags, i.e. "Tags: frogs, animals"
*
* @author Tim Su
*
@@ -27,7 +26,8 @@ public class TagDetailExposer extends BroadcastReceiver implements DetailExposer
if(taskId == -1)
return;
- TaskDetail taskDetail = getTaskDetails(context, taskId);
+ boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
+ String taskDetail = getTaskDetails(context, taskId, extended);
if(taskDetail == null)
return;
@@ -35,18 +35,21 @@ public class TagDetailExposer extends BroadcastReceiver implements DetailExposer
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, TagsPlugin.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
@Override
- public TaskDetail getTaskDetails(Context context, long id) {
- String tagList = TagService.getInstance().getTagsAsString(id);
+ public String getTaskDetails(Context context, long id, boolean extended) {
+ if(extended)
+ return null;
+ String tagList = TagService.getInstance().getTagsAsString(id);
if(tagList.length() == 0)
return null;
- return new TaskDetail(context.getString(R.string.tag_TLA_detail, tagList));
+ return context.getString(R.string.tag_TLA_detail, tagList);
}
}
diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagsPlugin.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagsPlugin.java
index 42a0e3617..7a3f168fd 100644
--- a/astrid/plugin-src/com/todoroo/astrid/tags/TagsPlugin.java
+++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagsPlugin.java
@@ -9,8 +9,9 @@ import com.todoroo.astrid.api.AstridApiConstants;
public class TagsPlugin extends BroadcastReceiver {
- static final String IDENTIFIER = "tags";
+ static final String IDENTIFIER = "tags"; //$NON-NLS-1$
+ @SuppressWarnings("nls")
@Override
public void onReceive(Context context, Intent intent) {
Addon plugin = new Addon(IDENTIFIER, "Tags", "Todoroo",
diff --git a/astrid/plugin-src/com/todoroo/astrid/timers/TimerDecorationExposer.java b/astrid/plugin-src/com/todoroo/astrid/timers/TimerDecorationExposer.java
new file mode 100644
index 000000000..cf8ebd870
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/timers/TimerDecorationExposer.java
@@ -0,0 +1,116 @@
+/**
+ * See the file "LICENSE" for the full license governing this code.
+ */
+package com.todoroo.astrid.timers;
+
+import java.util.HashMap;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.widget.RemoteViews;
+
+import com.timsu.astrid.R;
+import com.todoroo.andlib.service.Autowired;
+import com.todoroo.andlib.service.DependencyInjectionService;
+import com.todoroo.astrid.api.AstridApiConstants;
+import com.todoroo.astrid.api.TaskDecoration;
+import com.todoroo.astrid.service.TaskService;
+
+/**
+ * Exposes {@link TaskDecoration} for timers
+ *
+ * @author Tim Su
+ *
+ */
+public class TimerDecorationExposer extends BroadcastReceiver {
+
+ private static final int TASK_BG_COLOR = Color.argb(200, 220, 50, 0);
+
+ private static TaskService staticTaskService;
+ private static HashMap decorations =
+ new HashMap();
+ private static HashMap timers =
+ new HashMap();
+
+ @Autowired
+ private TaskService taskService;
+
+ private static class TimerTimerTask extends TimerTask {
+ int time;
+ RemoteViews remoteViews;
+
+ public TimerTimerTask(int time, RemoteViews remoteViews) {
+ super();
+ this.time = time;
+ this.remoteViews = remoteViews;
+ }
+
+ @Override
+ public void run() {
+ time++;
+ int seconds = time % 60;
+ int minutes = time / 60;
+ if(minutes > 59) {
+ int hours = minutes / 60;
+ minutes %= 60;
+ remoteViews.setTextViewText(R.id.timer,
+ String.format("%02d:%02d:%02d", //$NON-NLS-1$
+ hours, minutes, seconds));
+ } else {
+ remoteViews.setTextViewText(R.id.timer,
+ String.format("%02d:%02d", //$NON-NLS-1$
+ minutes, seconds));
+ }
+ }
+ }
+
+ public void removeFromCache(long taskId) {
+ decorations.remove(taskId);
+ timers.get(taskId).cancel();
+ timers.remove(taskId);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
+ if(taskId == -1)
+ return;
+
+ synchronized(TimerDecorationExposer.class) {
+ if(staticTaskService == null) {
+ DependencyInjectionService.getInstance().inject(this);
+ staticTaskService = taskService;
+ } else {
+ taskService = staticTaskService;
+ }
+ }
+
+ TaskDecoration decoration;
+
+ if(!decorations.containsKey(taskId)) {
+ RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
+ R.layout.timer_decoration);
+ decoration = new TaskDecoration(remoteViews,
+ TaskDecoration.POSITION_LEFT, TASK_BG_COLOR);
+ decorations.put(taskId, decoration);
+ Timer timer = new Timer();
+ timers.put(taskId, timer);
+ timer.scheduleAtFixedRate(new TimerTimerTask(0,
+ remoteViews), 0, 1000L);
+ } else {
+ decoration = decorations.get(taskId);
+ }
+
+ // transmit
+ Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DECORATIONS);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, TimerPlugin.IDENTIFIER);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, decoration);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
+ context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
+ }
+
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/timers/TimerPlugin.java b/astrid/plugin-src/com/todoroo/astrid/timers/TimerPlugin.java
new file mode 100644
index 000000000..45bf1e168
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/timers/TimerPlugin.java
@@ -0,0 +1,25 @@
+package com.todoroo.astrid.timers;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.todoroo.astrid.api.Addon;
+import com.todoroo.astrid.api.AstridApiConstants;
+
+public class TimerPlugin extends BroadcastReceiver {
+
+ static final String IDENTIFIER = "timer"; //$NON-NLS-1$
+
+ @Override
+ @SuppressWarnings("nls")
+ public void onReceive(Context context, Intent intent) {
+ Addon plugin = new Addon(IDENTIFIER, "Timer", "Todoroo",
+ "Lets you time how long it takes to complete tasks.");
+
+ Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_ADDONS);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, plugin);
+ context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
+ }
+
+}
diff --git a/astrid/res/drawable/timers_decoration.png b/astrid/res/drawable/timers_decoration.png
new file mode 100644
index 000000000..18b7c6781
Binary files /dev/null and b/astrid/res/drawable/timers_decoration.png differ
diff --git a/astrid/res/layout/task_adapter_row.xml b/astrid/res/layout/task_adapter_row.xml
index 20549d7c8..bad4d561a 100644
--- a/astrid/res/layout/task_adapter_row.xml
+++ b/astrid/res/layout/task_adapter_row.xml
@@ -10,7 +10,7 @@
android:paddingRight="6dip"
android:orientation="vertical">
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java
index bb35ff5ce..ce45edc46 100644
--- a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java
+++ b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java
@@ -52,7 +52,7 @@ import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.adapter.TaskAdapter.ViewHolder;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
-import com.todoroo.astrid.api.TaskDetail;
+import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.core.CoreFilterExposer;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
@@ -378,6 +378,8 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
super.onResume();
registerReceiver(detailReceiver,
new IntentFilter(AstridApiConstants.BROADCAST_SEND_DETAILS));
+ registerReceiver(detailReceiver,
+ new IntentFilter(AstridApiConstants.BROADCAST_SEND_DECORATIONS));
}
@Override
@@ -387,7 +389,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
}
/**
- * Receiver which receives intents to add items to the filter list
+ * Receiver which receives detail or decoration intents
*
* @author Tim Su
*
@@ -398,8 +400,17 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
try {
Bundle extras = intent.getExtras();
long taskId = extras.getLong(AstridApiConstants.EXTRAS_TASK_ID);
- TaskDetail detail = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE);
- taskAdapter.addDetails(getListView(), taskId, detail);
+
+ if(AstridApiConstants.BROADCAST_SEND_DECORATIONS.equals(intent.getAction())) {
+ TaskDecoration deco = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE);
+ taskAdapter.addDecorations(getListView(), taskId,
+ deco);
+ } else {
+ String detail = extras.getString(AstridApiConstants.EXTRAS_RESPONSE);
+ taskAdapter.addDetails(getListView(), taskId,
+ extras.getBoolean(AstridApiConstants.EXTRAS_EXTENDED),
+ detail);
+ }
} catch (Exception e) {
exceptionService.reportError("receive-detail-" + //$NON-NLS-1$
intent.getStringExtra(AstridApiConstants.EXTRAS_ADDON), e);
@@ -463,7 +474,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
if(requery) {
taskCursor.requery();
- taskAdapter.flushDetailCache();
+ taskAdapter.flushCaches();
taskAdapter.notifyDataSetChanged();
}
startManagingCursor(taskCursor);
diff --git a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java
index c806340c9..b1ba04bf0 100644
--- a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java
+++ b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java
@@ -1,11 +1,15 @@
package com.todoroo.astrid.adapter;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
-import android.app.Activity;
+import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -19,11 +23,11 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CursorAdapter;
import android.widget.LinearLayout;
-import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;
@@ -40,7 +44,7 @@ import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
-import com.todoroo.astrid.api.TaskDetail;
+import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.notes.NoteDetailExposer;
import com.todoroo.astrid.repeats.RepeatDetailExposer;
@@ -97,15 +101,19 @@ public class TaskAdapter extends CursorAdapter {
@Autowired
DialogUtilities dialogUtilities;
- protected final Activity activity;
+ protected final ListActivity activity;
protected final HashMap completedItems;
public boolean isFling = false;
private final int resource;
private final LayoutInflater inflater;
protected OnCompletedTaskListener onCompletedTaskListener = null;
private int fontSize;
- private static final SoftHashMap> detailCache =
- new SoftHashMap>();
+
+ // --- task detail and decoration soft caches
+
+ private static final TaskCache detailCache = new TaskCache();
+ private static final TaskCache extendedDetailCache = new TaskCache();
+ private static final TaskCache decorationCache = new TaskCache();
/**
* Constructor
@@ -120,7 +128,7 @@ public class TaskAdapter extends CursorAdapter {
* @param onCompletedTaskListener
* task listener. can be null
*/
- public TaskAdapter(Activity activity, int resource,
+ public TaskAdapter(ListActivity activity, int resource,
TodorooCursor c, boolean autoRequery,
OnCompletedTaskListener onCompletedTaskListener) {
super(activity, c, autoRequery);
@@ -155,7 +163,9 @@ public class TaskAdapter extends CursorAdapter {
viewHolder.completeBox = (CheckBox)view.findViewById(R.id.completeBox);
viewHolder.dueDate = (TextView)view.findViewById(R.id.dueDate);
viewHolder.details = (TextView)view.findViewById(R.id.details);
+ viewHolder.extendedDetails = (TextView)view.findViewById(R.id.extendedDetails);
viewHolder.actions = (LinearLayout)view.findViewById(R.id.actions);
+ viewHolder.taskRow = (LinearLayout)view.findViewById(R.id.task_row);
viewHolder.importance = (View)view.findViewById(R.id.importance);
view.setTag(viewHolder);
@@ -204,9 +214,13 @@ public class TaskAdapter extends CursorAdapter {
public CheckBox completeBox;
public TextView dueDate;
public TextView details;
+ public TextView extendedDetails;
public View importance;
public LinearLayout actions;
+ public LinearLayout taskRow;
public boolean expanded;
+
+ public View[] decorations;
}
/** Helper method to set the contents and visibility of each field */
@@ -251,7 +265,6 @@ public class TaskAdapter extends CursorAdapter {
dueDateView.setText(r.getString(R.string.TAd_completed, dateValue));
dueDateView.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDetails);
setVisibility(dueDateView);
-
} else {
dueDateView.setVisibility(View.GONE);
}
@@ -265,43 +278,63 @@ public class TaskAdapter extends CursorAdapter {
completeBox.setChecked(task.isCompleted());
}
- // task details - send out a request for it (only if not fling)
- viewHolder.details.setText(""); //$NON-NLS-1$
- if(!isFling) {
- retrieveDetails(viewHolder);
- }
-
- // importance bar - must be set at end when view height is determined
+ // importance bar
final View importanceView = viewHolder.importance; {
int value = task.getValue(Task.IMPORTANCE);
importanceView.setBackgroundColor(IMPORTANCE_COLORS[value]);
}
+
+ // details and decorations
+ viewHolder.details.setText(""); //$NON-NLS-1$
+ if(viewHolder.decorations != null) {
+ for(View decoration: viewHolder.decorations)
+ viewHolder.taskRow.removeView(decoration);
+ }
+ viewHolder.taskRow.setBackgroundDrawable(null);
+ if(!isFling) {
+ // task details - send out a request for it
+ retrieveDetails(viewHolder, false);
+
+ // task decoration - send out a request for it
+ retrieveDecorations(viewHolder);
+ }
}
- // --- task details
+ protected TaskRowListener listener = new TaskRowListener();
+ /**
+ * Set listeners for this view. This is called once per view when it is
+ * created.
+ */
+ private void addListeners(final View container) {
+ // check box listener
+ final CheckBox completeBox = ((CheckBox)container.findViewById(R.id.completeBox));
+ completeBox.setOnClickListener(completeBoxListener);
+
+ // context menu listener
+ container.setOnCreateContextMenuListener(listener);
- private void retrieveDetails(final ViewHolder viewHolder) {
- final long taskId = viewHolder.task.getId();
+ // tap listener
+ container.setOnClickListener(listener);
+ }
- // check the cache
- boolean inCache = false;
- final LinkedHashSet details;
- synchronized(detailCache) {
- if(detailCache.containsKey(taskId))
- inCache = true;
- else
- detailCache.put(taskId, new LinkedHashSet());
- details = detailCache.get(taskId);
- }
+ /* ======================================================================
+ * ============================================================== add-ons
+ * ====================================================================== */
- if(inCache) {
- spanifyAndAdd(viewHolder.details, details);
+ private void retrieveDetails(final ViewHolder viewHolder, final boolean extended) {
+ final long taskId = viewHolder.task.getId();
+
+ final TaskCache cache = extended ? extendedDetailCache : detailCache;
+ ArrayList list = cache.initialize(taskId);
+ if(list != null) {
+ spanifyAndAdd(viewHolder, extended, list);
return;
}
// request details
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
// load internal details
@@ -309,35 +342,40 @@ public class TaskAdapter extends CursorAdapter {
@Override
public void run() {
for(DetailExposer exposer : EXPOSERS) {
- if(Thread.interrupted())
- return;
-
- final TaskDetail detail = exposer.getTaskDetails(activity, taskId);
- if(detail == null || details.contains(detail))
- continue;
-
- details.add(detail);
- if(taskId != viewHolder.task.getId())
+ final String detail = exposer.getTaskDetails(activity,
+ taskId, extended);
+ if(detail == null)
continue;
-
- activity.runOnUiThread(new Runnable() {
- public void run() {
- spanifyAndAdd(viewHolder.details, details);
- }
- });
+ final ArrayList cacheList = cache.addIfNotExists(taskId, detail);
+ if(cacheList != null) {
+ if(taskId != viewHolder.task.getId())
+ continue;
+ activity.runOnUiThread(new Runnable() {
+ public void run() {
+ spanifyAndAdd(viewHolder, extended, cacheList);
+ }
+ });
+ }
}
};
}.start();
}
@SuppressWarnings("nls")
- private void spanifyAndAdd(TextView view, LinkedHashSet details) {
+ private void spanifyAndAdd(ViewHolder viewHolder, boolean extended, ArrayList details) {
+ if(details == null)
+ return;
+ TextView view = extended ? viewHolder.extendedDetails : viewHolder.details;
view.setVisibility(details.size() > 0 ? View.VISIBLE : View.GONE);
- if(details.size() == 0)
+ if(details.size() == 0 || (extended && !viewHolder.expanded)) {
+ view.setVisibility(View.GONE);
return;
+ } else {
+ view.setVisibility(View.VISIBLE);
+ }
StringBuilder detailText = new StringBuilder();
- for(Iterator iterator = details.iterator(); iterator.hasNext(); ) {
- detailText.append(iterator.next().text);
+ for(Iterator iterator = details.iterator(); iterator.hasNext(); ) {
+ detailText.append(iterator.next());
if(iterator.hasNext())
detailText.append(DETAIL_SEPARATOR);
}
@@ -351,14 +389,10 @@ public class TaskAdapter extends CursorAdapter {
/**
* Called to tell the cache to be cleared
*/
- public void flushDetailCache() {
+ public void flushCaches() {
detailCache.clear();
- }
-
- @Override
- public void notifyDataSetChanged() {
- super.notifyDataSetChanged();
- fontSize = Preferences.getIntegerFromString(R.string.p_fontSize);
+ extendedDetailCache.clear();
+ decorationCache.clear();
}
/**
@@ -366,23 +400,24 @@ public class TaskAdapter extends CursorAdapter {
*
* @param taskId
*/
- public synchronized void addDetails(ListView list, long taskId, TaskDetail detail) {
+ public synchronized void addDetails(ListView listView, long taskId,
+ boolean extended, String detail) {
if(detail == null)
return;
- LinkedHashSet details = detailCache.get(taskId);
- if(details.contains(detail))
- return;
- details.add(detail);
-
- // update view if it is visible
- int length = list.getChildCount();
- for(int i = 0; i < length; i++) {
- ViewHolder viewHolder = (ViewHolder) list.getChildAt(i).getTag();
- if(viewHolder == null || viewHolder.task.getId() != taskId)
- continue;
- spanifyAndAdd(viewHolder.details, details);
- break;
+ final TaskCache cache = extended ? extendedDetailCache : detailCache;
+
+ ArrayList cacheList = cache.addIfNotExists(taskId, detail);
+ if(cacheList != null) {
+ // update view if it is visible
+ int length = listView.getChildCount();
+ for(int i = 0; i < length; i++) {
+ ViewHolder viewHolder = (ViewHolder) listView.getChildAt(i).getTag();
+ if(viewHolder == null || viewHolder.task.getId() != taskId)
+ continue;
+ spanifyAndAdd(viewHolder, extended, cacheList);
+ break;
+ }
}
}
@@ -397,29 +432,120 @@ public class TaskAdapter extends CursorAdapter {
}
};
- protected ContextMenuListener listener = new ContextMenuListener();
+ private void retrieveDecorations(final ViewHolder viewHolder) {
+ final long taskId = viewHolder.task.getId();
+
+ ArrayList list = decorationCache.initialize(taskId);
+ if(list != null) {
+ decorate(viewHolder, list);
+ return;
+ }
+
+ // request details
+ Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DECORATIONS);
+ broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
+ activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
+
+ if(timer == null) {
+ timer = new Timer();
+ timer.scheduleAtFixedRate(decorationUpdater, 0, 1000L);
+ }
+ }
+
+ private Timer timer = null;
+
/**
- * Set listeners for this view. This is called once per view when it is
- * created.
+ * Task to update decorations every second
*/
- private void addListeners(final View container) {
- // check box listener
- final CheckBox completeBox = ((CheckBox)container.findViewById(R.id.completeBox));
- completeBox.setOnClickListener(completeBoxListener);
+ private final TimerTask decorationUpdater = new TimerTask() {
+ @Override
+ public void run() {
+ ListView listView = activity.getListView();
+ int length = listView.getChildCount();
+ for(int i = 0; i < length; i++) {
+ ViewHolder viewHolder = (ViewHolder) listView.getChildAt(i).getTag();
+ ArrayList list = decorationCache.get(viewHolder.task.getId());
+ if(list == null)
+ continue;
+
+ for(int j = 0; j < list.size(); j++) {
+ final TaskDecoration decoration = list.get(j);
+ if(decoration.decoration == null)
+ continue;
+ final View view = viewHolder.decorations[j];
+ if(view == null)
+ continue;
+ activity.runOnUiThread(new Runnable() {
+ public void run() {
+ decoration.decoration.reapply(activity, view);
+ }
+ });
+ }
+ }
+ }
+ };
- // context menu listener
- container.setOnCreateContextMenuListener(listener);
+ /**
+ * Respond to a request to add details for a task
+ *
+ * @param taskId
+ */
+ public synchronized void addDecorations(ListView listView, long taskId,
+ TaskDecoration taskDecoration) {
+ if(taskDecoration == null)
+ return;
- // tap listener
- container.setOnClickListener(listener);
+ ArrayList cacheList = decorationCache.addIfNotExists(taskId,
+ taskDecoration);
+ if(cacheList != null) {
+ // update view if it is visible
+ int length = listView.getChildCount();
+ for(int i = 0; i < length; i++) {
+ ViewHolder viewHolder = (ViewHolder) listView.getChildAt(i).getTag();
+ if(viewHolder == null || viewHolder.task.getId() != taskId)
+ continue;
+ decorate(viewHolder, cacheList);
+ break;
+ }
+ }
+ }
+
+ private void decorate(ViewHolder viewHolder, ArrayList decorations) {
+ if(decorations == null || decorations.size() == 0)
+ return;
+
+ // apply decorations in reverse so top priority appears at the ends &
+ // color is set bu the most important decoration
+ viewHolder.decorations = new View[decorations.size()];
+ for(int i = decorations.size() - 1; i >= 0; i--) {
+ TaskDecoration deco = decorations.get(i);
+ if(deco.color != 0)
+ ((View)viewHolder.taskRow.getParent()).setBackgroundColor(deco.color);
+ if(deco.decoration != null) {
+ View view = deco.decoration.apply(activity, viewHolder.taskRow);
+ viewHolder.decorations[i] = view;
+ switch(deco.position) {
+ case TaskDecoration.POSITION_LEFT:
+ viewHolder.taskRow.addView(view, 1);
+ break;
+ case TaskDecoration.POSITION_RIGHT:
+ viewHolder.taskRow.addView(view, viewHolder.taskRow.getChildCount() - 2);
+ }
+ }
+ }
}
/* ======================================================================
* ======================================================= event handlers
* ====================================================================== */
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+ fontSize = Preferences.getIntegerFromString(R.string.p_fontSize);
+ }
- class ContextMenuListener implements OnCreateContextMenuListener, OnClickListener {
+ class TaskRowListener implements OnCreateContextMenuListener, OnClickListener {
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
@@ -428,11 +554,23 @@ public class TaskAdapter extends CursorAdapter {
@Override
public void onClick(View v) {
+ // expand view
final ViewHolder viewHolder = (ViewHolder)v.getTag();
viewHolder.expanded = !viewHolder.expanded;
LinearLayout actions = viewHolder.actions;
+ TextView extendedDetails = viewHolder.extendedDetails;
+
actions.setVisibility(viewHolder.expanded ? View.VISIBLE : View.GONE);
- if(viewHolder.expanded && actions.getChildCount() == 0) {
+ if(!viewHolder.expanded) {
+ viewHolder.extendedDetails.setVisibility(View.GONE);
+ return;
+ }
+
+ final long taskId = viewHolder.task.getId();
+ extendedDetails.setText(""); //$NON-NLS-1$
+ retrieveDetails(viewHolder, true);
+
+ if(actions.getChildCount() == 0) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1f);
Button edit = new Button(activity);
@@ -442,7 +580,7 @@ public class TaskAdapter extends CursorAdapter {
@Override
public void onClick(View view) {
Intent intent = new Intent(activity, TaskEditActivity.class);
- intent.putExtra(TaskEditActivity.ID_TOKEN, viewHolder.task.getId());
+ intent.putExtra(TaskEditActivity.ID_TOKEN, taskId);
activity.startActivityForResult(intent, TaskListActivity.ACTIVITY_EDIT_TASK);
}
});
@@ -507,4 +645,53 @@ public class TaskAdapter extends CursorAdapter {
}
}
+ /* ======================================================================
+ * =============================================================== caches
+ * ====================================================================== */
+
+ private static class TaskCache {
+
+ private final Map> cache =
+ Collections.synchronizedMap(new SoftHashMap>());
+
+ /**
+ * Retrieves a list. If it doesn't exist, list is created, but
+ * the method will return null
+ * @param taskId
+ * @return list if there was already one
+ */
+ public ArrayList initialize(long taskId) {
+ if(cache.containsKey(taskId))
+ return cache.get(taskId);
+ cache.put(taskId, new ArrayList());
+ return null;
+ }
+
+ /**
+ * Adds an item to the cache if it doesn't exist
+ * @param taskId
+ * @param item
+ * @return list if item was added, null if it already existed
+ */
+ public ArrayList addIfNotExists(long taskId, TYPE item) {
+ ArrayList list = cache.get(taskId);
+ if(list == null || list.contains(item))
+ return null;
+ list.add(item);
+ return list;
+ }
+
+ /**
+ * Clears the cache
+ */
+ public void clear() {
+ cache.clear();
+ }
+
+ public ArrayList get(long taskId) {
+ return cache.get(taskId);
+ }
+
+ }
+
}
diff --git a/astrid/src/com/todoroo/astrid/api/DetailExposer.java b/astrid/src/com/todoroo/astrid/api/DetailExposer.java
index 2a4e84e60..804b7c846 100644
--- a/astrid/src/com/todoroo/astrid/api/DetailExposer.java
+++ b/astrid/src/com/todoroo/astrid/api/DetailExposer.java
@@ -12,8 +12,13 @@ public interface DetailExposer {
/**
* @param id
+ * task id
+ * @param extended
+ * whether this request is for extended details (which are
+ * displayed when user presses a task), or standard (which are
+ * always displayed)
* @return null if no details, or task details
*/
- public TaskDetail getTaskDetails(Context context, long id);
+ public String getTaskDetails(Context context, long id, boolean extended);
}