AST-246 - caching task details

pull/14/head
Tim Su 16 years ago
parent 1049549629
commit adea1b3126

@ -189,6 +189,12 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name="com.todoroo.astrid.alarms.AlarmDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- tags --> <!-- tags -->
<receiver android:name="com.todoroo.astrid.tags.TagsPlugin"> <receiver android:name="com.todoroo.astrid.tags.TagsPlugin">
@ -203,6 +209,12 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name="com.todoroo.astrid.tags.TagDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- repeats --> <!-- repeats -->
<receiver android:name="com.todoroo.astrid.repeats.RepeatsPlugin"> <receiver android:name="com.todoroo.astrid.repeats.RepeatsPlugin">
@ -217,6 +229,12 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name="com.todoroo.astrid.repeats.RepeatDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- calendar --> <!-- calendar -->
<receiver android:name="com.todoroo.astrid.gcal.GCalTaskCompleteListener"> <receiver android:name="com.todoroo.astrid.gcal.GCalTaskCompleteListener">
@ -255,6 +273,12 @@
</receiver> </receiver>
<!-- notes --> <!-- notes -->
<receiver android:name="com.todoroo.astrid.notes.NoteDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- locale --> <!-- locale -->
<activity android:name="com.todoroo.astrid.locale.LocaleEditAlerts" <activity android:name="com.todoroo.astrid.locale.LocaleEditAlerts"
@ -345,6 +369,12 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name="com.todoroo.astrid.producteev.ProducteevDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- rmilk --> <!-- rmilk -->
<receiver android:name="com.todoroo.astrid.rmilk.MilkFilterExposer"> <receiver android:name="com.todoroo.astrid.rmilk.MilkFilterExposer">
@ -373,6 +403,12 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name="com.todoroo.astrid.rmilk.MilkDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application> </application>

@ -12,7 +12,7 @@
<intAttribute key="com.android.ide.eclipse.adt.delay" value="0"/> <intAttribute key="com.android.ide.eclipse.adt.delay" value="0"/>
<booleanAttribute key="com.android.ide.eclipse.adt.nobootanim" value="true"/> <booleanAttribute key="com.android.ide.eclipse.adt.nobootanim" value="true"/>
<intAttribute key="com.android.ide.eclipse.adt.speed" value="0"/> <intAttribute key="com.android.ide.eclipse.adt.speed" value="0"/>
<booleanAttribute key="com.android.ide.eclipse.adt.target" value="true"/> <booleanAttribute key="com.android.ide.eclipse.adt.target" value="false"/>
<booleanAttribute key="com.android.ide.eclipse.adt.wipedata" value="false"/> <booleanAttribute key="com.android.ide.eclipse.adt.wipedata" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/astrid"/> <listEntry value="/astrid"/>

