Fixed startup crashing issue, added "completed task time" display on task listing.

pull/14/head
Tim Su 17 years ago
parent a6ba8a6c16
commit e5826cdb9d

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.timsu.astrid" package="com.timsu.astrid"
android:versionCode="16" android:versionCode="17"
android:versionName="1.7.7"> android:versionName="1.7.8">
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
@ -21,8 +21,7 @@
<activity android:name=".activities.TaskViewNotifier" <activity android:name=".activities.TaskViewNotifier"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:theme="@android:style/Theme.Dialog" android:theme="@android:style/Theme.Dialog"
android:launchMode="singleTask" android:launchMode="singleTask" />
android:taskAffinity="@null" />
<activity android:name=".activities.TaskEdit"/> <activity android:name=".activities.TaskEdit"/>

@ -25,6 +25,7 @@
<color name="taskList_dueDateOverdue">#ffffff44</color> <color name="taskList_dueDateOverdue">#ffffff44</color>
<color name="taskList_dueDate">#ffffffaa</color> <color name="taskList_dueDate">#ffffffaa</color>
<color name="taskList_completedDate">#ffccffaa</color>
<color name="taskList_tags">#ff888888</color> <color name="taskList_tags">#ff888888</color>
<color name="view_header_done">#ff83ffa9</color> <color name="view_header_done">#ff83ffa9</color>

@ -68,6 +68,7 @@
<string name="taskList_hiddenSuffix"> hidden</string> <string name="taskList_hiddenSuffix"> hidden</string>
<string name="taskList_dueIn">Due in</string> <string name="taskList_dueIn">Due in</string>
<string name="taskList_goalPrefix">Goal</string> <string name="taskList_goalPrefix">Goal</string>
<string name="taskList_completedPrefix">Finished</string>
<string name="taskList_overdueBy">Overdue by</string> <string name="taskList_overdueBy">Overdue by</string>
<string name="addtask_label">New Task</string> <string name="addtask_label">New Task</string>
<string name="tags_prefix">Tags: </string> <string name="tags_prefix">Tags: </string>
@ -151,8 +152,8 @@
<skip /> <skip />
<string name="information_title">Information</string> <string name="information_title">Information</string>
<string name="question_title">Question</string> <string name="question_title">Question</string>
<string name="yes">Yes</string> <string name="notify_yes">Let\'s do it!</string>
<string name="no">No</string> <string name="notify_no">No, quit.</string>
<string name="delete_title">Delete</string> <string name="delete_title">Delete</string>
<string name="delete_this_task_title">Delete this task?</string> <string name="delete_this_task_title">Delete this task?</string>

