Fixed bugs:

- adding blank tasks
   - rotating after creating task causes crash
   - save creates 2 copies of a task

  Added features:
   - add ability to start/stop timer from list
   - changed importance colors
   - shrink importance spinner
pull/14/head
Tim Su 16 years ago
parent 2c63a54802
commit 95450a63bb

@ -2,6 +2,6 @@
<classpath> <classpath>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="lib/android-src.jar"/> <classpathentry kind="lib" path="lib/android-src.jar"/>
<classpathentry kind="lib" path="lib/android.jar" sourcepath="/home/timsu/projects/android-astrid/lib/android-src.jar"/> <classpathentry kind="lib" path="lib/android.jar" sourcepath="lib/android-src.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

@ -0,0 +1,9 @@
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/black"
android:gravity="center_vertical"
android:paddingLeft="10dip"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="50dip" />

@ -37,16 +37,6 @@
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
</LinearLayout> </LinearLayout>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5px" />
<Button android:id="@+id/edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/edit_label"/>
<!-- Elapsed Time --> <!-- Elapsed Time -->
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
@ -169,5 +159,15 @@
android:colorForeground="@color/view_table_values" /> android:colorForeground="@color/view_table_values" />
</LinearLayout> </LinearLayout>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5px" />
<Button android:id="@+id/edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/edit_label"/>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

@ -25,8 +25,8 @@
<color name="view_table_values">#ffbbbbbb</color> <color name="view_table_values">#ffbbbbbb</color>
<color name="view_table_overdue">#ffff0000</color> <color name="view_table_overdue">#ffff0000</color>
<color name="importance_1">#ffe36150</color> <color name="importance_1">#ffec4a8e</color>
<color name="importance_2">#ffe3ad50</color> <color name="importance_2">#ffffbe33</color>
<color name="importance_3">#ffffffff</color> <color name="importance_3">#ffffffff</color>
<color name="importance_4">#ffb5b0a8</color> <color name="importance_4">#ffb5b0a8</color>
</resources> </resources>

@ -48,6 +48,8 @@
<string name="taskList_context_edit">Edit Task</string> <string name="taskList_context_edit">Edit Task</string>
<string name="taskList_context_delete">Delete Task</string> <string name="taskList_context_delete">Delete Task</string>
<string name="taskList_context_startTimer">Start Timer</string>
<string name="taskList_context_stopTimer">Stop Timer</string>
<string name="taskList_filter_title">Filters</string> <string name="taskList_filter_title">Filters</string>
<string name="taskList_filter_hidden">Hidden/Blocked Tasks</string> <string name="taskList_filter_hidden">Hidden/Blocked Tasks</string>
<string name="taskList_filter_done">Completed Tasks</string> <string name="taskList_filter_done">Completed Tasks</string>

