diff --git a/astrid/res/layout/task_adapter_row.xml b/astrid/res/layout/task_adapter_row.xml index e382cc375..7e1119218 100644 --- a/astrid/res/layout/task_adapter_row.xml +++ b/astrid/res/layout/task_adapter_row.xml @@ -1,71 +1,72 @@ - + android:paddingTop="4dip" + android:paddingBottom="4dip" + android:paddingLeft="4dip" + android:paddingRight="6dip"> - + android:layout_alignParentTop="true" + android:layout_alignParentLeft="true" + android:minHeight="48dip"> - - + - - - - - - - - + android:layout_alignParentTop="true" + android:layout_toRightOf="@id/completeBox" + android:paddingLeft="10dip" + style="@style/TextAppearance.TAd_ItemTitle" + android:gravity="center_vertical"/> + + + - + - - - - + - + + + + diff --git a/astrid/res/values/styles-3.0.xml b/astrid/res/values/styles-3.0.xml index 9d65e463c..afce2a693 100644 --- a/astrid/res/values/styles-3.0.xml +++ b/astrid/res/values/styles-3.0.xml @@ -49,11 +49,12 @@ diff --git a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java index 4a548a985..894ba5175 100644 --- a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java @@ -2,6 +2,8 @@ package com.todoroo.astrid.adapter; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; import android.app.Activity; import android.content.Context; @@ -10,6 +12,7 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.Paint; import android.text.Html; +import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; @@ -98,7 +101,9 @@ public class TaskAdapter extends CursorAdapter { private final int resource; private final LayoutInflater inflater; protected OnCompletedTaskListener onCompletedTaskListener = null; - private final int fontSize; + private int fontSize; + private final HashMap> detailCache = + new HashMap>(); /** * Constructor @@ -147,7 +152,7 @@ public class TaskAdapter extends CursorAdapter { viewHolder.nameView = (TextView)view.findViewById(R.id.title); viewHolder.completeBox = (CheckBox)view.findViewById(R.id.completeBox); 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.importance = (View)view.findViewById(R.id.importance); @@ -169,11 +174,12 @@ public class TaskAdapter extends CursorAdapter { @Override public void bindView(View view, Context context, Cursor c) { TodorooCursor cursor = (TodorooCursor)c; - Task actionItem = ((ViewHolder)view.getTag()).task; + ViewHolder viewHolder = ((ViewHolder)view.getTag()); + Task actionItem = viewHolder.task; actionItem.readFromCursor(cursor); setFieldContentsAndVisibility(view); - setTaskAppearance(view, actionItem.isCompleted()); + setTaskAppearance(viewHolder, actionItem.isCompleted()); } /** 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 * */ - public static class ViewHolder { + public class ViewHolder { public Task task; public TextView nameView; public CheckBox completeBox; public TextView dueDate; - public LinearLayout details; + public TextView details; public View importance; public LinearLayout actions; public boolean expanded; @@ -218,14 +224,6 @@ public class TaskAdapter extends CursorAdapter { 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 final TextView dueDateView = viewHolder.dueDate; { 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) - final LinearLayout detailsView = viewHolder.details; + // 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()); + completeBox.getLayoutParams().height = dueDateView.getHeight() + + nameView.getHeight(); + } + + // task details - send out a request for it (only if not fling) if(!isFling) { - detailsView.removeViews(2, detailsView.getChildCount() - 2); - retrieveDetails(detailsView, task.getId()); + retrieveDetails(viewHolder); } // importance bar - must be set at end when view height is determined final View importanceView = viewHolder.importance; { int value = task.getValue(Task.IMPORTANCE); importanceView.setBackgroundColor(IMPORTANCE_COLORS[value]); + importanceView.getLayoutParams().height = + ((View)viewHolder.completeBox.getParent()).getHeight(); } } - /** - * Retrieve task details - */ - private void retrieveDetails(final LinearLayout view, final long taskId) { - // read internal details directly + // --- task details + + @SuppressWarnings("nls") + private void retrieveDetails(final ViewHolder viewHolder) { + final long taskId = viewHolder.task.getId(); + + // 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); + } + + 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 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() { @Override public void run() { for(DetailExposer exposer : EXPOSERS) { + if(Thread.interrupted()) + return; + final TaskDetail detail = exposer.getTaskDetails(activity, taskId); - if(detail == null) + if(detail == null || details.contains(detail)) continue; - ViewHolder holder = (ViewHolder)view.getTag(); - if(holder == null || holder.task.getId() != taskId) - continue; - activity.runOnUiThread(new Runnable() { - public void run() { - view.addView(detailToView(detail)); - }; - }); + + CharSequence oldText = viewHolder.details.getText(); + if(oldText.length() > 0) + spanifyAndAdd(viewHolder.details, oldText + " | " + detail.text); + else + spanifyAndAdd(viewHolder.details, detail.text); + details.add(detail); } - } + Log.e("detail-load-" + Thread.currentThread().getId(), "Finished loading details: " + taskId); + }; }.start(); + } - Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS); - broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId); - activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); + @SuppressWarnings("nls") + private void spanifyAndAdd(TextView details, String string) { + if(string.contains("<")) + details.setText(Html.fromHtml(string.trim().replace("\n", "
"))); + else + details.setText(string.trim()); } /** * Called to tell the cache to be cleared */ 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 */ + @SuppressWarnings("unused") public synchronized void addDetails(ListView list, long taskId, TaskDetail detail) { - if(detail == null) + /*if(detail == null) + return; + + LinkedHashSet details = detailCache.get(taskId); + if(details.contains(detail)) return; // update view if it is visible @@ -322,36 +383,21 @@ public class TaskAdapter extends CursorAdapter { ViewHolder viewHolder = (ViewHolder) list.getChildAt(i).getTag(); if(viewHolder == null || viewHolder.task.getId() != taskId) continue; - + details.add(detail); TextView newView = detailToView(detail); viewHolder.details.addView(newView); 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", "
"))); - if(detail.color != 0) - textView.setTextColor(detail.color); - return textView; + }*/ } private final View.OnClickListener completeBoxListener = new View.OnClickListener() { public void onClick(View v) { - View container = (View) v.getParent(); - Task task = ((ViewHolder)container.getTag()).task; + ViewHolder viewHolder = (ViewHolder)((View)v.getParent().getParent()).getTag(); + Task task = viewHolder.task; completeTask(task, ((CheckBox)v).isChecked()); // 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 progress */ - void setTaskAppearance(View container, boolean state) { - CheckBox completed = (CheckBox)container.findViewById(R.id.completeBox); - TextView name = (TextView)container.findViewById(R.id.title); - - completed.setChecked(state); + void setTaskAppearance(ViewHolder viewHolder, boolean state) { + viewHolder.completeBox.setChecked(state); + TextView name = viewHolder.nameView; if(state) { name.setPaintFlags(name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); name.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemTitle_Completed);