@ -12,7 +12,6 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Metadata;
/** /**
@ -21,7 +20,7 @@ import com.todoroo.astrid.model.Metadata;
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class AlarmDetailExposer extends BroadcastReceiver implements DetailExposer { public class AlarmDetailExposer extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -44,7 +43,6 @@ public class AlarmDetailExposer extends BroadcastReceiver implements DetailExpos
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
} }
@Override
public String getTaskDetails(Context context, long id, boolean extended) { public String getTaskDetails(Context context, long id, boolean extended) {
if(extended) if(extended)
return null; return null;
@ -71,9 +69,4 @@ public class AlarmDetailExposer extends BroadcastReceiver implements DetailExpos
} }
} }
@Override
public String getPluginIdentifier() {
return AlarmService.IDENTIFIER;
}
} }

@ -10,7 +10,6 @@ import android.content.Intent;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.utility.Preferences; import com.todoroo.astrid.utility.Preferences;
@ -21,7 +20,7 @@ import com.todoroo.astrid.utility.Preferences;
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class NoteDetailExposer extends BroadcastReceiver implements DetailExposer { public class NoteDetailExposer extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -44,7 +43,6 @@ public class NoteDetailExposer extends BroadcastReceiver implements DetailExpose
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
} }
@Override
public String getTaskDetails(Context context, long id, boolean extended) { public String getTaskDetails(Context context, long id, boolean extended) {
if(Preferences.getBoolean(R.string.p_showNotes, false)) { if(Preferences.getBoolean(R.string.p_showNotes, false)) {
@ -65,9 +63,4 @@ public class NoteDetailExposer extends BroadcastReceiver implements DetailExpose
return "<img src='silk_note'/> " + notes; //$NON-NLS-1$ return "<img src='silk_note'/> " + notes; //$NON-NLS-1$
} }
@Override
public String getPluginIdentifier() {
return NotesPlugin.IDENTIFIER;
}
} }

@ -11,7 +11,6 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.astrid.adapter.TaskAdapter; import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.StoreObject; import com.todoroo.astrid.model.StoreObject;
import com.todoroo.astrid.producteev.sync.ProducteevDashboard; import com.todoroo.astrid.producteev.sync.ProducteevDashboard;
@ -27,7 +26,7 @@ import com.todoroo.astrid.utility.Preferences;
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class ProducteevDetailExposer extends BroadcastReceiver implements DetailExposer{ public class ProducteevDetailExposer extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -52,7 +51,6 @@ public class ProducteevDetailExposer extends BroadcastReceiver implements Detail
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
} }
@Override
public String getTaskDetails(Context context, long id, boolean extended) { public String getTaskDetails(Context context, long id, boolean extended) {
Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(id); Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(id);
if(metadata == null) if(metadata == null)
@ -133,9 +131,4 @@ public class ProducteevDetailExposer extends BroadcastReceiver implements Detail
return null; return null;
} }
@Override
public String getPluginIdentifier() {
return ProducteevUtilities.IDENTIFIER;
}
} }

@ -17,7 +17,6 @@ import com.google.ical.values.RRule;
import com.google.ical.values.WeekdayNum; import com.google.ical.values.WeekdayNum;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.Task;
@ -27,7 +26,7 @@ import com.todoroo.astrid.model.Task;
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class RepeatDetailExposer extends BroadcastReceiver implements DetailExposer { public class RepeatDetailExposer extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -119,7 +118,6 @@ public class RepeatDetailExposer extends BroadcastReceiver implements DetailExpo
return null; return null;
} }
@Override
public String getPluginIdentifier() { public String getPluginIdentifier() {
return RepeatsPlugin.IDENTIFIER; return RepeatsPlugin.IDENTIFIER;
} }

@ -11,7 +11,6 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.astrid.adapter.TaskAdapter; import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.model.Metadata; import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.rmilk.data.MilkDataService; import com.todoroo.astrid.rmilk.data.MilkDataService;
import com.todoroo.astrid.rmilk.data.MilkNote; import com.todoroo.astrid.rmilk.data.MilkNote;
@ -26,7 +25,7 @@ import com.todoroo.astrid.rmilk.data.MilkTask;
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class MilkDetailExposer extends BroadcastReceiver implements DetailExposer{ public class MilkDetailExposer extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -51,7 +50,6 @@ public class MilkDetailExposer extends BroadcastReceiver implements DetailExpose
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
} }
@Override
public String getTaskDetails(Context context, long id, boolean extended) { public String getTaskDetails(Context context, long id, boolean extended) {
Metadata metadata = MilkDataService.getInstance().getTaskMetadata(id); Metadata metadata = MilkDataService.getInstance().getTaskMetadata(id);
if(metadata == null) if(metadata == null)
@ -92,9 +90,4 @@ public class MilkDetailExposer extends BroadcastReceiver implements DetailExpose
return result.substring(0, result.length() - TaskAdapter.DETAIL_SEPARATOR.length()); return result.substring(0, result.length() - TaskAdapter.DETAIL_SEPARATOR.length());
} }
@Override
public String getPluginIdentifier() {
return MilkUtilities.IDENTIFIER;
}
} }

@ -8,7 +8,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
/** /**
* Exposes Task Detail for tags, i.e. "Tags: frogs, animals" * Exposes Task Detail for tags, i.e. "Tags: frogs, animals"
@ -16,7 +15,7 @@ import com.todoroo.astrid.api.DetailExposer;
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class TagDetailExposer extends BroadcastReceiver implements DetailExposer { public class TagDetailExposer extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -39,7 +38,6 @@ public class TagDetailExposer extends BroadcastReceiver implements DetailExposer
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
} }
@Override
public String getTaskDetails(Context context, long id, boolean extended) { public String getTaskDetails(Context context, long id, boolean extended) {
if(extended) if(extended)
return null; return null;
@ -51,9 +49,4 @@ public class TagDetailExposer extends BroadcastReceiver implements DetailExposer
return "<img src='silk_tag_pink'/> " + tagList; //$NON-NLS-1$ return "<img src='silk_tag_pink'/> " + tagList; //$NON-NLS-1$
} }
@Override
public String getPluginIdentifier() {
return TagsPlugin.IDENTIFIER;
}
} }

@ -8,13 +8,13 @@
android:paddingBottom="4dip" android:paddingBottom="4dip"
android:paddingLeft="4dip" android:paddingLeft="4dip"
android:paddingRight="4dip" android:paddingRight="4dip"
android:minHeight="40dip"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout android:id="@+id/task_row" <LinearLayout android:id="@+id/task_row"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="100" android:layout_weight="100"
android:minHeight="40dip"
android:orientation="horizontal"> android:orientation="horizontal">
<!-- importance --> <!-- importance -->

@ -477,9 +477,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
} else if(AstridApiConstants.BROADCAST_SEND_DETAILS.equals(intent.getAction())) { } else if(AstridApiConstants.BROADCAST_SEND_DETAILS.equals(intent.getAction())) {
String detail = extras.getString(AstridApiConstants.EXTRAS_RESPONSE); String detail = extras.getString(AstridApiConstants.EXTRAS_RESPONSE);
if(extras.getBoolean(AstridApiConstants.EXTRAS_EXTENDED)) if(extras.getBoolean(AstridApiConstants.EXTRAS_EXTENDED))
taskAdapter.detailManager.addNew(taskId, addOn, detail);
else
taskAdapter.extendedDetailManager.addNew(taskId, addOn, detail); taskAdapter.extendedDetailManager.addNew(taskId, addOn, detail);
else
taskAdapter.addDetails(taskId, detail);
} else if(AstridApiConstants.BROADCAST_SEND_ACTIONS.equals(intent.getAction())) { } else if(AstridApiConstants.BROADCAST_SEND_ACTIONS.equals(intent.getAction())) {
TaskAction action = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE); TaskAction action = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE);
taskAdapter.taskActionManager.addNew(taskId, addOn, action); taskAdapter.taskActionManager.addNew(taskId, addOn, action);

@ -1,6 +1,7 @@
package com.todoroo.astrid.adapter; package com.todoroo.astrid.adapter;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@ -15,6 +16,7 @@ import android.database.Cursor;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.Html; import android.text.Html;
import android.text.TextUtils;
import android.text.Html.ImageGetter; import android.text.Html.ImageGetter;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.view.ContextMenu; import android.view.ContextMenu;
@ -43,18 +45,12 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.SoftHashMap; import com.todoroo.andlib.utility.SoftHashMap;
import com.todoroo.astrid.activity.TaskEditActivity; import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.activity.TaskListActivity; import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.alarms.AlarmDetailExposer;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.DetailExposer;
import com.todoroo.astrid.api.TaskAction; import com.todoroo.astrid.api.TaskAction;
import com.todoroo.astrid.api.TaskDecoration; import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.notes.NoteDetailExposer; import com.todoroo.astrid.service.AddOnService;
import com.todoroo.astrid.producteev.ProducteevDetailExposer;
import com.todoroo.astrid.repeats.RepeatDetailExposer;
import com.todoroo.astrid.rmilk.MilkDetailExposer;
import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagDetailExposer;
import com.todoroo.astrid.utility.Constants; import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.utility.Preferences; import com.todoroo.astrid.utility.Preferences;
@ -83,16 +79,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
Task.COMPLETION_DATE, Task.COMPLETION_DATE,
Task.HIDE_UNTIL, Task.HIDE_UNTIL,
Task.DELETION_DATE, Task.DELETION_DATE,
}; Task.DETAILS,
/** Internal Task Detail exposers */
public static final DetailExposer[] EXPOSERS = new DetailExposer[] {
new TagDetailExposer(),
new RepeatDetailExposer(),
new NoteDetailExposer(),
new MilkDetailExposer(),
new ProducteevDetailExposer(),
new AlarmDetailExposer(),
}; };
private static int[] IMPORTANCE_COLORS = null; private static int[] IMPORTANCE_COLORS = null;
@ -105,6 +92,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
@Autowired @Autowired
private TaskService taskService; private TaskService taskService;
@Autowired
private AddOnService addOnService;
protected final ListActivity activity; protected final ListActivity activity;
protected final HashMap<Long, Boolean> completedItems = new HashMap<Long, Boolean>(); protected final HashMap<Long, Boolean> completedItems = new HashMap<Long, Boolean>();
private OnCompletedTaskListener onCompletedTaskListener = null; private OnCompletedTaskListener onCompletedTaskListener = null;
@ -112,6 +102,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private final int resource; private final int resource;
private final LayoutInflater inflater; private final LayoutInflater inflater;
private int fontSize; private int fontSize;
private DetailLoaderThread detailLoader;
private final AtomicReference<String> query; private final AtomicReference<String> query;
@ -120,8 +111,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// --- task detail and decoration soft caches // --- task detail and decoration soft caches
public final DetailManager detailManager = new DetailManager(false); public final DetailManager extendedDetailManager = new DetailManager();
public final DetailManager extendedDetailManager = new DetailManager(true);
public final DecorationManager decorationManager = public final DecorationManager decorationManager =
new DecorationManager(); new DecorationManager();
public final TaskActionManager taskActionManager = new TaskActionManager(); public final TaskActionManager taskActionManager = new TaskActionManager();
@ -159,6 +149,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
if(IMPORTANCE_COLORS == null) if(IMPORTANCE_COLORS == null)
IMPORTANCE_COLORS = Task.getImportanceColors(activity.getResources()); IMPORTANCE_COLORS = Task.getImportanceColors(activity.getResources());
} }
detailLoader = new DetailLoaderThread();
detailLoader.start();
} }
/* ====================================================================== /* ======================================================================
@ -221,6 +214,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
ViewHolder viewHolder = ((ViewHolder)view.getTag()); ViewHolder viewHolder = ((ViewHolder)view.getTag());
Task task = viewHolder.task; Task task = viewHolder.task;
task.clear();
task.readFromCursor(cursor); task.readFromCursor(cursor);
setFieldContentsAndVisibility(view); setFieldContentsAndVisibility(view);
@ -324,9 +318,21 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
importanceView.setBackgroundColor(0); importanceView.setBackgroundColor(0);
} }
String details;
if(tasksToLoad.containsKey(task.getId()))
details = tasksToLoad.get(task.getId()).getValue(Task.DETAILS);
else
details = task.getValue(Task.DETAILS);
if(TextUtils.isEmpty(details)) {
viewHolder.details.setVisibility(View.GONE);
} else {
viewHolder.details.setVisibility(View.VISIBLE);
viewHolder.details.setText(Html.fromHtml(details.trim().replace("\n", //$NON-NLS-1$
"<br>"), detailImageGetter, null)); //$NON-NLS-1$
}
// details and decorations, expanded // details and decorations, expanded
if(!isFling) { if(!isFling) {
detailManager.request(viewHolder);
decorationManager.request(viewHolder); decorationManager.request(viewHolder);
if(expanded == task.getId()) { if(expanded == task.getId()) {
extendedDetailManager.request(viewHolder); extendedDetailManager.request(viewHolder);
@ -337,8 +343,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
} else { } else {
long taskId = viewHolder.task.getId(); long taskId = viewHolder.task.getId();
detailManager.reset(viewHolder, taskId);
decorationManager.reset(viewHolder, taskId); decorationManager.reset(viewHolder, taskId);
viewHolder.extendedDetails.setVisibility(View.GONE);
viewHolder.actions.setVisibility(View.GONE);
} }
} }
@ -360,27 +367,69 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
/* ====================================================================== /* ======================================================================
* ============================================================== add-ons * ============================================================== details
* ====================================================================== */ * ====================================================================== */
/** private final Map<Long, Task> tasksToLoad = Collections.synchronizedMap(new HashMap<Long, Task>());
* Called to tell the cache to be cleared
*/ public class DetailLoaderThread extends Thread {
public void flushCaches() { @Override
detailManager.clearCache(); public void run() {
extendedDetailManager.clearCache(); // for all of the tasks returned by our cursor, verify details
decorationManager.clearCache(); TodorooCursor<Task> fetchCursor = taskService.fetchFiltered(
taskActionManager.clearCache(); query.get(), null, Task.ID, Task.DETAILS);
activity.startManagingCursor(fetchCursor);
Task task = new Task();
for(fetchCursor.moveToFirst(); !fetchCursor.isAfterLast(); fetchCursor.moveToNext()) {
task.clear();
task.readFromCursor(fetchCursor);
if(!task.containsNonNullValue(Task.DETAILS)) {
System.err.println("READING details for " + task.getId());
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
Task loadHolder = new Task(fetchCursor);
tasksToLoad.put(task.getId(), loadHolder);
task.setValue(Task.DETAILS, ""); //$NON-NLS-1$
taskService.save(task);
}
}
}
} }
/** /**
* AddOnManager for Details * Add detail to a task
* @author Tim Su <tim@todoroo.com>
* *
* @param id
* @param detail
*/ */
public class DetailManager extends AddOnManager<String> { public void addDetails(long id, String detail) {
final Task task = tasksToLoad.get(id);
if(task == null)
return;
String newDetails = task.getValue(Task.DETAILS);
if(TextUtils.isEmpty(newDetails))
newDetails = detail;
else if(newDetails.contains(detail))
return;
else
newDetails += DETAIL_SEPARATOR + detail;
task.setValue(Task.DETAILS, newDetails);
taskService.save(task);
private final ImageGetter imageGetter = new ImageGetter() { activity.runOnUiThread(new Runnable() {
@Override
public void run() {
notifyDataSetInvalidated();
}
});
}
private final ImageGetter detailImageGetter = new ImageGetter() {
public Drawable getDrawable(String source) { public Drawable getDrawable(String source) {
Resources r = activity.getResources(); Resources r = activity.getResources();
int drawable = r.getIdentifier("drawable/" + source, null, Constants.PACKAGE); //$NON-NLS-1$ int drawable = r.getIdentifier("drawable/" + source, null, Constants.PACKAGE); //$NON-NLS-1$
@ -392,50 +441,43 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
}; };
private final boolean extended; /* ======================================================================
public DetailManager(boolean extended) { * ============================================================== add-ons
this.extended = extended; * ====================================================================== */
/**
* Called to tell the cache to be cleared
*/
public void flushCaches() {
extendedDetailManager.clearCache();
decorationManager.clearCache();
taskActionManager.clearCache();
detailLoader = new DetailLoaderThread();
detailLoader.start();
}
/**
* AddOnManager for Details
* @author Tim Su <tim@todoroo.com>
*
*/
public class DetailManager extends AddOnManager<String> {
public DetailManager() {
//
} }
@Override @Override
Intent createBroadcastIntent(long taskId) { Intent createBroadcastIntent(long taskId) {
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS); Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, true);
return broadcastIntent; return broadcastIntent;
} }
@Override @Override
public boolean request(final ViewHolder viewHolder) { public void addNew(long taskId, String addOn, String item) {
if(super.request(viewHolder)) { super.addNew(taskId, addOn, item);
final long taskId = viewHolder.task.getId();
// load internal details
new Thread() {
@Override
public void run() {
for(DetailExposer exposer : EXPOSERS) {
final String detail = exposer.getTaskDetails(activity,
taskId, extended);
if(detail == null)
continue;
final Collection<String> cacheList =
addIfNotExists(taskId, exposer.getPluginIdentifier(),
detail);
if(cacheList != null) {
if(taskId != viewHolder.task.getId())
continue;
activity.runOnUiThread(new Runnable() {
public void run() {
draw(viewHolder, taskId, cacheList);
}
});
}
}
};
}.start();
return true;
}
return false;
} }
@SuppressWarnings("nls") @SuppressWarnings("nls")
@ -443,9 +485,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
void draw(ViewHolder viewHolder, long taskId, Collection<String> details) { void draw(ViewHolder viewHolder, long taskId, Collection<String> details) {
if(details == null || viewHolder.task.getId() != taskId) if(details == null || viewHolder.task.getId() != taskId)
return; return;
TextView view = extended ? viewHolder.extendedDetails : viewHolder.details; TextView view = viewHolder.extendedDetails;
if(details.isEmpty() || (expanded != taskId)) {
reset(viewHolder, taskId); reset(viewHolder, taskId);
if(details.isEmpty() || (extended && expanded != taskId)) {
return; return;
} }
view.setVisibility(View.VISIBLE); view.setVisibility(View.VISIBLE);
@ -457,7 +499,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
String string = detailText.toString(); String string = detailText.toString();
if(string.contains("<")) if(string.contains("<"))
view.setText(Html.fromHtml(string.trim().replace("\n", "<br>"), imageGetter, null)); view.setText(Html.fromHtml(string.trim().replace("\n", "<br>"),
detailImageGetter, null));
else else
view.setText(string.trim()); view.setText(string.trim());
Linkify.addLinks(view, Linkify.ALL); Linkify.addLinks(view, Linkify.ALL);
@ -465,7 +508,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
@Override @Override
void reset(ViewHolder viewHolder, long taskId) { void reset(ViewHolder viewHolder, long taskId) {
TextView view = extended ? viewHolder.extendedDetails : viewHolder.details; TextView view = viewHolder.extendedDetails;
view.setVisibility(View.GONE); view.setVisibility(View.GONE);
} }
} }
@ -533,6 +576,11 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
* *
*/ */
public class TaskActionManager extends AddOnManager<TaskAction> { public class TaskActionManager extends AddOnManager<TaskAction> {
private final LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT, 1f);
@Override @Override
Intent createBroadcastIntent(long taskId) { Intent createBroadcastIntent(long taskId) {
Intent intent = new Intent(AstridApiConstants.BROADCAST_REQUEST_ACTIONS); Intent intent = new Intent(AstridApiConstants.BROADCAST_REQUEST_ACTIONS);
@ -545,15 +593,24 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
if(actions == null || viewHolder.task.getId() != taskId) if(actions == null || viewHolder.task.getId() != taskId)
return; return;
reset(viewHolder, taskId); // hack because we know we have > 1 button
if(addOnService.hasPowerPack() && actions.size() == 0)
LinearLayout.LayoutParams params = return;
new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT, 1f);
for(int i = viewHolder.actions.getChildCount(); i < actions.size() + 1; i++) {
Button editButton = new Button(activity); Button editButton = new Button(activity);
editButton.setText(R.string.TAd_actionEditTask); editButton.setLayoutParams(params);
editButton.setOnClickListener(new OnClickListener() { viewHolder.actions.addView(editButton);
}
if(actions.size() + 1 < viewHolder.actions.getChildCount())
viewHolder.actions.removeViews(0, viewHolder.actions.getChildCount() -
actions.size() - 1);
int i = 0;
Button button = (Button) viewHolder.actions.getChildAt(i++);
button.setText(R.string.TAd_actionEditTask);
button.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View arg0) { public void onClick(View arg0) {
Intent intent = new Intent(activity, TaskEditActivity.class); Intent intent = new Intent(activity, TaskEditActivity.class);
@ -561,17 +618,14 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
activity.startActivityForResult(intent, TaskListActivity.ACTIVITY_EDIT_TASK); activity.startActivityForResult(intent, TaskListActivity.ACTIVITY_EDIT_TASK);
} }
}); });
editButton.setLayoutParams(params);
viewHolder.actions.addView(editButton);
for(TaskAction action : actions) { for(TaskAction action : actions) {
Button view = new Button(activity); button = (Button) viewHolder.actions.getChildAt(i++);
view.setText(action.text); button.setText(action.text);
view.setOnClickListener(new ActionClickListener(action)); button.setOnClickListener(new ActionClickListener(action));
view.setLayoutParams(params);
viewHolder.actions.addView(view);
} }
reset(viewHolder, taskId);
} }
@Override @Override
@ -581,7 +635,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
return; return;
} }
viewHolder.actions.setVisibility(View.VISIBLE); viewHolder.actions.setVisibility(View.VISIBLE);
viewHolder.actions.removeAllViews();
} }
} }

