Refactored task adapter add on manager into own class, fixed a bug with detail loading, updated task details to not use broadcast receiver, added skeleton google order actions

pull/14/head
Tim Su 14 years ago
parent aa7ed3dc94
commit 459009f39c

@ -211,6 +211,63 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- gtasks -->
<receiver android:name="com.todoroo.astrid.gtasks.GtasksFilterExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity android:name="com.todoroo.astrid.gtasks.GtasksPreferences"
android:label="@string/gtasks_GPr_header">
<meta-data android:name="category"
android:resource="@string/SyP_label" />
<intent-filter>
<action android:name="com.todoroo.astrid.SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksSyncActionExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_SYNC_ACTIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksIndentAction$GtasksIncreaseIndentAction"
android:label="@string/gtasks_increase_indent">
<intent-filter>
<action android:name="com.todoroo.astrid.CONTEXT_MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksIndentAction$GtasksDecreaseIndentAction"
android:label="@string/gtasks_decrease_indent">
<intent-filter>
<action android:name="com.todoroo.astrid.CONTEXT_MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksOrderAction$GtasksMoveUpAction"
android:label="@string/gtasks_move_up">
<intent-filter>
<action android:name="com.todoroo.astrid.CONTEXT_MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksOrderAction$GtasksMoveDownAction"
android:label="@string/gtasks_move_down">
<intent-filter>
<action android:name="com.todoroo.astrid.CONTEXT_MENU" />
<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">
<intent-filter> <intent-filter>
@ -308,12 +365,6 @@
</receiver> </receiver>
<!-- timers --> <!-- timers -->
<receiver android:name="com.todoroo.astrid.timers.TimerDecorationExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DECORATIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.timers.TimerActionExposer"> <receiver android:name="com.todoroo.astrid.timers.TimerActionExposer">
<intent-filter> <intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_ACTIONS" /> <action android:name="com.todoroo.astrid.REQUEST_ACTIONS" />
@ -437,49 +488,6 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- gtasks -->
<receiver android:name="com.todoroo.astrid.gtasks.GtasksFilterExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity android:name="com.todoroo.astrid.gtasks.GtasksPreferences"
android:label="@string/gtasks_GPr_header">
<meta-data android:name="category"
android:resource="@string/SyP_label" />
<intent-filter>
<action android:name="com.todoroo.astrid.SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksSyncActionExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_SYNC_ACTIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksIndentAction$GtasksIncreaseIndentAction"
android:label="@string/gtasks_increase_indent">
<intent-filter>
<action android:name="com.todoroo.astrid.CONTEXT_MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.gtasks.GtasksIndentAction$GtasksDecreaseIndentAction"
android:label="@string/gtasks_decrease_indent">
<intent-filter>
<action android:name="com.todoroo.astrid.CONTEXT_MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>