@ -63,6 +63,8 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
private static final int DISCARD_ID = Menu.FIRST + 1; private static final int DISCARD_ID = Menu.FIRST + 1;
private static final int DELETE_ID = Menu.FIRST + 2; private static final int DELETE_ID = Menu.FIRST + 2;
public static final int RESULT_DELETE = RESULT_FIRST_USER;
private EditText name; private EditText name;
private Spinner importance; private Spinner importance;
private TimeDurationControlSet estimatedDuration; private TimeDurationControlSet estimatedDuration;
@ -72,6 +74,8 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
private DateControlSet hiddenUntil; private DateControlSet hiddenUntil;
private EditText notes; private EditText notes;
private boolean shouldSaveState = true;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -116,6 +120,10 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
} }
private void save() { private void save() {
// usually, user accidentally created a new task
if(name.getText().length() == 0)
return;
model.setName(name.getText().toString()); model.setName(name.getText().toString());
model.setEstimatedSeconds(estimatedDuration.getTimeDurationInSeconds()); model.setEstimatedSeconds(estimatedDuration.getTimeDurationInSeconds());
model.setElapsedSeconds(elapsedDuration.getTimeDurationInSeconds()); model.setElapsedSeconds(elapsedDuration.getTimeDurationInSeconds());
@ -162,7 +170,7 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
ImportanceAdapter importanceAdapter = new ImportanceAdapter(this, ImportanceAdapter importanceAdapter = new ImportanceAdapter(this,
android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_item,
android.R.layout.simple_spinner_dropdown_item, R.layout.importance_spinner_dropdown,
Importance.values()); Importance.values());
importance.setAdapter(importanceAdapter); importance.setAdapter(importanceAdapter);
} }
@ -247,12 +255,12 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
} }
private void saveButtonClick() { private void saveButtonClick() {
save();
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();
} }
private void discardButtonClick() { private void discardButtonClick() {
shouldSaveState = false;
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
finish(); finish();
} }
@ -267,7 +275,8 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
controller.deleteTask(model.getTaskIdentifier()); controller.deleteTask(model.getTaskIdentifier());
setResult(RESULT_OK); shouldSaveState = false;
setResult(RESULT_DELETE);
finish(); finish();
} }
}) })
@ -301,21 +310,30 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
item.setIcon(android.R.drawable.ic_menu_save); item.setIcon(android.R.drawable.ic_menu_save);
item.setAlphabeticShortcut('s'); item.setAlphabeticShortcut('s');
if(model.getTaskIdentifier() != null) {
item = menu.add(Menu.NONE, DISCARD_ID, 0, R.string.discard_label); item = menu.add(Menu.NONE, DISCARD_ID, 0, R.string.discard_label);
item.setIcon(android.R.drawable.ic_menu_close_clear_cancel); item.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
item.setAlphabeticShortcut('c'); item.setAlphabeticShortcut('c');
}
item = menu.add(Menu.NONE, DISCARD_ID, 0, R.string.delete_label); item = menu.add(Menu.NONE, DELETE_ID, 0, R.string.delete_label);
item.setIcon(android.R.drawable.ic_menu_delete); item.setIcon(android.R.drawable.ic_menu_delete);
item.setAlphabeticShortcut('d'); item.setAlphabeticShortcut('d');
return true; return true;
} }
@Override
protected void onSaveInstanceState(Bundle outState) {
save();
super.onSaveInstanceState(outState);
}
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); if(shouldSaveState)
save(); save();
super.onPause();
} }
@Override @Override

