|
|
|
@ -2,6 +2,8 @@ package com.todoroo.astrid.adapter;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.Date;
|
|
|
|
import java.util.Date;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
|
|
|
import java.util.LinkedHashSet;
|
|
|
|
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Context;
|
|
|
|
@ -10,6 +12,7 @@ import android.content.res.Resources;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.graphics.Paint;
|
|
|
|
import android.graphics.Paint;
|
|
|
|
import android.text.Html;
|
|
|
|
import android.text.Html;
|
|
|
|
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.ContextMenu;
|
|
|
|
import android.view.ContextMenu;
|
|
|
|
import android.view.ContextMenu.ContextMenuInfo;
|
|
|
|
import android.view.ContextMenu.ContextMenuInfo;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
@ -98,7 +101,9 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
private final int resource;
|
|
|
|
private final int resource;
|
|
|
|
private final LayoutInflater inflater;
|
|
|
|
private final LayoutInflater inflater;
|
|
|
|
protected OnCompletedTaskListener onCompletedTaskListener = null;
|
|
|
|
protected OnCompletedTaskListener onCompletedTaskListener = null;
|
|
|
|
private final int fontSize;
|
|
|
|
private int fontSize;
|
|
|
|
|
|
|
|
private final HashMap<Long, LinkedHashSet<TaskDetail>> detailCache =
|
|
|
|
|
|
|
|
new HashMap<Long, LinkedHashSet<TaskDetail>>();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
* Constructor
|
|
|
|
@ -147,7 +152,7 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
viewHolder.nameView = (TextView)view.findViewById(R.id.title);
|
|
|
|
viewHolder.nameView = (TextView)view.findViewById(R.id.title);
|
|
|
|
viewHolder.completeBox = (CheckBox)view.findViewById(R.id.completeBox);
|
|
|
|
viewHolder.completeBox = (CheckBox)view.findViewById(R.id.completeBox);
|
|
|
|
viewHolder.dueDate = (TextView)view.findViewById(R.id.dueDate);
|
|
|
|
viewHolder.dueDate = (TextView)view.findViewById(R.id.dueDate);
|
|
|
|
viewHolder.details = (LinearLayout)view.findViewById(R.id.details);
|
|
|
|
viewHolder.details = (TextView)view.findViewById(R.id.details);
|
|
|
|
viewHolder.actions = (LinearLayout)view.findViewById(R.id.actions);
|
|
|
|
viewHolder.actions = (LinearLayout)view.findViewById(R.id.actions);
|
|
|
|
viewHolder.importance = (View)view.findViewById(R.id.importance);
|
|
|
|
viewHolder.importance = (View)view.findViewById(R.id.importance);
|
|
|
|
|
|
|
|
|
|
|
|
@ -169,11 +174,12 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void bindView(View view, Context context, Cursor c) {
|
|
|
|
public void bindView(View view, Context context, Cursor c) {
|
|
|
|
TodorooCursor<Task> cursor = (TodorooCursor<Task>)c;
|
|
|
|
TodorooCursor<Task> cursor = (TodorooCursor<Task>)c;
|
|
|
|
Task actionItem = ((ViewHolder)view.getTag()).task;
|
|
|
|
ViewHolder viewHolder = ((ViewHolder)view.getTag());
|
|
|
|
|
|
|
|
Task actionItem = viewHolder.task;
|
|
|
|
actionItem.readFromCursor(cursor);
|
|
|
|
actionItem.readFromCursor(cursor);
|
|
|
|
|
|
|
|
|
|
|
|
setFieldContentsAndVisibility(view);
|
|
|
|
setFieldContentsAndVisibility(view);
|
|
|
|
setTaskAppearance(view, actionItem.isCompleted());
|
|
|
|
setTaskAppearance(viewHolder, actionItem.isCompleted());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Helper method to set the visibility based on if there's stuff inside */
|
|
|
|
/** Helper method to set the visibility based on if there's stuff inside */
|
|
|
|
@ -190,12 +196,12 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
* @author Tim Su <tim@todoroo.com>
|
|
|
|
* @author Tim Su <tim@todoroo.com>
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public static class ViewHolder {
|
|
|
|
public class ViewHolder {
|
|
|
|
public Task task;
|
|
|
|
public Task task;
|
|
|
|
public TextView nameView;
|
|
|
|
public TextView nameView;
|
|
|
|
public CheckBox completeBox;
|
|
|
|
public CheckBox completeBox;
|
|
|
|
public TextView dueDate;
|
|
|
|
public TextView dueDate;
|
|
|
|
public LinearLayout details;
|
|
|
|
public TextView details;
|
|
|
|
public View importance;
|
|
|
|
public View importance;
|
|
|
|
public LinearLayout actions;
|
|
|
|
public LinearLayout actions;
|
|
|
|
public boolean expanded;
|
|
|
|
public boolean expanded;
|
|
|
|
@ -218,14 +224,6 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
nameView.setText(nameValue);
|
|
|
|
nameView.setText(nameValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// complete box
|
|
|
|
|
|
|
|
final CheckBox completeBox = viewHolder.completeBox; {
|
|
|
|
|
|
|
|
// show item as completed if it was recently checked
|
|
|
|
|
|
|
|
if(completedItems.containsKey(task.getId()))
|
|
|
|
|
|
|
|
task.setValue(Task.COMPLETION_DATE, DateUtilities.now());
|
|
|
|
|
|
|
|
completeBox.setChecked(task.isCompleted());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// due date / completion date
|
|
|
|
// due date / completion date
|
|
|
|
final TextView dueDateView = viewHolder.dueDate; {
|
|
|
|
final TextView dueDateView = viewHolder.dueDate; {
|
|
|
|
if(!task.isCompleted() && task.hasDueDate()) {
|
|
|
|
if(!task.isCompleted() && task.hasDueDate()) {
|
|
|
|
@ -257,54 +255,112 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// other information - send out a request for it (only if not fling)
|
|
|
|
// complete box
|
|
|
|
final LinearLayout detailsView = viewHolder.details;
|
|
|
|
final CheckBox completeBox = viewHolder.completeBox; {
|
|
|
|
|
|
|
|
// show item as completed if it was recently checked
|
|
|
|
|
|
|
|
if(completedItems.containsKey(task.getId()))
|
|
|
|
|
|
|
|
task.setValue(Task.COMPLETION_DATE, DateUtilities.now());
|
|
|
|
|
|
|
|
completeBox.setChecked(task.isCompleted());
|
|
|
|
|
|
|
|
completeBox.getLayoutParams().height = dueDateView.getHeight() +
|
|
|
|
|
|
|
|
nameView.getHeight();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// task details - send out a request for it (only if not fling)
|
|
|
|
if(!isFling) {
|
|
|
|
if(!isFling) {
|
|
|
|
detailsView.removeViews(2, detailsView.getChildCount() - 2);
|
|
|
|
retrieveDetails(viewHolder);
|
|
|
|
retrieveDetails(detailsView, task.getId());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// importance bar - must be set at end when view height is determined
|
|
|
|
// importance bar - must be set at end when view height is determined
|
|
|
|
final View importanceView = viewHolder.importance; {
|
|
|
|
final View importanceView = viewHolder.importance; {
|
|
|
|
int value = task.getValue(Task.IMPORTANCE);
|
|
|
|
int value = task.getValue(Task.IMPORTANCE);
|
|
|
|
importanceView.setBackgroundColor(IMPORTANCE_COLORS[value]);
|
|
|
|
importanceView.setBackgroundColor(IMPORTANCE_COLORS[value]);
|
|
|
|
|
|
|
|
importanceView.getLayoutParams().height =
|
|
|
|
|
|
|
|
((View)viewHolder.completeBox.getParent()).getHeight();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
// --- task details
|
|
|
|
* Retrieve task details
|
|
|
|
|
|
|
|
*/
|
|
|
|
@SuppressWarnings("nls")
|
|
|
|
private void retrieveDetails(final LinearLayout view, final long taskId) {
|
|
|
|
private void retrieveDetails(final ViewHolder viewHolder) {
|
|
|
|
// read internal details directly
|
|
|
|
final long taskId = viewHolder.task.getId();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// check the cache
|
|
|
|
|
|
|
|
boolean inCache = false;
|
|
|
|
|
|
|
|
final LinkedHashSet<TaskDetail> details;
|
|
|
|
|
|
|
|
synchronized(detailCache) {
|
|
|
|
|
|
|
|
if(detailCache.containsKey(taskId))
|
|
|
|
|
|
|
|
inCache = true;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
detailCache.put(taskId, new LinkedHashSet<TaskDetail>());
|
|
|
|
|
|
|
|
details = detailCache.get(taskId);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(inCache) {
|
|
|
|
|
|
|
|
Log.e("detail-load-" + Thread.currentThread().getId(), "Already In Cache: " + taskId);
|
|
|
|
|
|
|
|
viewHolder.details.setVisibility(details.size() > 0 ? View.VISIBLE : View.GONE);
|
|
|
|
|
|
|
|
if(details.size() == 0)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
StringBuilder detailText = new StringBuilder();
|
|
|
|
|
|
|
|
for(Iterator<TaskDetail> iterator = details.iterator(); iterator.hasNext(); ) {
|
|
|
|
|
|
|
|
detailText.append(iterator.next().text);
|
|
|
|
|
|
|
|
if(iterator.hasNext())
|
|
|
|
|
|
|
|
detailText.append(" | ");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
spanifyAndAdd(viewHolder.details, detailText.toString());
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Log.e("detail-load-" + Thread.currentThread().getId(), "Loading details: " + taskId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// request details
|
|
|
|
|
|
|
|
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
|
|
|
|
|
|
|
|
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
|
|
|
|
|
|
|
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// load internal details
|
|
|
|
new Thread() {
|
|
|
|
new Thread() {
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
public void run() {
|
|
|
|
for(DetailExposer exposer : EXPOSERS) {
|
|
|
|
for(DetailExposer exposer : EXPOSERS) {
|
|
|
|
|
|
|
|
if(Thread.interrupted())
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
final TaskDetail detail = exposer.getTaskDetails(activity, taskId);
|
|
|
|
final TaskDetail detail = exposer.getTaskDetails(activity, taskId);
|
|
|
|
if(detail == null)
|
|
|
|
if(detail == null || details.contains(detail))
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
ViewHolder holder = (ViewHolder)view.getTag();
|
|
|
|
|
|
|
|
if(holder == null || holder.task.getId() != taskId)
|
|
|
|
CharSequence oldText = viewHolder.details.getText();
|
|
|
|
continue;
|
|
|
|
if(oldText.length() > 0)
|
|
|
|
activity.runOnUiThread(new Runnable() {
|
|
|
|
spanifyAndAdd(viewHolder.details, oldText + " | " + detail.text);
|
|
|
|
public void run() {
|
|
|
|
else
|
|
|
|
view.addView(detailToView(detail));
|
|
|
|
spanifyAndAdd(viewHolder.details, detail.text);
|
|
|
|
};
|
|
|
|
details.add(detail);
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Log.e("detail-load-" + Thread.currentThread().getId(), "Finished loading details: " + taskId);
|
|
|
|
|
|
|
|
};
|
|
|
|
}.start();
|
|
|
|
}.start();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
|
|
|
|
@SuppressWarnings("nls")
|
|
|
|
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
|
|
|
private void spanifyAndAdd(TextView details, String string) {
|
|
|
|
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
|
|
|
if(string.contains("<"))
|
|
|
|
|
|
|
|
details.setText(Html.fromHtml(string.trim().replace("\n", "<br>")));
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
details.setText(string.trim());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Called to tell the cache to be cleared
|
|
|
|
* Called to tell the cache to be cleared
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public void flushDetailCache() {
|
|
|
|
public void flushDetailCache() {
|
|
|
|
//
|
|
|
|
detailCache.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void notifyDataSetChanged() {
|
|
|
|
|
|
|
|
super.notifyDataSetChanged();
|
|
|
|
|
|
|
|
fontSize = Preferences.getIntegerFromString(R.string.p_fontSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
@ -312,8 +368,13 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param taskId
|
|
|
|
* @param taskId
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
@SuppressWarnings("unused")
|
|
|
|
public synchronized void addDetails(ListView list, long taskId, TaskDetail detail) {
|
|
|
|
public synchronized void addDetails(ListView list, long taskId, TaskDetail detail) {
|
|
|
|
if(detail == null)
|
|
|
|
/*if(detail == null)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LinkedHashSet<TaskDetail> details = detailCache.get(taskId);
|
|
|
|
|
|
|
|
if(details.contains(detail))
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// update view if it is visible
|
|
|
|
// update view if it is visible
|
|
|
|
@ -322,36 +383,21 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
ViewHolder viewHolder = (ViewHolder) list.getChildAt(i).getTag();
|
|
|
|
ViewHolder viewHolder = (ViewHolder) list.getChildAt(i).getTag();
|
|
|
|
if(viewHolder == null || viewHolder.task.getId() != taskId)
|
|
|
|
if(viewHolder == null || viewHolder.task.getId() != taskId)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
details.add(detail);
|
|
|
|
TextView newView = detailToView(detail);
|
|
|
|
TextView newView = detailToView(detail);
|
|
|
|
viewHolder.details.addView(newView);
|
|
|
|
viewHolder.details.addView(newView);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Create a new view for the given detail
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param detail
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@SuppressWarnings("nls")
|
|
|
|
|
|
|
|
private TextView detailToView(TaskDetail detail) {
|
|
|
|
|
|
|
|
TextView textView = new TextView(activity);
|
|
|
|
|
|
|
|
textView.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDetails);
|
|
|
|
|
|
|
|
textView.setText(Html.fromHtml(detail.text.replace("\n", "<br>")));
|
|
|
|
|
|
|
|
if(detail.color != 0)
|
|
|
|
|
|
|
|
textView.setTextColor(detail.color);
|
|
|
|
|
|
|
|
return textView;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private final View.OnClickListener completeBoxListener = new View.OnClickListener() {
|
|
|
|
private final View.OnClickListener completeBoxListener = new View.OnClickListener() {
|
|
|
|
public void onClick(View v) {
|
|
|
|
public void onClick(View v) {
|
|
|
|
View container = (View) v.getParent();
|
|
|
|
ViewHolder viewHolder = (ViewHolder)((View)v.getParent().getParent()).getTag();
|
|
|
|
Task task = ((ViewHolder)container.getTag()).task;
|
|
|
|
Task task = viewHolder.task;
|
|
|
|
|
|
|
|
|
|
|
|
completeTask(task, ((CheckBox)v).isChecked());
|
|
|
|
completeTask(task, ((CheckBox)v).isChecked());
|
|
|
|
// set check box to actual action item state
|
|
|
|
// set check box to actual action item state
|
|
|
|
setTaskAppearance(container, task.isCompleted());
|
|
|
|
setTaskAppearance(viewHolder, task.isCompleted());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@ -427,12 +473,10 @@ public class TaskAdapter extends CursorAdapter {
|
|
|
|
* @param name
|
|
|
|
* @param name
|
|
|
|
* @param progress
|
|
|
|
* @param progress
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
void setTaskAppearance(View container, boolean state) {
|
|
|
|
void setTaskAppearance(ViewHolder viewHolder, boolean state) {
|
|
|
|
CheckBox completed = (CheckBox)container.findViewById(R.id.completeBox);
|
|
|
|
viewHolder.completeBox.setChecked(state);
|
|
|
|
TextView name = (TextView)container.findViewById(R.id.title);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
completed.setChecked(state);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TextView name = viewHolder.nameView;
|
|
|
|
if(state) {
|
|
|
|
if(state) {
|
|
|
|
name.setPaintFlags(name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
|
|
|
name.setPaintFlags(name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
|
|
|
name.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemTitle_Completed);
|
|
|
|
name.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemTitle_Completed);
|
|
|
|
|