diff --git a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java index 3af4a7f46..e0c789b6d 100644 --- a/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/astrid/src/com/todoroo/astrid/adapter/TaskAdapter.java @@ -16,8 +16,10 @@ import android.database.Cursor; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.text.Html; +import android.text.Spanned; import android.text.TextUtils; import android.text.Html.ImageGetter; +import android.text.Html.TagHandler; import android.text.util.Linkify; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -284,13 +286,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable { dueDateView.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDueDate_Overdue); } - String dateValue; Date dueDateAsDate = DateUtilities.unixtimeToDate(dueDate); - if (task.hasDueTime()) { - dateValue = DateUtilities.getDateStringWithTimeAndWeekday(activity, dueDateAsDate); - } else { - dateValue = DateUtilities.getDateStringWithWeekday(activity, dueDateAsDate); - } + String dateValue = formatDate(dueDateAsDate); dueDateView.setText(dateValue); setVisibility(dueDateView); } else if(task.isCompleted()) { @@ -332,7 +329,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { viewHolder.details.setVisibility(View.GONE); } else { viewHolder.details.setVisibility(View.VISIBLE); - viewHolder.details.setText(Html.fromHtml(details.trim().replace("\n", //$NON-NLS-1$ + viewHolder.details.setText(convertToHtml(details.trim().replace("\n", //$NON-NLS-1$ "
"), detailImageGetter, null)); //$NON-NLS-1$ } @@ -376,6 +373,32 @@ public class TaskAdapter extends CursorAdapter implements Filterable { * ============================================================== details * ====================================================================== */ + private final HashMap htmlCache = new HashMap(); + + private Spanned convertToHtml(String string, ImageGetter imageGetter, TagHandler tagHandler) { + if(!htmlCache.containsKey(string)) { + Spanned html = Html.fromHtml(string, imageGetter, tagHandler); + htmlCache.put(string, html); + return html; + } + return htmlCache.get(string); + } + + private final HashMap dateCache = new HashMap(); + + private String formatDate(Date date) { + if(dateCache.containsKey(date)) + return dateCache.get(date); + + String string; + if(Task.hasDueTime(date.getTime())) + string = DateUtilities.getDateStringWithTimeAndWeekday(activity, date); + else + string = DateUtilities.getDateStringWithWeekday(activity, date); + dateCache.put(date, string); + return string; + } + // implementation note: this map is really costly if users have // a large number of tasks to load, since it all goes into memory. // it's best to do this, though, in order to append details to each other @@ -388,7 +411,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable { public void run() { // for all of the tasks returned by our cursor, verify details TodorooCursor fetchCursor = taskService.fetchFiltered( - query.get(), null, Task.ID, Task.DETAILS, Task.COMPLETION_DATE); + query.get(), null, Task.ID, Task.DETAILS, Task.DETAILS_DATE, + Task.MODIFICATION_DATE, Task.COMPLETION_DATE); activity.startManagingCursor(fetchCursor); try { Task task = new Task(); @@ -398,15 +422,18 @@ public class TaskAdapter extends CursorAdapter implements Filterable { if(task.isCompleted()) continue; - taskDetailLoader.put(task.getId(), new StringBuilder(task.getValue(Task.DETAILS))); + if(task.getValue(Task.DETAILS_DATE) < task.getValue(Task.MODIFICATION_DATE)) { + taskDetailLoader.put(task.getId(), new StringBuilder(task.getValue(Task.DETAILS))); - 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); + 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); - if(TextUtils.isEmpty(task.getValue(Task.DETAILS))) { - task.setValue(Task.DETAILS, DETAIL_SEPARATOR); + if(TextUtils.isEmpty(task.getValue(Task.DETAILS))) { + task.setValue(Task.DETAILS, DETAIL_SEPARATOR); + } + task.setValue(Task.DETAILS_DATE, DateUtilities.now()); taskService.save(task); } } @@ -434,6 +461,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { details.append(detail); taskDetailContainer.setId(id); taskDetailContainer.setValue(Task.DETAILS, details.toString()); + taskDetailContainer.setValue(Task.DETAILS_DATE, DateUtilities.now()); taskService.save(taskDetailContainer); } @@ -536,7 +564,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable { } String string = detailText.toString(); if(string.contains("<")) - view.setText(Html.fromHtml(string.trim().replace("\n", "
"), + view.setText(convertToHtml(string.trim().replace("\n", "
"), detailImageGetter, null)); else view.setText(string.trim()); diff --git a/astrid/src/com/todoroo/astrid/dao/Database.java b/astrid/src/com/todoroo/astrid/dao/Database.java index ce7267bbd..e80d5d385 100644 --- a/astrid/src/com/todoroo/astrid/dao/Database.java +++ b/astrid/src/com/todoroo/astrid/dao/Database.java @@ -28,7 +28,7 @@ public class Database extends AbstractDatabase { * Database version number. This variable must be updated when database * tables are updated, as it determines whether a database needs updating. */ - public static final int VERSION = 6; + public static final int VERSION = 7; /** * Database name (must be unique) @@ -127,6 +127,10 @@ public class Database extends AbstractDatabase { database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " + Task.REMINDER_SNOOZE.accept(visitor, null)); } + case 6: { + database.execSQL("ALTER TABLE " + Task.TABLE.name + " ADD " + + Task.DETAILS_DATE.accept(visitor, null)); + } return true; }