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

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

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

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

@ -68,6 +68,7 @@
<string name="taskList_hiddenSuffix"> hidden</string>
<string name="taskList_dueIn">Due in</string>
<string name="taskList_goalPrefix">Goal</string>
<string name="taskList_completedPrefix">Finished</string>
<string name="taskList_overdueBy">Overdue by</string>
<string name="addtask_label">New Task</string>
<string name="tags_prefix">Tags: </string>
@ -151,8 +152,8 @@
<skip />
<string name="information_title">Information</string>
<string name="question_title">Question</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="notify_yes">Let\'s do it!</string>
<string name="notify_no">No, quit.</string>
<string name="delete_title">Delete</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.TaskIdentifier;
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
@ -89,8 +90,20 @@ public class TaskList extends Activity {
static boolean shouldCloseInstance = false;
/* ======================================================================
* ======================================================= initialization
* ====================================================================== */
@Override
/** 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;
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 */
private void fillData() {
Resources r = getResources();
Cursor tasksCursor;
// load tags (again)
// load tags (they might've changed)
tagMap = tagController.getAllTagsAsMap(this);
Bundle extras = getIntent().getExtras();
if(extras != null && extras.containsKey(TAG_TOKEN)) {
@ -229,33 +272,32 @@ public class TaskList extends Activity {
});
}
/* ======================================================================
* ======================================================= event handlers
* ====================================================================== */
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode == TaskView.RESULT_DISMISS) {
finish();
return;
}
fillData();
// we would fill the list, but it is already happening on focus change
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus) { // stuff might have changed...
if(shouldCloseInstance) // user wants to quit
// refresh, since stuff might have changed...
if(hasFocus) {
if(shouldCloseInstance) { // user wants to quit
shouldCloseInstance = false;
finish();
else
} else
fillData();
shouldCloseInstance = false;
}
}
// --- list adapter
private void createTask() {
Intent intent = new Intent(this, TaskEdit.class);
if(filterTag != null)
@ -335,42 +377,6 @@ public class TaskList extends Activity {
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
protected void onDestroy() {
super.onDestroy();

@ -118,33 +118,49 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
timer.setImageDrawable(r.getDrawable(R.drawable.ic_dialog_time));
progress.setChecked(task.isTaskCompleted());
// due date
Date dueDate = task.getDefiniteDueDate();
String dueString = "";
if(dueDate == null || (task.getPreferredDueDate() != null &&
task.getPreferredDueDate().before(dueDate))) {
// only prefix with "goal:" if the real deadline isn't overdue
if(task.getDefiniteDueDate() == null || task.getDefiniteDueDate().
after(new Date()))
dueString = r.getString(R.string.taskList_goalPrefix) + " ";
dueDate = task.getPreferredDueDate();
}
if(dueDate != null) {
int secondsLeft = (int)(dueDate.getTime() -
System.currentTimeMillis()) / 1000;
if(secondsLeft > 0)
dueString += r.getString(R.string.taskList_dueIn) + " ";
else {
dueString += r.getString(R.string.taskList_overdueBy) + " ";
dueDateView.setTextColor(r.getColor(R.color.taskList_dueDateOverdue));
// 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();
String dueString = "";
if(dueDate == null || (task.getPreferredDueDate() != null &&
task.getPreferredDueDate().before(dueDate))) {
// only prefix with "goal:" if the real deadline isn't overdue
if(task.getDefiniteDueDate() == null || task.getDefiniteDueDate().
after(new Date()))
dueString = r.getString(R.string.taskList_goalPrefix) + " ";
dueDate = task.getPreferredDueDate();
}
if(dueDate != null) {
int secondsLeft = (int)(dueDate.getTime() -
System.currentTimeMillis()) / 1000;
if(secondsLeft > 0)
dueString += r.getString(R.string.taskList_dueIn) + " ";
else {
dueString += r.getString(R.string.taskList_overdueBy) + " ";
dueDateView.setTextColor(r.getColor(R.color.taskList_dueDateOverdue));
}
dueString += DateUtilities.getDurationString(r, Math.abs(secondsLeft), 1);
dueDateView.setText(dueString);
hasProperties = true;
} else
dueDateView.setVisibility(View.GONE);
dueString += DateUtilities.getDurationString(r, Math.abs(secondsLeft), 1);
dueDateView.setText(dueString);
hasProperties = true;
} else
dueDateView.setVisibility(View.GONE);
}
// tags
List<TagIdentifier> tags = hooks.getTagController().getTaskTags(

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

@ -36,13 +36,13 @@ public abstract class AbstractModel {
*/
/** User set values */
protected ContentValues setValues = new ContentValues();
protected ContentValues setValues = new ContentValues();
/** Cached values from database */
private ContentValues values = new ContentValues();
private ContentValues values = new ContentValues();
/** Cursor into the database */
private Cursor cursor = null;
private Cursor cursor = null;
// --- constructors
@ -82,6 +82,56 @@ public abstract class AbstractModel {
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
protected String retrieveString(String field) {

@ -166,6 +166,40 @@ public abstract class AbstractTaskModel extends AbstractModel {
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
private TaskIdentifier identifier = null;
@ -266,15 +300,15 @@ public abstract class AbstractTaskModel extends AbstractModel {
// --- setters
protected void setName(String name) {
setValues.put(NAME, name);
putIfChangedFromDatabase(NAME, name);
}
protected void setNotes(String notes) {
setValues.put(NOTES, notes);
putIfChangedFromDatabase(NOTES, notes);
}
protected void setProgressPercentage(int progressPercentage) {
setValues.put(PROGRESS_PERCENTAGE, progressPercentage);
putIfChangedFromDatabase(PROGRESS_PERCENTAGE, progressPercentage);
if(getProgressPercentage() != progressPercentage &&
progressPercentage == COMPLETE_PERCENTAGE)
@ -282,58 +316,58 @@ public abstract class AbstractTaskModel extends AbstractModel {
}
protected void setImportance(Importance importance) {
setValues.put(IMPORTANCE, importance.ordinal());
putIfChangedFromDatabase(IMPORTANCE, importance.ordinal());
}
protected void setEstimatedSeconds(Integer estimatedSeconds) {
setValues.put(ESTIMATED_SECONDS, estimatedSeconds);
putIfChangedFromDatabase(ESTIMATED_SECONDS, estimatedSeconds);
}
protected void setElapsedSeconds(int elapsedSeconds) {
setValues.put(ELAPSED_SECONDS, elapsedSeconds);
putIfChangedFromDatabase(ELAPSED_SECONDS, elapsedSeconds);
}
protected void setTimerStart(Date timerStart) {
putDate(setValues, TIMER_START, timerStart);
putDate(TIMER_START, timerStart);
}
protected void setDefiniteDueDate(Date definiteDueDate) {
putDate(setValues, DEFINITE_DUE_DATE, definiteDueDate);
putDate(DEFINITE_DUE_DATE, definiteDueDate);
}
protected void setPreferredDueDate(Date preferredDueDate) {
putDate(setValues, PREFERRED_DUE_DATE, preferredDueDate);
putDate(PREFERRED_DUE_DATE, preferredDueDate);
}
protected void setHiddenUntil(Date hiddenUntil) {
putDate(setValues, HIDDEN_UNTIL, hiddenUntil);
putDate(HIDDEN_UNTIL, hiddenUntil);
}
protected void setBlockingOn(TaskIdentifier blockingOn) {
if(blockingOn == null || blockingOn.equals(getTaskIdentifier()))
setValues.put(BLOCKING_ON, (Integer)null);
putIfChangedFromDatabase(BLOCKING_ON, (Integer)null);
else
setValues.put(BLOCKING_ON, blockingOn.getId());
putIfChangedFromDatabase(BLOCKING_ON, blockingOn.getId());
}
protected void setCreationDate(Date creationDate) {
putDate(setValues, CREATION_DATE, creationDate);
putDate(CREATION_DATE, creationDate);
}
protected void setCompletionDate(Date completionDate) {
putDate(setValues, COMPLETION_DATE, completionDate);
putDate(COMPLETION_DATE, completionDate);
}
protected void setNotificationIntervalSeconds(Integer intervalInSeconds) {
setValues.put(NOTIFICATIONS, intervalInSeconds);
putIfChangedFromDatabase(NOTIFICATIONS, intervalInSeconds);
}
// --- utility methods
static void putDate(ContentValues cv, String fieldName, Date date) {
protected void putDate(String fieldName, Date date) {
if(date == null)
cv.put(fieldName, (Long)null);
putIfChangedFromDatabase(fieldName, (Long)null);
else
cv.put(fieldName, date.getTime());
putIfChangedFromDatabase(fieldName, date.getTime());
}
}

@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
@ -157,6 +158,15 @@ public class TaskController extends AbstractController {
saveSucessful = newRow >= 0;
} else {
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(),
KEY_ROWID + "=" + id, null) > 0;
}
@ -214,7 +224,7 @@ public class TaskController extends AbstractController {
public TaskModelForList fetchTaskForList(TaskIdentifier taskId) throws SQLException {
long id = taskId.getId();
Cursor cursor = database.query(true, TASK_TABLE_NAME,
TaskModelForView.FIELD_LIST,
TaskModelForList.FIELD_LIST,
KEY_ROWID + "=" + id, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();

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

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

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

Loading…
Cancel
Save