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>
<classpathentry kind="src" path="src"/>
<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"/>
</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" />

@ -36,16 +36,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</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 -->
<LinearLayout
@ -168,6 +158,16 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:colorForeground="@color/view_table_values" />
</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>
</ScrollView>

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

@ -48,6 +48,8 @@
<string name="taskList_context_edit">Edit 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_hidden">Hidden/Blocked Tasks</string>
<string name="taskList_filter_done">Completed Tasks</string>

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

@ -18,6 +18,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.activities;
import java.util.Date;
import java.util.List;
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_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_DONE = Menu.FIRST + 21;
@ -78,6 +80,7 @@ public class TaskList extends Activity {
private ListView listView;
private Button addButton;
private List<TaskModelForList> taskArray;
private boolean filterShowHidden = false;
private boolean filterShowDone = false;
@ -135,8 +138,7 @@ public class TaskList extends Activity {
startManagingCursor(tasksCursor);
int totalTasks = tasksCursor.getCount();
List<TaskModelForList> taskArray =
controller.createTaskListFromCursor(tasksCursor, !filterShowHidden);
taskArray = controller.createTaskListFromCursor(tasksCursor, !filterShowHidden);
int hiddenTasks = totalTasks - taskArray.size();
// 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,
ContextMenuInfo menuInfo) {
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);
menu.add(id, CONTEXT_DELETE_ID, Menu.NONE,
menu.add(position, CONTEXT_DELETE_ID, Menu.NONE,
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());
}
});
@ -329,16 +337,24 @@ public class TaskList extends Activity {
return true;
case CONTEXT_EDIT_ID:
long id = item.getGroupId(); // hackhack =(
TaskModelForList task = taskArray.get(item.getGroupId());
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);
return true;
case CONTEXT_DELETE_ID:
id = item.getGroupId();
deleteTask(new TaskIdentifier(id));
task = taskArray.get(item.getGroupId());
deleteTask(task.getTaskIdentifier());
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;
case CONTEXT_FILTER_HIDDEN:

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

@ -22,10 +22,14 @@ import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
@ -46,6 +50,9 @@ import com.timsu.astrid.widget.NumberPickerDialog;
public class TaskView extends TaskModificationActivity<TaskModelForView> {
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 elapsed;
private TextView estimated;
@ -78,6 +85,8 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
return controller.fetchTaskForView(identifier);
}
// --- initialization
private void setUpUIComponents() {
Resources r = getResources();
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.scheduleAtFixedRate(elapsedTimeUpdater, 0, 1000);
}
@ -125,10 +134,7 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
edit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(TaskView.this, TaskEdit.class);
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN,
model.getTaskIdentifier().getId());
startActivityForResult(intent, ACTIVITY_EDIT);
editButtonClick();
}
});
@ -139,11 +145,7 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
model.setTimerStart(new Date());
controller.saveTask(model);
} else {
long start = model.getTimerStart().getTime();
model.setTimerStart(null);
long secondsElapsed = (System.currentTimeMillis() - start)/1000;
model.setElapsedSeconds((int) (model.getElapsedSeconds() +
secondsElapsed));
model.stopTimerAndUpdateElapsedTime();
controller.saveTask(model);
}
@ -196,15 +198,33 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
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
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if(resultCode == RESULT_CANCELED)
return;
// if user edits a task, take them straight to the listing page
setResult(resultCode);
finish();
// if user doesn't click 'back', finish this activity too
if(resultCode != RESULT_CANCELED) {
setResult(resultCode);
finish();
}
}
@Override
@ -218,6 +238,54 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
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 */
private void updateElapsedTimeText() {
Resources r = getResources();
@ -253,12 +321,5 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
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 color;
public static final Importance DEFAULT = LEVEL_2;
public static final Importance DEFAULT = LEVEL_3;
private Importance(int label, int color) {
this.label = label;

@ -136,6 +136,15 @@ public abstract class AbstractTaskModel extends AbstractModel {
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
private TaskIdentifier identifier = null;

@ -1,9 +1,7 @@
package com.timsu.astrid.data.task;
import java.util.Date;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
@ -46,27 +44,16 @@ public class TaskController extends AbstractController {
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. */
public boolean saveTask(AbstractTaskModel task) {
boolean saveSucessful;
if(task.getTaskIdentifier() == null) {
saveSucessful = database.insert(TASK_TABLE_NAME, AbstractTaskModel.NAME,
task.getMergedValues()) >= 0;
long newRow = database.insert(TASK_TABLE_NAME, AbstractTaskModel.NAME,
task.getMergedValues());
task.setTaskIdentifier(new TaskIdentifier(newRow));
saveSucessful = newRow >= 0;
} else {
long id = task.getTaskIdentifier().getId();
saveSucessful = database.update(TASK_TABLE_NAME, task.getSetValues(),

@ -180,4 +180,14 @@ public class TaskModelForList extends AbstractTaskModel {
public void setProgressPercentage(int 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
public void setElapsedSeconds(int elapsedSeconds) {
super.setElapsedSeconds(elapsedSeconds);
public void stopTimerAndUpdateElapsedTime() {
super.stopTimerAndUpdateElapsedTime();
}
}

Loading…
Cancel
Save