@ -1,26 +0,0 @@
package com.todoroo.astrid.api;
import android.content.Context;
/**
* Internal API for Task Details
*
* @author Tim Su <tim@todoroo.com>
*
*/
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 String getTaskDetails(Context context, long id, boolean extended);
public String getPluginIdentifier();
}

@ -28,7 +28,7 @@ public class Database extends AbstractDatabase {
* Database version number. This variable must be updated when database * Database version number. This variable must be updated when database
* tables are updated, as it determines whether a database needs updating. * tables are updated, as it determines whether a database needs updating.
*/ */
public static final int VERSION = 4; public static final int VERSION = 5;
/** /**
* Database name (must be unique) * Database name (must be unique)
@ -119,6 +119,10 @@ public class Database extends AbstractDatabase {
append(')'); append(')');
database.execSQL(sql.toString()); database.execSQL(sql.toString());
} }
case 4: {
database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " +
Task.DETAILS.accept(visitor, null));
}
return true; return true;
} }

@ -157,6 +157,10 @@ public class TaskDao extends GenericDao<Task> {
return false; return false;
} }
// clear task detail cache
if(values != null && !values.containsKey(Task.DETAILS.name))
values.put(Task.DETAILS.name, (String)null);
if (task.getId() == Task.NO_ID) { if (task.getId() == Task.NO_ID) {
saveSuccessful = createNew(task); saveSuccessful = createNew(task);
} else { } else {

@ -14,11 +14,11 @@ import android.content.res.Resources;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.data.TodorooCursor;
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.TodorooCursor;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
/** /**
@ -72,7 +72,13 @@ public final class Task extends AbstractModel {
public static final LongProperty DELETION_DATE = new LongProperty( public static final LongProperty DELETION_DATE = new LongProperty(
TABLE, "deleted"); TABLE, "deleted");
// --- for migration purposes from astrid 2 (eventually we will want to /** Cached Details Column - built from add-on detail exposers. A null
* value means there is no value in the cache and it needs to be
* refreshed */
public static final StringProperty DETAILS = new StringProperty(
TABLE, "details");
// --- for migration purposes from astrid 2 (eventually we may want to
// move these into the metadata table and treat them as plug-ins // move these into the metadata table and treat them as plug-ins
public static final StringProperty NOTES = new StringProperty( public static final StringProperty NOTES = new StringProperty(
@ -179,6 +185,7 @@ public final class Task extends AbstractModel {
defaultValues.put(NOTES.name, ""); defaultValues.put(NOTES.name, "");
defaultValues.put(FLAGS.name, 0); defaultValues.put(FLAGS.name, 0);
defaultValues.put(TIMER_START.name, 0); defaultValues.put(TIMER_START.name, 0);
defaultValues.put(DETAILS.name, (String)null);
} }
@Override @Override

Loading…
Cancel
Save