@ -48,6 +48,7 @@ import com.timsu.astrid.data.tag.TagModelForView;
import com.timsu.astrid.data.task.TaskController; import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier; import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForList; import com.timsu.astrid.data.task.TaskModelForList;
import com.timsu.astrid.utilities.Notifications;
/** Primary view for the Astrid Application. Lists all of the tasks in the /** Primary view for the Astrid Application. Lists all of the tasks in the
@ -89,8 +90,20 @@ public class TaskList extends Activity {
static boolean shouldCloseInstance = false; static boolean shouldCloseInstance = false;
/* ======================================================================
* ======================================================= initialization
* ====================================================================== */
@Override
/** Called when loading up the activity for the first time */ /** Called when loading up the activity for the first time */
private void onLoad() { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.task_list);
// if we've never been started, do this
if(Notifications.areAlarmsSet())
Notifications.scheduleAllAlarms(this);
shouldCloseInstance = false; shouldCloseInstance = false;
controller = new TaskController(this); controller = new TaskController(this);
@ -133,13 +146,43 @@ public class TaskList extends Activity {
}); });
} }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem item;
item = menu.add(Menu.NONE, INSERT_ID, Menu.NONE,
R.string.taskList_menu_insert);
item.setIcon(android.R.drawable.ic_menu_add);
item.setAlphabeticShortcut('n');
if(filterTag == null) {
item = menu.add(Menu.NONE, FILTERS_ID, Menu.NONE,
R.string.taskList_menu_filters);
item.setIcon(android.R.drawable.ic_menu_view);
item.setAlphabeticShortcut('f');
item = menu.add(Menu.NONE, TAGS_ID, Menu.NONE,
R.string.taskList_menu_tags);
item.setIcon(android.R.drawable.ic_menu_myplaces);
item.setAlphabeticShortcut('t');
}
return true;
}
/* ======================================================================
* ====================================================== populating list
* ====================================================================== */
/** Fill in the Task List with our tasks */ /** Fill in the Task List with our tasks */
private void fillData() { private void fillData() {
Resources r = getResources(); Resources r = getResources();
Cursor tasksCursor; Cursor tasksCursor;
// load tags (again) // load tags (they might've changed)
tagMap = tagController.getAllTagsAsMap(this); tagMap = tagController.getAllTagsAsMap(this);
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
if(extras != null && extras.containsKey(TAG_TOKEN)) { if(extras != null && extras.containsKey(TAG_TOKEN)) {
@ -229,33 +272,32 @@ public class TaskList extends Activity {
}); });
} }
/* ======================================================================
* ======================================================= event handlers
* ====================================================================== */
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, protected void onActivityResult(int requestCode, int resultCode,
Intent intent) { Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode == TaskView.RESULT_DISMISS) { // we would fill the list, but it is already happening on focus change
finish();
return;
}
fillData();
} }
@Override @Override
public void onWindowFocusChanged(boolean hasFocus) { public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus); super.onWindowFocusChanged(hasFocus);
if(hasFocus) { // stuff might have changed... // refresh, since stuff might have changed...
if(shouldCloseInstance) // user wants to quit if(hasFocus) {
if(shouldCloseInstance) { // user wants to quit
shouldCloseInstance = false;
finish(); finish();
else } else
fillData(); fillData();
shouldCloseInstance = false;
} }
} }
// --- list adapter
private void createTask() { private void createTask() {
Intent intent = new Intent(this, TaskEdit.class); Intent intent = new Intent(this, TaskEdit.class);
if(filterTag != null) if(filterTag != null)
@ -335,42 +377,6 @@ public class TaskList extends Activity {
return super.onMenuItemSelected(featureId, item); return super.onMenuItemSelected(featureId, item);
} }
// --- creating stuff
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.task_list);
onLoad();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem item;
item = menu.add(Menu.NONE, INSERT_ID, Menu.NONE,
R.string.taskList_menu_insert);
item.setIcon(android.R.drawable.ic_menu_add);
item.setAlphabeticShortcut('n');
if(filterTag == null) {
item = menu.add(Menu.NONE, FILTERS_ID, Menu.NONE,
R.string.taskList_menu_filters);
item.setIcon(android.R.drawable.ic_menu_view);
item.setAlphabeticShortcut('f');
item = menu.add(Menu.NONE, TAGS_ID, Menu.NONE,
R.string.taskList_menu_tags);
item.setIcon(android.R.drawable.ic_menu_myplaces);
item.setAlphabeticShortcut('t');
}
return true;
}
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();