@ -18,6 +18,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
package com.timsu.astrid.activities; package com.timsu.astrid.activities;
import java.util.Date;
import java.util.List; import java.util.List;
import android.app.Activity; import android.app.Activity;
@ -70,6 +71,7 @@ public class TaskList extends Activity {
private static final int CONTEXT_EDIT_ID = Menu.FIRST + 10; private static final int CONTEXT_EDIT_ID = Menu.FIRST + 10;
private static final int CONTEXT_DELETE_ID = Menu.FIRST + 11; private static final int CONTEXT_DELETE_ID = Menu.FIRST + 11;
private static final int CONTEXT_TIMER_ID = Menu.FIRST + 12;
private static final int CONTEXT_FILTER_HIDDEN = Menu.FIRST + 20; private static final int CONTEXT_FILTER_HIDDEN = Menu.FIRST + 20;
private static final int CONTEXT_FILTER_DONE = Menu.FIRST + 21; private static final int CONTEXT_FILTER_DONE = Menu.FIRST + 21;
@ -78,6 +80,7 @@ public class TaskList extends Activity {
private ListView listView; private ListView listView;
private Button addButton; private Button addButton;
private List<TaskModelForList> taskArray;
private boolean filterShowHidden = false; private boolean filterShowHidden = false;
private boolean filterShowDone = false; private boolean filterShowDone = false;
@ -135,8 +138,7 @@ public class TaskList extends Activity {
startManagingCursor(tasksCursor); startManagingCursor(tasksCursor);
int totalTasks = tasksCursor.getCount(); int totalTasks = tasksCursor.getCount();
List<TaskModelForList> taskArray = taskArray = controller.createTaskListFromCursor(tasksCursor, !filterShowHidden);
controller.createTaskListFromCursor(tasksCursor, !filterShowHidden);
int hiddenTasks = totalTasks - taskArray.size(); int hiddenTasks = totalTasks - taskArray.size();
// hide "add" button if we have a few tasks // hide "add" button if we have a few tasks
@ -266,13 +268,19 @@ public class TaskList extends Activity {
public void onCreateContextMenu(ContextMenu menu, View v, public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) { ContextMenuInfo menuInfo) {
TaskModelForList task = (TaskModelForList)v.getTag(); TaskModelForList task = (TaskModelForList)v.getTag();
int id = (int)task.getTaskIdentifier().getId();
menu.add(id, CONTEXT_EDIT_ID, Menu.NONE, menu.add(position, CONTEXT_EDIT_ID, Menu.NONE,
R.string.taskList_context_edit); R.string.taskList_context_edit);
menu.add(id, CONTEXT_DELETE_ID, Menu.NONE, menu.add(position, CONTEXT_DELETE_ID, Menu.NONE,
R.string.taskList_context_delete); R.string.taskList_context_delete);
int timerTitle;
if(task.getTimerStart() == null)
timerTitle = R.string.taskList_context_startTimer;
else
timerTitle = R.string.taskList_context_stopTimer;
menu.add(position, CONTEXT_TIMER_ID, Menu.NONE, timerTitle);
menu.setHeaderTitle(task.getName()); menu.setHeaderTitle(task.getName());
} }
}); });
@ -329,16 +337,24 @@ public class TaskList extends Activity {
return true; return true;
case CONTEXT_EDIT_ID: case CONTEXT_EDIT_ID:
long id = item.getGroupId(); // hackhack =( TaskModelForList task = taskArray.get(item.getGroupId());
Intent intent = new Intent(TaskList.this, TaskEdit.class); Intent intent = new Intent(TaskList.this, TaskEdit.class);
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, id); intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, task.getTaskIdentifier().getId());
startActivityForResult(intent, ACTIVITY_EDIT); startActivityForResult(intent, ACTIVITY_EDIT);
return true; return true;
case CONTEXT_DELETE_ID: case CONTEXT_DELETE_ID:
id = item.getGroupId(); task = taskArray.get(item.getGroupId());
deleteTask(task.getTaskIdentifier());
deleteTask(new TaskIdentifier(id)); return true;
case CONTEXT_TIMER_ID:
task = taskArray.get(item.getGroupId());
if(task.getTimerStart() == null)
task.setTimerStart(new Date());
else {
task.stopTimerAndUpdateElapsedTime();
}
controller.saveTask(task);
fillData();
return true; return true;
case CONTEXT_FILTER_HIDDEN: case CONTEXT_FILTER_HIDDEN:

@ -22,7 +22,7 @@ public abstract class TaskModificationActivity<MODEL_TYPE extends
// check if we have a TaskIdentifier // check if we have a TaskIdentifier
TaskIdentifier identifier = null; TaskIdentifier identifier = null;
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
if(savedInstanceState != null) { if(savedInstanceState != null && savedInstanceState.containsKey(LOAD_INSTANCE_TOKEN)) {
identifier = new TaskIdentifier(savedInstanceState.getLong( identifier = new TaskIdentifier(savedInstanceState.getLong(
LOAD_INSTANCE_TOKEN)); LOAD_INSTANCE_TOKEN));
} else if(extras != null) } else if(extras != null)
@ -43,6 +43,7 @@ public abstract class TaskModificationActivity<MODEL_TYPE extends
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
if(model.getTaskIdentifier() != null)
outState.putLong(LOAD_INSTANCE_TOKEN, model.getTaskIdentifier().getId()); outState.putLong(LOAD_INSTANCE_TOKEN, model.getTaskIdentifier().getId());
} }
} }