@ -9,11 +9,11 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.TaskDecoration; import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.api.TaskDecorationExposer; import com.todoroo.astrid.api.TaskDecorationExposer;
import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.utility.Flags;
/** /**
* Exposes {@link TaskDecoration} for GTasks indentation * Exposes {@link TaskDecoration} for GTasks indentation
@ -31,11 +31,11 @@ public class GtasksDecorationExposer implements TaskDecorationExposer {
} }
@Override @Override
public TaskDecoration expose(Filter activeFilter, Task task) { public TaskDecoration expose(Task task) {
if(!gtasksPreferenceService.isLoggedIn()) if(!gtasksPreferenceService.isLoggedIn())
return null; return null;
if(!activeFilter.sqlQuery.contains(GtasksMetadata.METADATA_KEY)) if(Flags.checkAndClear(Flags.GTASKS))
return null; return null;
return createDecoration(task); return createDecoration(task);

@ -12,7 +12,13 @@ import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.utility.Flags;
/**
* Context Menu actions for changing indent level of a task
* @author Tim Su <tim@todoroo.com>
*
*/
abstract public class GtasksIndentAction extends BroadcastReceiver { abstract public class GtasksIndentAction extends BroadcastReceiver {
@Autowired private GtasksMetadataService gtasksMetadataService; @Autowired private GtasksMetadataService gtasksMetadataService;
@ -37,6 +43,7 @@ abstract public class GtasksIndentAction extends BroadcastReceiver {
metadata.setValue(GtasksMetadata.INDENTATION, newIndent); metadata.setValue(GtasksMetadata.INDENTATION, newIndent);
PluginServices.getMetadataService().save(metadata); PluginServices.getMetadataService().save(metadata);
Flags.set(Flags.REFRESH);
Toast.makeText(context, context.getString(R.string.gtasks_indent_toast, newIndent), Toast.makeText(context, context.getString(R.string.gtasks_indent_toast, newIndent),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }

@ -0,0 +1,61 @@
package com.todoroo.astrid.gtasks;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.utility.Flags;
/**
* Context Menu actions for changing the order of a task
* @author Tim Su <tim@todoroo.com>
*
*/
abstract public class GtasksOrderAction extends BroadcastReceiver {
@Autowired private GtasksMetadataService gtasksMetadataService;
abstract int getDelta();
@Override
public void onReceive(Context context, Intent intent) {
ContextManager.setContext(context);
DependencyInjectionService.getInstance().inject(this);
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
if(taskId == -1)
return;
Metadata metadata = gtasksMetadataService.getTaskMetadata(taskId);
if(metadata == null) {
metadata = GtasksMetadata.createEmptyMetadata(taskId);
}
// TODO
PluginServices.getMetadataService().save(metadata);
Flags.set(Flags.REFRESH);
}
public static class GtasksMoveUpAction extends GtasksOrderAction {
@Override
public int getDelta() {
return -1;
}
}
public static class GtasksMoveDownAction extends GtasksOrderAction {
@Override
public int getDelta() {
return 1;
}
}
}

@ -3,11 +3,6 @@
*/ */
package com.todoroo.astrid.timers; package com.todoroo.astrid.timers;
import java.util.HashMap;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.os.SystemClock; import android.os.SystemClock;
import android.text.format.DateUtils; import android.text.format.DateUtils;
@ -15,10 +10,10 @@ import android.view.View;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.TaskDecoration; import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.api.TaskDecorationExposer;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
/** /**
@ -27,51 +22,21 @@ import com.todoroo.astrid.data.Task;
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class TimerDecorationExposer extends BroadcastReceiver { public class TimerDecorationExposer implements TaskDecorationExposer {
private static final int TIMING_BG_COLOR = Color.argb(200, 220, 50, 0); private static final int TIMING_BG_COLOR = Color.argb(200, 220, 50, 0);
private static HashMap<Long, TaskDecoration> decorations =
new HashMap<Long, TaskDecoration>();
private static HashMap<Long, Boolean> tasksNeedingUpdate =
new HashMap<Long, Boolean>();
public static void updateTimer(long taskId) {
decorations.remove(taskId);
tasksNeedingUpdate.put(taskId, true);
}
@Override @Override
public void onReceive(Context context, Intent intent) { public TaskDecoration expose(Task task) {
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); if(task == null || (task.getValue(Task.ELAPSED_SECONDS) == 0 &&
if(taskId == -1)
return;
Task task;
try {
if(tasksNeedingUpdate.containsKey(taskId))
task = PluginServices.getTaskService().fetchById(taskId, Task.ID, Task.ELAPSED_SECONDS, Task.TIMER_START);
else
task = intent.getParcelableExtra("model"); //$NON-NLS-1$
} catch (IllegalStateException e) {
return;
}
if(task == null || task.getId() != taskId || (task.getValue(Task.ELAPSED_SECONDS) == 0 &&
task.getValue(Task.TIMER_START) == 0)) task.getValue(Task.TIMER_START) == 0))
return; return null;
TaskDecoration decoration; TaskDecoration decoration;
if(!decorations.containsKey(taskId)) { RemoteViews remoteViews = new RemoteViews(ContextManager.getContext().getPackageName(),
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.timer_decoration); R.layout.timer_decoration);
decoration = new TaskDecoration(remoteViews, decoration = new TaskDecoration(remoteViews,
TaskDecoration.POSITION_LEFT, 0); TaskDecoration.POSITION_LEFT, 0);
decorations.put(taskId, decoration);
} else {
decoration = decorations.get(taskId);
}
long elapsed = task.getValue(Task.ELAPSED_SECONDS) * 1000L; long elapsed = task.getValue(Task.ELAPSED_SECONDS) * 1000L;
if(task.getValue(Task.TIMER_START) != 0) { if(task.getValue(Task.TIMER_START) != 0) {
@ -91,13 +56,7 @@ public class TimerDecorationExposer extends BroadcastReceiver {
decoration.decoration.setViewVisibility(R.id.label, View.VISIBLE); decoration.decoration.setViewVisibility(R.id.label, View.VISIBLE);
} }
return decoration;
// 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);
} }
private String buildFormat(long elapsed) { private String buildFormat(long elapsed) {

@ -36,7 +36,7 @@ public class TimerPlugin extends BroadcastReceiver {
} }
/** /**
* stops timer and sets elapsed time. you still need to save the task. * toggles timer and updates elapsed time.
* @param task * @param task
* @param start if true, start timer. else, stop it * @param start if true, start timer. else, stop it
*/ */
@ -53,12 +53,10 @@ public class TimerPlugin extends BroadcastReceiver {
} }
} }
PluginServices.getTaskService().save(task); PluginServices.getTaskService().save(task);
TimerDecorationExposer.updateTimer(task.getId());
// transmit new intents // transmit new intents
Intent intent = new Intent(AstridApiConstants.BROADCAST_REQUEST_ACTIONS); Intent intent = new Intent(AstridApiConstants.BROADCAST_REQUEST_ACTIONS);
intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
new TimerDecorationExposer().onReceive(context, intent);
new TimerActionExposer().onReceive(context, intent); new TimerActionExposer().onReceive(context, intent);
// update notification // update notification

@ -13,11 +13,17 @@
<!-- GTasks Indent changed message (%d => new level) --> <!-- GTasks Indent changed message (%d => new level) -->
<string name="gtasks_indent_toast">New Indentation: %d</string> <string name="gtasks_indent_toast">New Indentation: %d</string>
<!-- GTasks label: move up -->
<string name="gtasks_move_up">▲ Move Up</string>
<!-- GTasks label: increase indent --> <!-- GTasks label: increase indent -->
<string name="gtasks_increase_indent">Move Right</string> <string name="gtasks_increase_indent">Move Right</string>
<!-- GTasks label: decrease indent --> <!-- GTasks label: decrease indent -->
<string name="gtasks_decrease_indent">Move Left</string> <string name="gtasks_decrease_indent">◀ Move Left</string>
<!-- GTasks label: move down -->
<string name="gtasks_move_down">▼ Move Down</string>
<!-- ============================================== GtasksPreferences == --> <!-- ============================================== GtasksPreferences == -->

@ -75,6 +75,7 @@ import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader;
import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader.ContextMenuItem; import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader.ContextMenuItem;
import com.todoroo.astrid.reminders.Notifications; import com.todoroo.astrid.reminders.Notifications;
@ -617,6 +618,10 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
TodorooCursor<Task> currentCursor = taskService.fetchFiltered( TodorooCursor<Task> currentCursor = taskService.fetchFiltered(
sqlQueryTemplate.get(), null, TaskAdapter.PROPERTIES); sqlQueryTemplate.get(), null, TaskAdapter.PROPERTIES);
startManagingCursor(currentCursor); startManagingCursor(currentCursor);
if(sqlQueryTemplate.get().contains(GtasksMetadata.METADATA_KEY))
Flags.set(Flags.GTASKS);
else
Flags.checkAndClear(Flags.GTASKS);
// set up list adapters // set up list adapters
taskAdapter = new TaskAdapter(this, R.layout.task_adapter_row, taskAdapter = new TaskAdapter(this, R.layout.task_adapter_row,

@ -35,7 +35,6 @@ import android.widget.CheckBox;
import android.widget.CursorAdapter; import android.widget.CursorAdapter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import com.timsu.astrid.R; import com.timsu.astrid.R;
@ -51,9 +50,13 @@ import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
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.api.TaskDecorationExposer;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksDecorationExposer;
import com.todoroo.astrid.helper.TaskAdapterAddOnManager;
import com.todoroo.astrid.service.AddOnService; import com.todoroo.astrid.service.AddOnService;
import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.timers.TimerDecorationExposer;
import com.todoroo.astrid.utility.Constants; import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.utility.Preferences; import com.todoroo.astrid.utility.Preferences;
@ -118,10 +121,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// --- task detail and decoration soft caches // --- task detail and decoration soft caches
public final ExtendedDetailManager extendedDetailManager = new ExtendedDetailManager(); public final ExtendedDetailManager extendedDetailManager;
public final DecorationManager decorationManager = public final DecorationManager decorationManager;
new DecorationManager(); public final TaskActionManager taskActionManager;
public final TaskActionManager taskActionManager = new TaskActionManager();
/** /**
* Constructor * Constructor
@ -159,6 +161,10 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
detailLoader = new DetailLoaderThread(); detailLoader = new DetailLoaderThread();
detailLoader.start(); detailLoader.start();
extendedDetailManager = new ExtendedDetailManager();
decorationManager = new DecorationManager();
taskActionManager = new TaskActionManager();
} }
/* ====================================================================== /* ======================================================================
@ -399,8 +405,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// it's best to do this, though, in order to append details to each other // it's best to do this, though, in order to append details to each other
private final Map<Long, StringBuilder> taskDetailLoader = Collections.synchronizedMap(new HashMap<Long, StringBuilder>(0)); private final Map<Long, StringBuilder> taskDetailLoader = Collections.synchronizedMap(new HashMap<Long, StringBuilder>(0));
private final Task taskDetailContainer = new Task();
public class DetailLoaderThread extends Thread { public class DetailLoaderThread extends Thread {
@Override @Override
public void run() { public void run() {
@ -412,7 +416,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
activity.startManagingCursor(fetchCursor); activity.startManagingCursor(fetchCursor);
Random random = new Random(); Random random = new Random();
try { try {
Task task = taskDetailContainer; Task task = new Task();
for(fetchCursor.moveToFirst(); !fetchCursor.isAfterLast(); fetchCursor.moveToNext()) { for(fetchCursor.moveToFirst(); !fetchCursor.isAfterLast(); fetchCursor.moveToNext()) {
task.clear(); task.clear();
task.readFromCursor(fetchCursor); task.readFromCursor(fetchCursor);
@ -425,15 +429,21 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
taskDetailLoader.put(task.getId(), taskDetailLoader.put(task.getId(),
new StringBuilder(task.getValue(Task.DETAILS))); new StringBuilder(task.getValue(Task.DETAILS)));
requestNewDetails(task); requestNewDetails(task);
System.err.println("Refreshing details: " + task.getId());
} }
continue; continue;
} else {
System.err.println("Forced loading of details: " + task.getId() +
"\n details: " + new Date(task.getValue(Task.DETAILS_DATE)) +
"\n modified: " + new Date(task.getValue(Task.MODIFICATION_DATE)));
} }
addTaskToLoadingArray(task); addTaskToLoadingArray(task);
requestNewDetails(task);
task.setValue(Task.DETAILS, DETAIL_SEPARATOR); task.setValue(Task.DETAILS, DETAIL_SEPARATOR);
task.setValue(Task.DETAILS_DATE, DateUtilities.now()); task.setValue(Task.DETAILS_DATE, DateUtilities.now());
taskService.save(task); taskService.save(task);
requestNewDetails(task);
} }
} catch (Exception e) { } catch (Exception e) {
// suppress silently // suppress silently
@ -472,18 +482,15 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
synchronized(details) { synchronized(details) {
if(details.toString().contains(detail)) if(details.toString().contains(detail))
return; return;
if(details.length() > 0 && !details.toString().endsWith(DETAIL_SEPARATOR)) if(details.length() > 0)
details.append(DETAIL_SEPARATOR); details.append(DETAIL_SEPARATOR);
else if(details.equals(DETAIL_SEPARATOR))
details.setLength(0);
details.append(detail); details.append(detail);
taskDetailContainer.setId(id); Task task = new Task();
String detailsAsString = details.toString(); task.setId(id);
if(detailsAsString.startsWith(DETAIL_SEPARATOR)) System.err.println("task " + id + " - '" + details.toString() + "' (" + detail + ")");
detailsAsString = detailsAsString.substring(DETAIL_SEPARATOR.length()); task.setValue(Task.DETAILS, details.toString());
taskDetailContainer.setValue(Task.DETAILS, details.toString()); task.setValue(Task.DETAILS_DATE, DateUtilities.now());
taskDetailContainer.setValue(Task.DETAILS_DATE, DateUtilities.now()); taskService.save(task);
taskService.save(taskDetailContainer);
} }
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@ -544,14 +551,15 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class ExtendedDetailManager extends AddOnManager<String> { public class ExtendedDetailManager extends TaskAdapterAddOnManager<String> {
private final Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS); private final Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
public ExtendedDetailManager() { public ExtendedDetailManager() {
// super(activity);
} }
@Override @Override
protected
Intent createBroadcastIntent(Task task) { Intent createBroadcastIntent(Task task) {
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, true); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, true);
@ -567,6 +575,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
@SuppressWarnings("nls") @SuppressWarnings("nls")
@Override @Override
protected
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;
@ -594,7 +603,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
@Override @Override
void reset(ViewHolder viewHolder, long taskId) { protected void reset(ViewHolder viewHolder, long taskId) {
TextView view = viewHolder.extendedDetails; TextView view = viewHolder.extendedDetails;
view.setVisibility(View.GONE); view.setVisibility(View.GONE);
} }
@ -606,27 +615,45 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class DecorationManager extends AddOnManager<TaskDecoration> { public class DecorationManager extends TaskAdapterAddOnManager<TaskDecoration> {
private final Intent intent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DECORATIONS);
@Override public DecorationManager() {
Intent createBroadcastIntent(Task task) { super(activity);
// performance hack, get rid of me when task list performance is improved
if(isFling || task.getValue(Task.TIMER_START) == 0 &&
task.getValue(Task.ELAPSED_SECONDS) == 0)
return null;
intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
intent.putExtra(BROADCAST_EXTRA_TASK, task);
return intent;
} }
private final TaskDecorationExposer[] exposers = new TaskDecorationExposer[] {
new TimerDecorationExposer(),
new GtasksDecorationExposer()
};
/**
* Request add-ons for the given task
* @return true if cache miss, false if cache hit
*/
@Override @Override
public void addNew(long taskId, String addOn, TaskDecoration item) { public boolean request(ViewHolder viewHolder) {
super.addNew(taskId, addOn, item); long taskId = viewHolder.task.getId();
Collection<TaskDecoration> list = initialize(taskId);
if(list != null) {
draw(viewHolder, taskId, list);
return false;
}
// request details
draw(viewHolder, taskId, get(taskId));
for(TaskDecorationExposer exposer : exposers) {
TaskDecoration deco = exposer.expose(viewHolder.task);
if(deco != null)
addNew(viewHolder.task.getId(), exposer.getClass().getName(), deco);
}
return true;
} }
@Override @Override
void draw(ViewHolder viewHolder, long taskId, Collection<TaskDecoration> decorations) { protected void draw(ViewHolder viewHolder, long taskId, Collection<TaskDecoration> decorations) {
if(decorations == null || viewHolder.task.getId() != taskId) if(decorations == null || viewHolder.task.getId() != taskId)
return; return;
@ -660,7 +687,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
@Override @Override
void reset(ViewHolder viewHolder, long taskId) { protected void reset(ViewHolder viewHolder, long taskId) {
if(viewHolder.decorations != null) { if(viewHolder.decorations != null) {
for(View view : viewHolder.decorations) for(View view : viewHolder.decorations)
viewHolder.taskRow.removeView(view); viewHolder.taskRow.removeView(view);
@ -670,6 +697,11 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
else else
viewHolder.view.setBackgroundResource(android.R.drawable.list_selector_background); viewHolder.view.setBackgroundResource(android.R.drawable.list_selector_background);
} }
@Override
protected Intent createBroadcastIntent(Task task) {
return null;
}
} }
/** /**
@ -678,7 +710,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
* @author Tim Su <tim@todoroo.com> * @author Tim Su <tim@todoroo.com>
* *
*/ */
public class TaskActionManager extends AddOnManager<TaskAction> { public class TaskActionManager extends TaskAdapterAddOnManager<TaskAction> {
private final LinearLayout.LayoutParams params = private final LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
@ -686,14 +718,18 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private final Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_ACTIONS); private final Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_ACTIONS);
public TaskActionManager() {
super(activity);
}
@Override @Override
Intent createBroadcastIntent(Task task) { protected Intent createBroadcastIntent(Task task) {
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
return broadcastIntent; return broadcastIntent;
} }
@Override @Override
void draw(final ViewHolder viewHolder, final long taskId, Collection<TaskAction> actions) { protected void draw(final ViewHolder viewHolder, final long taskId, Collection<TaskAction> actions) {
if(actions == null || viewHolder.task.getId() != taskId) if(actions == null || viewHolder.task.getId() != taskId)
return; return;
@ -735,7 +771,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
@Override @Override
void reset(ViewHolder viewHolder, long taskId) { protected void reset(ViewHolder viewHolder, long taskId) {
if(expanded != taskId) { if(expanded != taskId) {
viewHolder.actions.setVisibility(View.GONE); viewHolder.actions.setVisibility(View.GONE);
return; return;
@ -873,122 +909,4 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
} }
} }
/* ======================================================================
* ========================================================= addon helper
* ====================================================================== */
abstract public class AddOnManager<TYPE> {
private final Map<Long, HashMap<String, TYPE>> cache =
Collections.synchronizedMap(new HashMap<Long, HashMap<String, TYPE>>(0));
// --- interface
/**
* Request add-ons for the given task
* @return true if cache miss, false if cache hit
*/
public boolean request(ViewHolder viewHolder) {
long taskId = viewHolder.task.getId();
Collection<TYPE> list = initialize(taskId);
if(list != null) {
draw(viewHolder, taskId, list);
return false;
}
// request details
draw(viewHolder, taskId, get(taskId));
Intent broadcastIntent = createBroadcastIntent(viewHolder.task);
if(broadcastIntent != null)
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
return true;
}
/** creates a broadcast intent for requesting */
abstract Intent createBroadcastIntent(Task task);
/** updates the given view */
abstract void draw(ViewHolder viewHolder, long taskId, Collection<TYPE> list);
/** resets the view as if there was nothing */
abstract void reset(ViewHolder viewHolder, long taskId);
/** on receive an intent */
public void addNew(long taskId, String addOn, TYPE item) {
if(item == null)
return;
Collection<TYPE> cacheList = addIfNotExists(taskId, addOn, item);
if(cacheList != null) {
ListView listView = activity.getListView();
// 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;
draw(viewHolder, taskId, cacheList);
break;
}
}
}
/**
* Clears the cache
*/
public void clearCache() {
cache.clear();
}
/**
* Clears single item from cache
*/
public void clearCache(long taskId) {
cache.remove(taskId);
}
// --- internal goodies
/**
* 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
*/
protected synchronized Collection<TYPE> initialize(long taskId) {
if(cache.containsKey(taskId) && cache.get(taskId) != null)
return get(taskId);
cache.put(taskId, new HashMap<String, TYPE>(0));
return null;
}
/**
* Adds an item to the cache if it doesn't exist
* @param taskId
* @param item
* @return iterator if item was added, null if it already existed
*/
protected synchronized Collection<TYPE> addIfNotExists(long taskId, String addOn,
TYPE item) {
HashMap<String, TYPE> list = cache.get(taskId);
if(list == null)
return null;
if(list.containsKey(addOn) && list.get(addOn).equals(item))
return null;
list.put(addOn, item);
return get(taskId);
}
/**
* Gets an item at the given index
* @param taskId
* @return
*/
protected Collection<TYPE> get(long taskId) {
return cache.get(taskId).values();
}
}
} }

@ -12,10 +12,10 @@ public interface TaskDecorationExposer {
/** /**
* Expose task decorations for the given task * Expose task decorations for the given task
*
* @param task * @param task
*
* @return null if no decorations, or decoration * @return null if no decorations, or decoration
*/ */
public TaskDecoration expose(Filter activeFilter, Task task); public TaskDecoration expose(Task task);
} }

@ -211,10 +211,11 @@ public class TaskDao extends DatabaseDao<Task> {
@Override @Override
public boolean saveExisting(Task item) { public boolean saveExisting(Task item) {
if(!item.getSetValues().containsKey(Task.DETAILS.name)) if(!item.getSetValues().containsKey(Task.DETAILS_DATE.name)) {
item.setValue(Task.DETAILS, null); item.setValue(Task.DETAILS, null);
if(!item.getSetValues().containsKey(Task.DETAILS_DATE.name))
item.setValue(Task.MODIFICATION_DATE, DateUtilities.now()); item.setValue(Task.MODIFICATION_DATE, DateUtilities.now());
}
System.err.println(">> SAVE EXISTING: " + item.getSetValues());
return super.saveExisting(item); return super.saveExisting(item);
} }

@ -0,0 +1,140 @@
/**
*
*/
package com.todoroo.astrid.helper;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import android.app.ListActivity;
import android.content.Intent;
import android.widget.ListView;
import com.todoroo.astrid.adapter.TaskAdapter.ViewHolder;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.data.Task;
abstract public class TaskAdapterAddOnManager<TYPE> {
private final ListActivity activity;
/**
* @param taskAdapter
*/
protected TaskAdapterAddOnManager(ListActivity activity) {
this.activity = activity;
}
private final Map<Long, HashMap<String, TYPE>> cache =
Collections.synchronizedMap(new HashMap<Long, HashMap<String, TYPE>>(0));
// --- interface
/**
* Request add-ons for the given task
* @return true if cache miss, false if cache hit
*/
public boolean request(ViewHolder viewHolder) {
long taskId = viewHolder.task.getId();
Collection<TYPE> list = initialize(taskId);
if(list != null) {
draw(viewHolder, taskId, list);
return false;
}
// request details
draw(viewHolder, taskId, get(taskId));
Intent broadcastIntent = createBroadcastIntent(viewHolder.task);
if(broadcastIntent != null)
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
return true;
}
/** creates a broadcast intent for requesting */
abstract protected Intent createBroadcastIntent(Task task);
/** updates the given view */
abstract protected void draw(ViewHolder viewHolder, long taskId, Collection<TYPE> list);
/** resets the view as if there was nothing */
abstract protected void reset(ViewHolder viewHolder, long taskId);
/** on receive an intent */
public void addNew(long taskId, String addOn, TYPE item) {
if(item == null)
return;
Collection<TYPE> cacheList = addIfNotExists(taskId, addOn, item);
if(cacheList != null) {
ListView listView = activity.getListView();
// 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;
draw(viewHolder, taskId, cacheList);
break;
}
}
}
/**
* Clears the cache
*/
public void clearCache() {
cache.clear();
}
/**
* Clears single item from cache
*/
public void clearCache(long taskId) {
cache.remove(taskId);
}
// --- internal goodies
/**
* 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
*/
protected synchronized Collection<TYPE> initialize(long taskId) {
if(cache.containsKey(taskId) && cache.get(taskId) != null)
return get(taskId);
cache.put(taskId, new HashMap<String, TYPE>(0));
return null;
}
/**
* Adds an item to the cache if it doesn't exist
* @param taskId
* @param item
* @return iterator if item was added, null if it already existed
*/
protected synchronized Collection<TYPE> addIfNotExists(long taskId, String addOn,
TYPE item) {
HashMap<String, TYPE> list = cache.get(taskId);
if(list == null)
return null;
if(list.containsKey(addOn) && list.get(addOn).equals(item))
return null;
list.put(addOn, item);
return get(taskId);
}
/**
* Gets an item at the given index
* @param taskId
* @return
*/
protected Collection<TYPE> get(long taskId) {
return cache.get(taskId).values();
}
}

@ -7,7 +7,12 @@ public class Flags {
/** /**
* Whether to refresh the task list * Whether to refresh the task list
*/ */
public static final int REFRESH = 1; public static final int REFRESH = 1 << 0;
/**
* Whether active filter is GTasks
*/
public static final int GTASKS = 1 << 1;
public static boolean checkAndClear(int flag) { public static boolean checkAndClear(int flag) {
boolean set = (state & flag) > 0; boolean set = (state & flag) > 0;
@ -15,6 +20,10 @@ public class Flags {
return set; return set;
} }
public static boolean check(int flag) {
return (state & flag) > 0;
}
public static void set(int flag) { public static void set(int flag) {
state |= flag; state |= flag;
} }

@ -66,7 +66,7 @@ public class GtasksDecorationExposerTest extends DatabaseTestCase {
inflated.measure(100, 100); inflated.measure(100, 100);
int width = inflated.getMeasuredWidth(); int width = inflated.getMeasuredWidth();
result = new GtasksDecorationExposer().expose(gtasksFilter(), otherTask); result = new GtasksDecorationExposer().expose(otherTask);
View otherInflated = result.decoration.apply(getContext(), null); View otherInflated = result.decoration.apply(getContext(), null);
otherInflated.measure(100, 100); otherInflated.measure(100, 100);
int otherWidth = otherInflated.getMeasuredWidth(); int otherWidth = otherInflated.getMeasuredWidth();
@ -120,7 +120,7 @@ public class GtasksDecorationExposerTest extends DatabaseTestCase {
} }
private void whenRequestingDecoration(Filter filter, Task task) { private void whenRequestingDecoration(Filter filter, Task task) {
result = new GtasksDecorationExposer().expose(filter, task); result = new GtasksDecorationExposer().expose(task);
} }
private void givenLoggedInStatus(boolean status) { private void givenLoggedInStatus(boolean status) {

Loading…
Cancel
Save