@ -118,7 +118,22 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
timer.setImageDrawable(r.getDrawable(R.drawable.ic_dialog_time)); timer.setImageDrawable(r.getDrawable(R.drawable.ic_dialog_time));
progress.setChecked(task.isTaskCompleted()); progress.setChecked(task.isTaskCompleted());
// due date // due date / completion date
if(task.isTaskCompleted()) {
if(task.getCompletionDate() != null) {
int secondsLeft = (int)(task.getCompletionDate().getTime() -
System.currentTimeMillis()) / 1000;
StringBuilder label = new StringBuilder().
append(r.getString(R.string.taskList_completedPrefix)).
append(" ").
append(DateUtilities.getDurationString(r, Math.abs(secondsLeft), 1)).
append(r.getString(R.string.ago_suffix));
dueDateView.setText(label);
dueDateView.setTextColor(r.getColor(R.color.taskList_completedDate));
hasProperties = true;
} else
dueDateView.setVisibility(View.GONE);
} else {
Date dueDate = task.getDefiniteDueDate(); Date dueDate = task.getDefiniteDueDate();
String dueString = ""; String dueString = "";
if(dueDate == null || (task.getPreferredDueDate() != null && if(dueDate == null || (task.getPreferredDueDate() != null &&
@ -145,6 +160,7 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
hasProperties = true; hasProperties = true;
} else } else
dueDateView.setVisibility(View.GONE); dueDateView.setVisibility(View.GONE);
}
// tags // tags
List<TagIdentifier> tags = hooks.getTagController().getTaskTags( List<TagIdentifier> tags = hooks.getTagController().getTaskTags(

@ -39,8 +39,8 @@ public class TaskViewNotifier extends TaskView {
.setTitle(R.string.taskView_notifyTitle) .setTitle(R.string.taskView_notifyTitle)
.setMessage(response) .setMessage(response)
.setIcon(android.R.drawable.ic_dialog_alert) .setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.yes, null) .setPositiveButton(R.string.notify_yes, null)
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { .setNegativeButton(R.string.notify_no, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);

@ -82,6 +82,56 @@ public abstract class AbstractModel {
return cursor; return cursor;
} }
// --- checking against cached values
protected void putIfChangedFromDatabase(String field, String newValue) {
if(values.containsKey(field)) {
String value = values.getAsString(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
protected void putIfChangedFromDatabase(String field, Long newValue) {
if(values.containsKey(field)) {
Long value = values.getAsLong(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
protected void putIfChangedFromDatabase(String field, Integer newValue) {
if(values.containsKey(field)) {
Integer value = values.getAsInteger(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
protected void putIfChangedFromDatabase(String field, Double newValue) {
if(values.containsKey(field)) {
Double value = values.getAsDouble(field);
if(value == null) {
if(newValue == null)
return;
} else if(value.equals(newValue))
return;
}
setValues.put(field, newValue);
}
// --- data retrieval for the different object types // --- data retrieval for the different object types
protected String retrieveString(String field) { protected String retrieveString(String field) {

@ -166,6 +166,40 @@ public abstract class AbstractTaskModel extends AbstractModel {
setElapsedSeconds((int) (getElapsedSeconds() + secondsElapsed)); setElapsedSeconds((int) (getElapsedSeconds() + secondsElapsed));
} }
protected void prefetchData(String[] fields) {
for(String field : fields) {
if(field.equals(NAME))
getName();
else if(field.equals(NOTES))
getNotes();
else if(field.equals(PROGRESS_PERCENTAGE))
getProgressPercentage();
else if(field.equals(IMPORTANCE))
getImportance();
else if(field.equals(ESTIMATED_SECONDS))
getEstimatedSeconds();
else if(field.equals(ELAPSED_SECONDS))
getElapsedSeconds();
else if(field.equals(TIMER_START))
getTimerStart();
else if(field.equals(DEFINITE_DUE_DATE))
getDefiniteDueDate();
else if(field.equals(PREFERRED_DUE_DATE))
getPreferredDueDate();
else if(field.equals(HIDDEN_UNTIL))
getHiddenUntil();
else if(field.equals(BLOCKING_ON))
getBlockingOn();
else if(field.equals(NOTIFICATIONS))
getNotificationIntervalSeconds();
else if(field.equals(CREATION_DATE))
getCreationDate();
else if(field.equals(COMPLETION_DATE))
getCompletionDate();
}
}
// --- task identifier // --- task identifier
private TaskIdentifier identifier = null; private TaskIdentifier identifier = null;
@ -266,15 +300,15 @@ public abstract class AbstractTaskModel extends AbstractModel {
// --- setters // --- setters
protected void setName(String name) { protected void setName(String name) {
setValues.put(NAME, name); putIfChangedFromDatabase(NAME, name);
} }
protected void setNotes(String notes) { protected void setNotes(String notes) {
setValues.put(NOTES, notes); putIfChangedFromDatabase(NOTES, notes);
} }
protected void setProgressPercentage(int progressPercentage) { protected void setProgressPercentage(int progressPercentage) {
setValues.put(PROGRESS_PERCENTAGE, progressPercentage); putIfChangedFromDatabase(PROGRESS_PERCENTAGE, progressPercentage);
if(getProgressPercentage() != progressPercentage && if(getProgressPercentage() != progressPercentage &&
progressPercentage == COMPLETE_PERCENTAGE) progressPercentage == COMPLETE_PERCENTAGE)
@ -282,58 +316,58 @@ public abstract class AbstractTaskModel extends AbstractModel {
} }
protected void setImportance(Importance importance) { protected void setImportance(Importance importance) {
setValues.put(IMPORTANCE, importance.ordinal()); putIfChangedFromDatabase(IMPORTANCE, importance.ordinal());
} }
protected void setEstimatedSeconds(Integer estimatedSeconds) { protected void setEstimatedSeconds(Integer estimatedSeconds) {
setValues.put(ESTIMATED_SECONDS, estimatedSeconds); putIfChangedFromDatabase(ESTIMATED_SECONDS, estimatedSeconds);
} }
protected void setElapsedSeconds(int elapsedSeconds) { protected void setElapsedSeconds(int elapsedSeconds) {
setValues.put(ELAPSED_SECONDS, elapsedSeconds); putIfChangedFromDatabase(ELAPSED_SECONDS, elapsedSeconds);
} }
protected void setTimerStart(Date timerStart) { protected void setTimerStart(Date timerStart) {
putDate(setValues, TIMER_START, timerStart); putDate(TIMER_START, timerStart);
} }
protected void setDefiniteDueDate(Date definiteDueDate) { protected void setDefiniteDueDate(Date definiteDueDate) {
putDate(setValues, DEFINITE_DUE_DATE, definiteDueDate); putDate(DEFINITE_DUE_DATE, definiteDueDate);
} }
protected void setPreferredDueDate(Date preferredDueDate) { protected void setPreferredDueDate(Date preferredDueDate) {
putDate(setValues, PREFERRED_DUE_DATE, preferredDueDate); putDate(PREFERRED_DUE_DATE, preferredDueDate);
} }
protected void setHiddenUntil(Date hiddenUntil) { protected void setHiddenUntil(Date hiddenUntil) {
putDate(setValues, HIDDEN_UNTIL, hiddenUntil); putDate(HIDDEN_UNTIL, hiddenUntil);
} }
protected void setBlockingOn(TaskIdentifier blockingOn) { protected void setBlockingOn(TaskIdentifier blockingOn) {
if(blockingOn == null || blockingOn.equals(getTaskIdentifier())) if(blockingOn == null || blockingOn.equals(getTaskIdentifier()))
setValues.put(BLOCKING_ON, (Integer)null); putIfChangedFromDatabase(BLOCKING_ON, (Integer)null);
else else
setValues.put(BLOCKING_ON, blockingOn.getId()); putIfChangedFromDatabase(BLOCKING_ON, blockingOn.getId());
} }
protected void setCreationDate(Date creationDate) { protected void setCreationDate(Date creationDate) {
putDate(setValues, CREATION_DATE, creationDate); putDate(CREATION_DATE, creationDate);
} }
protected void setCompletionDate(Date completionDate) { protected void setCompletionDate(Date completionDate) {
putDate(setValues, COMPLETION_DATE, completionDate); putDate(COMPLETION_DATE, completionDate);
} }
protected void setNotificationIntervalSeconds(Integer intervalInSeconds) { protected void setNotificationIntervalSeconds(Integer intervalInSeconds) {
setValues.put(NOTIFICATIONS, intervalInSeconds); putIfChangedFromDatabase(NOTIFICATIONS, intervalInSeconds);
} }
// --- utility methods // --- utility methods
static void putDate(ContentValues cv, String fieldName, Date date) { protected void putDate(String fieldName, Date date) {
if(date == null) if(date == null)
cv.put(fieldName, (Long)null); putIfChangedFromDatabase(fieldName, (Long)null);
else else
cv.put(fieldName, date.getTime()); putIfChangedFromDatabase(fieldName, date.getTime());
} }
} }

@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import android.app.Activity; import android.app.Activity;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.SQLException; import android.database.SQLException;
@ -157,6 +158,15 @@ public class TaskController extends AbstractController {
saveSucessful = newRow >= 0; saveSucessful = newRow >= 0;
} else { } else {
long id = task.getTaskIdentifier().getId(); long id = task.getTaskIdentifier().getId();
ContentValues values = task.getSetValues();
// set completion date
if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) &&
values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE)
== AbstractTaskModel.COMPLETE_PERCENTAGE) {
values.put(AbstractTaskModel.COMPLETION_DATE, System.currentTimeMillis());
}
saveSucessful = database.update(TASK_TABLE_NAME, task.getSetValues(), saveSucessful = database.update(TASK_TABLE_NAME, task.getSetValues(),
KEY_ROWID + "=" + id, null) > 0; KEY_ROWID + "=" + id, null) > 0;
} }
@ -214,7 +224,7 @@ public class TaskController extends AbstractController {
public TaskModelForList fetchTaskForList(TaskIdentifier taskId) throws SQLException { public TaskModelForList fetchTaskForList(TaskIdentifier taskId) throws SQLException {
long id = taskId.getId(); long id = taskId.getId();
Cursor cursor = database.query(true, TASK_TABLE_NAME, Cursor cursor = database.query(true, TASK_TABLE_NAME,
TaskModelForView.FIELD_LIST, TaskModelForList.FIELD_LIST,
KEY_ROWID + "=" + id, null, null, null, null, null); KEY_ROWID + "=" + id, null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();

@ -46,6 +46,7 @@ public class TaskModelForList extends AbstractTaskModel {
DEFINITE_DUE_DATE, DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE, PREFERRED_DUE_DATE,
PROGRESS_PERCENTAGE, PROGRESS_PERCENTAGE,
COMPLETION_DATE,
HIDDEN_UNTIL, HIDDEN_UNTIL,
}; };
@ -123,16 +124,7 @@ public class TaskModelForList extends AbstractTaskModel {
public TaskModelForList(Cursor cursor) { public TaskModelForList(Cursor cursor) {
super(cursor); super(cursor);
// prefetch every field - we can't lazy load with more than 1 prefetchData(FIELD_LIST);
getElapsedSeconds();
getDefiniteDueDate();
getEstimatedSeconds();
getHiddenUntil();
getImportance();
getName();
getPreferredDueDate();
getProgressPercentage();
getTimerStart();
} }
// --- exposed getters and setters // --- exposed getters and setters
@ -196,6 +188,11 @@ public class TaskModelForList extends AbstractTaskModel {
return super.getTimerStart(); return super.getTimerStart();
} }
@Override
public Date getCompletionDate() {
return super.getCompletionDate();
}
@Override @Override
public void setProgressPercentage(int progressPercentage) { public void setProgressPercentage(int progressPercentage) {
super.setProgressPercentage(progressPercentage); super.setProgressPercentage(progressPercentage);

@ -44,9 +44,8 @@ public class TaskModelForNotify extends AbstractTaskModel implements Notifiable
public TaskModelForNotify(Cursor cursor) { public TaskModelForNotify(Cursor cursor) {
super(cursor); super(cursor);
getNotificationIntervalSeconds();
getHiddenUntil(); prefetchData(FIELD_LIST);
isTaskCompleted();
} }
// --- getters and setters // --- getters and setters

@ -46,6 +46,7 @@ public class Notifications extends BroadcastReceiver {
public static final int FLAG_PREFERRED_DEADLINE = 2; public static final int FLAG_PREFERRED_DEADLINE = 2;
private static Random random = new Random(); private static Random random = new Random();
private static boolean alarmsSet = false;
/** Something we can create a notification for */ /** Something we can create a notification for */
public interface Notifiable { public interface Notifiable {
@ -93,6 +94,10 @@ public class Notifications extends BroadcastReceiver {
return false; return false;
} }
public static boolean areAlarmsSet() {
return alarmsSet;
}
public static void scheduleAllAlarms(Context context) { public static void scheduleAllAlarms(Context context) {
TaskController controller = new TaskController(context); TaskController controller = new TaskController(context);
controller.open(); controller.open();
@ -101,6 +106,7 @@ public class Notifications extends BroadcastReceiver {
for(TaskModelForNotify task : tasks) for(TaskModelForNotify task : tasks)
updateAlarm(context, task, false); updateAlarm(context, task, false);
alarmsSet = true;
controller.close(); controller.close();
} }
@ -268,8 +274,7 @@ public class Notifications extends BroadcastReceiver {
Resources r = context.getResources(); Resources r = context.getResources();
Intent notifyIntent = new Intent(context, TaskViewNotifier.class); Intent notifyIntent = new Intent(context, TaskViewNotifier.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
notifyIntent.putExtra(TaskViewNotifier.LOAD_INSTANCE_TOKEN, id); notifyIntent.putExtra(TaskViewNotifier.LOAD_INSTANCE_TOKEN, id);
notifyIntent.putExtra(TaskViewNotifier.FROM_NOTIFICATION_TOKEN, true); notifyIntent.putExtra(TaskViewNotifier.FROM_NOTIFICATION_TOKEN, true);
notifyIntent.putExtra(TaskViewNotifier.NOTIF_FLAGS_TOKEN, flags); notifyIntent.putExtra(TaskViewNotifier.NOTIF_FLAGS_TOKEN, flags);

Loading…
Cancel
Save