@ -22,10 +22,14 @@ import java.util.Date;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
@ -46,6 +50,9 @@ import com.timsu.astrid.widget.NumberPickerDialog;
public class TaskView extends TaskModificationActivity<TaskModelForView> { public class TaskView extends TaskModificationActivity<TaskModelForView> {
private static final int ACTIVITY_EDIT = 0; private static final int ACTIVITY_EDIT = 0;
private static final int EDIT_ID = Menu.FIRST;
private static final int DELETE_ID = Menu.FIRST + 1;
private TextView name; private TextView name;
private TextView elapsed; private TextView elapsed;
private TextView estimated; private TextView estimated;
@ -78,6 +85,8 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
return controller.fetchTaskForView(identifier); return controller.fetchTaskForView(identifier);
} }
// --- initialization
private void setUpUIComponents() { private void setUpUIComponents() {
Resources r = getResources(); Resources r = getResources();
setTitle(r.getString(R.string.taskView_title)); setTitle(r.getString(R.string.taskView_title));
@ -115,7 +124,7 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
} }
}; };
// update the UI // update the timer UI
updateTimer = new Timer(); updateTimer = new Timer();
updateTimer.scheduleAtFixedRate(elapsedTimeUpdater, 0, 1000); updateTimer.scheduleAtFixedRate(elapsedTimeUpdater, 0, 1000);
} }
@ -125,10 +134,7 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
edit.setOnClickListener(new View.OnClickListener() { edit.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent(TaskView.this, TaskEdit.class); editButtonClick();
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN,
model.getTaskIdentifier().getId());
startActivityForResult(intent, ACTIVITY_EDIT);
} }
}); });
@ -139,11 +145,7 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
model.setTimerStart(new Date()); model.setTimerStart(new Date());
controller.saveTask(model); controller.saveTask(model);
} else { } else {
long start = model.getTimerStart().getTime(); model.stopTimerAndUpdateElapsedTime();
model.setTimerStart(null);
long secondsElapsed = (System.currentTimeMillis() - start)/1000;
model.setElapsedSeconds((int) (model.getElapsedSeconds() +
secondsElapsed));
controller.saveTask(model); controller.saveTask(model);
} }
@ -196,16 +198,34 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
view.setText(text); view.setText(text);
} }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem item;
item = menu.add(Menu.NONE, EDIT_ID, 0, R.string.edit_label);
item.setIcon(android.R.drawable.ic_menu_edit);
item.setAlphabeticShortcut('s');
item = menu.add(Menu.NONE, DELETE_ID, 0, R.string.delete_label);
item.setIcon(android.R.drawable.ic_menu_delete);
item.setAlphabeticShortcut('d');
return true;
}
// --- event handlers
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, protected void onActivityResult(int requestCode, int resultCode,
Intent intent) { Intent intent) {
if(resultCode == RESULT_CANCELED)
return;
// if user edits a task, take them straight to the listing page // if user doesn't click 'back', finish this activity too
if(resultCode != RESULT_CANCELED) {
setResult(resultCode); setResult(resultCode);
finish(); finish();
} }
}
@Override @Override
protected void onPause() { protected void onPause() {
@ -218,6 +238,54 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
populateFields(); populateFields();
} }
@Override
/** Cancel the timer thread */
protected void onDestroy() {
super.onDestroy();
updateTimer.cancel();
}
// --- event response methods
private void editButtonClick() {
Intent intent = new Intent(TaskView.this, TaskEdit.class);
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN,
model.getTaskIdentifier().getId());
startActivityForResult(intent, ACTIVITY_EDIT);
}
private void deleteButtonClick() {
new AlertDialog.Builder(this)
.setTitle(R.string.delete_title)
.setMessage(R.string.delete_this_task_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
controller.deleteTask(model.getTaskIdentifier());
setResult(RESULT_OK);
finish();
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch(item.getItemId()) {
case EDIT_ID:
editButtonClick();
return true;
case DELETE_ID:
deleteButtonClick();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
/** Update components that depend on elapsed time */ /** Update components that depend on elapsed time */
private void updateElapsedTimeText() { private void updateElapsedTimeText() {
Resources r = getResources(); Resources r = getResources();
@ -253,12 +321,5 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
progressDialog.setInitialValue(model.getProgressPercentage()); progressDialog.setInitialValue(model.getProgressPercentage());
} }
@Override
/** Cancel the timer thread */
protected void onDestroy() {
super.onDestroy();
updateTimer.cancel();
}
} }

@ -15,7 +15,7 @@ public enum Importance {
int label; int label;
int color; int color;
public static final Importance DEFAULT = LEVEL_2; public static final Importance DEFAULT = LEVEL_3;
private Importance(int label, int color) { private Importance(int label, int color) {
this.label = label; this.label = label;

@ -136,6 +136,15 @@ public abstract class AbstractTaskModel extends AbstractModel {
return getProgressPercentage() >= COMPLETE_PERCENTAGE; return getProgressPercentage() >= COMPLETE_PERCENTAGE;
} }
/** Stops the timer & increments elapsed time. Requires timerStart and
* elapsedSeconds */
protected void stopTimerAndUpdateElapsedTime() {
long start = getTimerStart().getTime();
setTimerStart(null);
long secondsElapsed = (System.currentTimeMillis() - start)/1000;
setElapsedSeconds((int) (getElapsedSeconds() + secondsElapsed));
}
// --- task identifier // --- task identifier
private TaskIdentifier identifier = null; private TaskIdentifier identifier = null;

@ -1,9 +1,7 @@
package com.timsu.astrid.data.task; package com.timsu.astrid.data.task;
import java.util.Date;
import java.util.List; import java.util.List;
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;
@ -46,27 +44,16 @@ public class TaskController extends AbstractController {
return database.delete(TASK_TABLE_NAME, KEY_ROWID + "=" + id, null) > 0; return database.delete(TASK_TABLE_NAME, KEY_ROWID + "=" + id, null) > 0;
} }
/** Sets the timer start time to the given value. Passing in "null"
* signifies that the timer is not running. */
public boolean startTimer(TaskModelForView task, Date startDate) throws
SQLException {
task.setTimerStart(startDate);
long id = task.getTaskIdentifier().getId();
ContentValues values = new ContentValues();
AbstractTaskModel.putDate(values, AbstractTaskModel.TIMER_START,
startDate);
return database.update(TASK_TABLE_NAME, values, KEY_ROWID + "=" + id,
null) > 0;
}
/** Saves the given task to the database. Returns true on success. */ /** Saves the given task to the database. Returns true on success. */
public boolean saveTask(AbstractTaskModel task) { public boolean saveTask(AbstractTaskModel task) {
boolean saveSucessful; boolean saveSucessful;
if(task.getTaskIdentifier() == null) { if(task.getTaskIdentifier() == null) {
saveSucessful = database.insert(TASK_TABLE_NAME, AbstractTaskModel.NAME, long newRow = database.insert(TASK_TABLE_NAME, AbstractTaskModel.NAME,
task.getMergedValues()) >= 0; task.getMergedValues());
task.setTaskIdentifier(new TaskIdentifier(newRow));
saveSucessful = newRow >= 0;
} else { } else {
long id = task.getTaskIdentifier().getId(); long id = task.getTaskIdentifier().getId();
saveSucessful = database.update(TASK_TABLE_NAME, task.getSetValues(), saveSucessful = database.update(TASK_TABLE_NAME, task.getSetValues(),

@ -180,4 +180,14 @@ public class TaskModelForList extends AbstractTaskModel {
public void setProgressPercentage(int progressPercentage) { public void setProgressPercentage(int progressPercentage) {
super.setProgressPercentage(progressPercentage); super.setProgressPercentage(progressPercentage);
} }
@Override
public void setTimerStart(Date timerStart) {
super.setTimerStart(timerStart);
}
@Override
public void stopTimerAndUpdateElapsedTime() {
super.stopTimerAndUpdateElapsedTime();
}
} }

@ -99,7 +99,7 @@ public class TaskModelForView extends AbstractTaskModel {
} }
@Override @Override
public void setElapsedSeconds(int elapsedSeconds) { public void stopTimerAndUpdateElapsedTime() {
super.setElapsedSeconds(elapsedSeconds); super.stopTimerAndUpdateElapsedTime();
} }
} }

Loading…
Cancel
Save