Now got edit to work. yay! no saving tags, and no alerts. Still to do: due date stuff, urgency stuff

pull/14/head
Tim Su 14 years ago
parent 4b85db1e46
commit e06f60b95f

@ -83,7 +83,7 @@
<activity android:name=".activities.TaskListNotify"
android:launchMode="singleTop" />
<!-- Activity that creates or edits tasks -->
<activity android:name=".activities.TaskEdit"
<activity android:name="com.todoroo.astrid.activity.TaskEditActivity"
android:icon="@drawable/icon_add"
android:label="@string/taskEdit_label">
<intent-filter>

@ -176,6 +176,13 @@ public abstract class AbstractModel implements Parcelable {
setValues.put(ID_PROPERTY_NAME, id);
}
/**
* @return true if this model has found Jesus (i.e. the database)
*/
public boolean isSaved() {
return getId() != NO_ID;
}
/**
* @param property
* @return true if setValues or values contains this property
@ -228,6 +235,16 @@ public abstract class AbstractModel implements Parcelable {
saver.save(property, setValues, value);
}
/**
* Merges content values with those coming from another source
*/
public synchronized <TYPE> void mergeWith(ContentValues other) {
if (setValues == null)
setValues = other;
else
setValues.putAll(other);
}
/**
* Clear the key for the given property
* @param property
@ -332,7 +349,7 @@ public abstract class AbstractModel implements Parcelable {
protected static final class ModelCreator<TYPE extends AbstractModel>
implements Parcelable.Creator<TYPE> {
private Class<TYPE> cls;
private final Class<TYPE> cls;
public ModelCreator(Class<TYPE> cls) {
super();

@ -7,6 +7,7 @@ import java.net.URL;
import java.net.URLConnection;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@ -106,4 +107,24 @@ public class AndroidUtilities {
}
}
/**
* Put an arbitrary object into a {@link ContentValues}
* @param target
* @param key
* @param value
*/
public static void putInto(ContentValues target, String key, Object value) {
if(value instanceof String)
target.put(key, (String) value);
else if(value instanceof Long)
target.put(key, (Long) value);
else if(value instanceof Integer)
target.put(key, (Integer) value);
else if(value instanceof Double)
target.put(key, (Double) value);
else
throw new UnsupportedOperationException("Could not handle type " + //$NON-NLS-1$
value.getClass());
}
}

@ -10,6 +10,7 @@ import java.util.Date;
import android.content.res.Resources;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
@ -85,9 +86,8 @@ public class DateUtilities {
/**
* Convenience method for dropping the preposition argument.
*/
public String getDurationString(Resources r, int timeInSeconds,
int unitsToShow) {
return getDurationString(r, timeInSeconds, unitsToShow, false);
public String getDurationString(long duration, int unitsToShow) {
return getDurationString(duration, unitsToShow, false);
}
/**
@ -100,17 +100,17 @@ public class DateUtilities {
* @param withPreposition whether there is a preceding preposition
* @return
*/
public String getDurationString(Resources r, int timeInSeconds,
int unitsToShow, boolean withPreposition) {
public String getDurationString(long duration, int unitsToShow, boolean withPreposition) {
Resources r = ContextManager.getContext().getResources();
int years, months, days, hours, minutes, seconds;
short unitsDisplayed = 0;
timeInSeconds = Math.abs(timeInSeconds);
duration = Math.abs(duration);
if(timeInSeconds == 0)
if(duration == 0)
return r.getQuantityString(secondsResource, 0, 0);
Date now = new Date(80, 0, 1);
Date then = unixtimeToDate((int)(now.getTime() / 1000L) + timeInSeconds);
Date now = new Date();
Date then = new Date(DateUtilities.now() + duration);
years = then.getYear() - now.getYear();
months = then.getMonth() - now.getMonth();

@ -27,7 +27,7 @@
<item android:state_checked="false"
android:state_enabled="true"
android:drawable="@drawable/btn_check_0" />
android:drawable="@drawable/btn_check_off" />
<item android:state_checked="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

@ -64,6 +64,13 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<!-- Quick Add Button -->
<ImageButton android:id="@+id/quickAddButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/btn_add"/>
<!-- Quick Add Task -->
<EditText android:id="@+id/quickAddText"
@ -75,12 +82,12 @@
android:autoText="true"
android:capitalize="sentences"/>
<!-- Quick Add Button -->
<ImageButton android:id="@+id/quickAddButton"
<!-- Extended Add Button -->
<ImageButton android:id="@+id/extendedAddButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@android:drawable/ic_input_add"/>
android:src="@drawable/btn_add_extended"/>
</LinearLayout>

@ -14,10 +14,12 @@
<!-- completion check-box -->
<CheckBox android:id="@+id/completeBox"
android:layout_width="40px"
android:layout_height="45px"
android:layout_width="52px"
android:layout_height="52px"
android:layout_weight="1"
android:paddingLeft="10px" />
android:paddingLeft="10px"
android:button="@drawable/btn_check"
android:scaleType="center"/>
<LinearLayout android:id="@+id/details"
android:layout_width="wrap_content"

@ -155,5 +155,5 @@
<item>07:00</item>
<item>08:00</item>
</string-array>
</resources>

@ -1,24 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
ASTRID: Android's Simple Task Recording Dashboard
Copyright (c) 2009 Tim Su
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
<resources>
<color name="task_list_overdue">#FFFB6666</color>
<color name="task_list_normal">#FFFFFFFF</color>

@ -729,12 +729,12 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
if(task.isTaskCompleted() || task == recentlyCompleted) {
name.setPaintFlags(name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
name.setTextColor(r.getColor(R.color.task_list_done));
progress.setButtonDrawable(R.drawable.btn_check0);
progress.setButtonDrawable(R.drawable.btn_check);
progress.setChecked(true);
} else {
name.setPaintFlags(name.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
name.setTextColor(r.getColor(task.getTaskColorResource(getContext())));
progress.setButtonDrawable(R.drawable.btn_check0);
progress.setButtonDrawable(R.drawable.btn_check);
}
}

@ -340,8 +340,8 @@ public abstract class AbstractTaskModel extends AbstractModel {
// --- helper classes
public static class RepeatInfo {
private RepeatInterval interval;
private int value;
private final RepeatInterval interval;
private final int value;
public RepeatInfo(RepeatInterval repeatInterval, int value) {
this.interval = repeatInterval;
@ -362,6 +362,26 @@ public abstract class AbstractTaskModel extends AbstractModel {
return value;
}
public static int toSingleField(RepeatInfo repeatInfo) {
int repeat;
if(repeatInfo == null)
repeat = 0;
else
repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) +
repeatInfo.interval.ordinal();
return repeat;
}
public static RepeatInfo fromSingleField(int repeat) {
if(repeat == 0)
return null;
int value = repeat >> REPEAT_VALUE_OFFSET;
RepeatInterval interval = RepeatInterval.values()
[repeat - (value << REPEAT_VALUE_OFFSET)];
return new RepeatInfo(interval, value);
}
}
// --- task identifier

@ -66,6 +66,12 @@ public class DateControlSet implements OnTimeSetListener,
return date;
}
public long getMillis() {
if(date == null)
return 0;
return date.getTime();
}
/** Initialize the components for the given date field */
public void setDate(Date newDate) {
if(newDate == null) {
@ -82,6 +88,13 @@ public class DateControlSet implements OnTimeSetListener,
updateTime();
}
public void setDate(long newDate) {
if(newDate == 0L)
setDate(null);
else
setDate(new Date(newDate));
}
public void onDateSet(DatePicker view, int year, int month, int monthDay) {
date.setYear(year - 1900);
date.setMonth(month);

@ -0,0 +1,104 @@
package com.todoroo.astrid.activity;
import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle;
import com.flurry.android.FlurryAgent;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.utility.Constants;
abstract public class AbstractModelTabActivity<TYPE> extends TabActivity {
// from AstridActivity
static {
AstridDependencyInjector.initialize();
}
@Override
protected void onStart() {
super.onStart();
FlurryAgent.onStartSession(this, Constants.FLURRY_KEY);
}
@Override
protected void onStop() {
super.onStop();
FlurryAgent.onEndSession(this);
}
// from AbstractModelActivity
// --- bundle arguments
/**
* Action Item ID
*/
public static final String ID_TOKEN = "i"; //$NON-NLS-1$
// --- instance variables
@Autowired
protected ExceptionService exceptionService;
@Autowired
protected Database database;
protected TYPE model = null;
// --- abstract methods
abstract protected TYPE fetchModel(long id);
/**
* Load Bente Dependency Injector
*/
static {
AstridDependencyInjector.initialize();
}
public AbstractModelTabActivity() {
DependencyInjectionService.getInstance().inject(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ContextManager.setContext(this);
loadItem(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
loadItem(intent);
}
/**
* Loads action item from the given intent
* @param intent
*/
protected void loadItem(Intent intent) {
long idParam = intent.getLongExtra(ID_TOKEN, -1L);
if(idParam == -1) {
exceptionService.reportError("AMA-no-token", null); //$NON-NLS-1$
finish();
return;
}
database.openForReading();
model = fetchModel(idParam);
if(model == null) {
exceptionService.reportError("AMA-no-task", new NullPointerException("model")); //$NON-NLS-1$ //$NON-NLS-2$
finish();
return;
}
}
}

@ -0,0 +1,868 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.todoroo.astrid.activity;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
import com.timsu.astrid.data.enums.RepeatInterval;
import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.task.TaskModelForEdit;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
import com.timsu.astrid.utilities.AstridUtilities;
import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.utilities.Preferences;
import com.timsu.astrid.widget.DateControlSet;
import com.timsu.astrid.widget.DateWithNullControlSet;
import com.timsu.astrid.widget.NumberPicker;
import com.timsu.astrid.widget.NumberPickerDialog;
import com.timsu.astrid.widget.TimeDurationControlSet;
import com.timsu.astrid.widget.NumberPickerDialog.OnNumberPickedListener;
import com.timsu.astrid.widget.TimeDurationControlSet.TimeDurationType;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TagService.Tag;
/**
* This activity is responsible for creating new tasks and editing existing
* ones. It saves a task when it is paused (screen rotated, back button
* pressed) as long as the task has a title.
*
* @author timsu
*
*/
public final class TaskEditActivity extends AbstractModelTabActivity<Task> {
// --- request codes
@SuppressWarnings("unused")
private static final int REQUEST_CODE_OPERATION = 0;
// --- menu codes
private static final int MENU_SAVE_ID = Menu.FIRST;
private static final int MENU_DISCARD_ID = Menu.FIRST + 1;
private static final int MENU_DELETE_ID = Menu.FIRST + 2;
// --- result codes
public static final int RESULT_CODE_SAVED = RESULT_FIRST_USER;
public static final int RESULT_CODE_DISCARDED = RESULT_FIRST_USER + 1;
public static final int RESULT_CODE_DELETED = RESULT_FIRST_USER + 2;
// --- other constants
private static final int MAX_TAGS = 5;
private static final int MAX_ALERTS = 5;
private static final String TAB_BASIC = "basic"; //$NON-NLS-1$
private static final String TAB_DATES = "dates"; //$NON-NLS-1$
private static final String TAB_ALERTS = "alerts"; //$NON-NLS-1$
private static final int DEFAULT_CAL_TIME = 3600;
// --- autowired
@Autowired
TaskService taskService;
@Autowired
DateUtilities dateUtilities;
// --- UI components
EditText title;
ImportanceControlSet importance;
TimeDurationControlSet estimatedDuration;
TimeDurationControlSet elapsedDuration;
TimeDurationControlSet notification;
DateControlSet dueDate;
DateControlSet preferredDueDate;
DateControlSet hiddenUntil;
EditText notes;
LinearLayout tagsContainer;
NotifyFlagControlSet flags;
LinearLayout alertsContainer;
Button repeatValue;
Spinner repeatInterval;
CheckBox addToCalendar;
// --- other instance variables
/** whether task should be saved when this activity exits */
boolean shouldSaveState = true;
/** whether help should be shown when setting repeat */
boolean repeatHelpShown = false;
/** list of all tags */
Tag[] tags;
/* ======================================================================
* ======================================================= initialization
* ====================================================================== */
@Override
protected Task fetchModel(long id) {
database.openForWriting();
if(id == Task.NO_ID) {
FlurryAgent.onEvent("create-task"); //$NON-NLS-1$
Task task = new Task();
taskService.save(task, false);
return task;
}
FlurryAgent.onEvent("edit-task"); //$NON-NLS-1$
return taskService.fetchById(id, Task.PROPERTIES);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TabHost tabHost = getTabHost();
tabHost.setPadding(0, 4, 0, 0);
Resources r = getResources();
LayoutInflater.from(this).inflate(R.layout.task_edit, tabHost.getTabContentView(), true);
tabHost.addTab(tabHost.newTabSpec(TAB_BASIC).setIndicator(r.getString(R.string.taskEdit_tab_basic),
r.getDrawable(R.drawable.ic_dialog_info_c)).setContent(R.id.tab_basic));
tabHost.addTab(tabHost.newTabSpec(TAB_DATES).setIndicator(r.getString(R.string.taskEdit_tab_dates),
r.getDrawable(R.drawable.ic_dialog_time_c)).setContent(R.id.tab_dates));
tabHost.addTab(tabHost.newTabSpec(TAB_ALERTS).setIndicator(r.getString(R.string.taskEdit_tab_alerts),
r.getDrawable(R.drawable.ic_dialog_alert_c)).setContent(R.id.tab_notification));
// weird case that has been hit before.
if(model == null)
model = new Task();
setUpUIComponents();
setUpListeners();
// disable name input box until user requests it
AstridUtilities.suppressVirtualKeyboard(title);
}
/* ======================================================================
* ==================================================== UI initialization
* ====================================================================== */
/** Initialize UI components */
private void setUpUIComponents() {
Resources r = getResources();
setTitle(new StringBuilder().append(r.getString(R.string.taskEdit_titleGeneric)));
// populate instance variables
title = (EditText)findViewById(R.id.name);
importance = new ImportanceControlSet(R.id.importance_container);
tagsContainer = (LinearLayout)findViewById(R.id.tags_container);
estimatedDuration = new TimeDurationControlSet(this,
R.id.estimatedDuration, 0, R.string.hour_minutes_dialog,
TimeDurationType.HOURS_MINUTES);
elapsedDuration = new TimeDurationControlSet(this, R.id.elapsedDuration,
0, R.string.hour_minutes_dialog,
TimeDurationType.HOURS_MINUTES);
notification = new TimeDurationControlSet(this, R.id.notification,
R.string.notification_prefix, R.string.notification_dialog,
TimeDurationType.DAYS_HOURS);
dueDate = new DateWithNullControlSet(this, R.id.definiteDueDate_notnull,
R.id.definiteDueDate_date, R.id.definiteDueDate_time);
preferredDueDate = new DateWithNullControlSet(this, R.id.preferredDueDate_notnull,
R.id.preferredDueDate_date, R.id.preferredDueDate_time);
hiddenUntil = new DateWithNullControlSet(this, R.id.hiddenUntil_notnull,
R.id.hiddenUntil_date, R.id.hiddenUntil_time);
notes = (EditText)findViewById(R.id.notes);
flags = new NotifyFlagControlSet(R.id.flag_before,
R.id.flag_during, R.id.flag_after, R.id.flag_nonstop);
alertsContainer = (LinearLayout)findViewById(R.id.alert_container);
repeatInterval = (Spinner)findViewById(R.id.repeat_interval);
repeatValue = (Button)findViewById(R.id.repeat_value);
addToCalendar = (CheckBox)findViewById(R.id.add_to_calendar);
// individual ui component initialization
ArrayAdapter<String> repeatAdapter = new ArrayAdapter<String>(
this, android.R.layout.simple_spinner_item,
RepeatInterval.getLabels(getResources()));
repeatAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
repeatInterval.setAdapter(repeatAdapter);
// load tags
TagService tagService = new TagService(this);
tags = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE);
// read data
populateFields();
}
/** Set up button listeners */
private void setUpListeners() {
Button saveButtonGeneral = (Button) findViewById(R.id.save_general);
saveButtonGeneral.setOnClickListener(mSaveListener);
Button saveButtonDates = (Button) findViewById(R.id.save_dates);
saveButtonDates.setOnClickListener(mSaveListener);
Button saveButtonNotify = (Button) findViewById(R.id.save_notify);
saveButtonNotify.setOnClickListener(mSaveListener);
Button discardButtonGeneral = (Button) findViewById(R.id.discard_general);
discardButtonGeneral.setOnClickListener(mDiscardListener);
Button discardButtonDates = (Button) findViewById(R.id.discard_dates);
discardButtonDates.setOnClickListener(mDiscardListener);
Button discardButtonNotify = (Button) findViewById(R.id.discard_notify);
discardButtonNotify.setOnClickListener(mDiscardListener);
Button deleteButtonGeneral = (Button) findViewById(R.id.delete_general);
Button deleteButtonDates = (Button) findViewById(R.id.delete_dates);
Button deleteButtonNotify = (Button) findViewById(R.id.delete_notify);
if(model.getId() == Task.NO_ID) {
deleteButtonGeneral.setVisibility(View.GONE);
deleteButtonDates.setVisibility(View.GONE);
deleteButtonNotify.setVisibility(View.GONE);
} else {
deleteButtonGeneral.setOnClickListener(mDeleteListener);
deleteButtonDates.setOnClickListener(mDeleteListener);
deleteButtonNotify.setOnClickListener(mDeleteListener);
}
Button addAlertButton = (Button) findViewById(R.id.addAlert);
addAlertButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
addAlert(null);
}
});
repeatValue.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
repeatValueClick();
}
});
}
private final View.OnClickListener mSaveListener = new View.OnClickListener() {
public void onClick(View v) {
saveButtonClick();
}
};
private final View.OnClickListener mDiscardListener = new View.OnClickListener() {
public void onClick(View v) {
discardButtonClick();
}
};
private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
public void onClick(View v) {
deleteButtonClick();
}
};
/** Set up the repeat value button */
private void setRepeatValue(int value) {
if(value == 0)
repeatValue.setText(R.string.repeat_value_unset);
else
repeatValue.setText(Integer.toString(value));
repeatValue.setTag(value);
}
private RepeatInfo getRepeatValue() {
if(repeatValue.getTag().equals(0))
return null;
return new RepeatInfo(RepeatInterval.values()
[repeatInterval.getSelectedItemPosition()],
(Integer)repeatValue.getTag());
}
/** Adds an alert to the alert field */
protected boolean addAlert(Date alert) {
if(alertsContainer.getChildCount() >= MAX_ALERTS)
return false;
LayoutInflater inflater = getLayoutInflater();
final View alertItem = inflater.inflate(R.layout.edit_alert_item, null);
alertsContainer.addView(alertItem);
DateControlSet dcs = new DateControlSet(this,
(Button)alertItem.findViewById(R.id.date),
(Button)alertItem.findViewById(R.id.time));
dcs.setDate(alert);
alertItem.setTag(dcs);
ImageButton reminderRemoveButton;
reminderRemoveButton = (ImageButton)alertItem.findViewById(R.id.button1);
reminderRemoveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
alertsContainer.removeView(alertItem);
}
});
return true;
}
/* ======================================================================
* =============================================== model reading / saving
* ====================================================================== */
/** Populate UI component values from the model */
private void populateFields() {
Resources r = getResources();
title.setText(model.getValue(Task.TITLE));
if(title.getText().length() > 0) {
setTitle(new StringBuilder().
append(r.getString(R.string.taskEdit_titlePrefix)).
append(" "). //$NON-NLS-1$
append(title.getText()));
}
estimatedDuration.setTimeDuration(model.getValue(Task.ESTIMATED_SECONDS));
elapsedDuration.setTimeDuration(model.getValue(Task.ELAPSED_SECONDS));
importance.setImportance(model.getValue(Task.IMPORTANCE));
dueDate.setDate(model.getValue(Task.DUE_DATE));
hiddenUntil.setDate(model.getValue(Task.HIDE_UNTIL));
notification.setTimeDuration(model.getValue(Task.NOTIFICATIONS));
flags.setValue(model.getValue(Task.NOTIFICATION_FLAGS));
notes.setText(model.getValue(Task.NOTES));
if(model.getValue(Task.CALENDAR_URI).length() > 0)
addToCalendar.setText(r.getString(R.string.showCalendar_label));
// tags (only configure if not already set)
if(tagsContainer.getChildCount() == 0) {
TagService tagService = new TagService(this);
TodorooCursor<Metadata> cursor = tagService.getTags(model.getId());
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
addTag(cursor.get(Metadata.VALUE));
addTag(""); //$NON-NLS-1$
}
/* // alerts
if(model.getTaskIdentifier() != null) {
List<Date> alerts = alertController.getTaskAlerts(model.getTaskIdentifier());
for(Date alert : alerts) {
addAlert(alert);
}
}
// repeats
RepeatInfo repeatInfo = model.getRepeat();
if(repeatInfo != null) {
setRepeatValue(repeatInfo.getValue());
repeatInterval.setSelection(repeatInfo.getInterval().ordinal());
} else
setRepeatValue(0);*/ // TODO
}
/** Save task model from values in UI components */
private void save() {
// don't save if user accidentally created a new task
if(title.getText().length() == 0) {
if(model.isSaved())
taskService.delete(model);
return;
}
model.setValue(Task.TITLE, title.getText().toString());
model.setValue(Task.ESTIMATED_SECONDS, estimatedDuration.getTimeDurationInSeconds());
model.setValue(Task.ELAPSED_SECONDS, elapsedDuration.getTimeDurationInSeconds());
model.setValue(Task.IMPORTANCE, importance.getImportance());
model.setValue(Task.DUE_DATE, dueDate.getMillis());
model.setValue(Task.HIDE_UNTIL, hiddenUntil.getMillis());
model.setValue(Task.NOTIFICATION_FLAGS, flags.getValue());
model.setValue(Task.NOTES, notes.getText().toString());
model.setValue(Task.NOTIFICATIONS, notification.getTimeDurationInSeconds());
model.setValue(Task.REPEAT, RepeatInfo.toSingleField(getRepeatValue()));
taskService.save(model, false);
long due = model.getValue(Task.DUE_DATE);
if (due != 0) {
showSaveToast(due);
} else {
showSaveToast();
}
}
/**
* Displays a Toast reporting that the selected task has been saved and is
* due in 'x' amount of time, to 2 time-units of precision (e.g. Days + Hours).
* @param dueDate the Date when the task is due
*/
private void showSaveToast(long dueDate) {
int stringResource;
int timeInSeconds = (int)((dueDate - System.currentTimeMillis())/1000L);
if (timeInSeconds < 0) {
timeInSeconds *= -1; // DateUtilities.getDurationString() requires positive integer
stringResource = R.string.taskEdit_onTaskSave_Overdue;
} else {
stringResource = R.string.taskEdit_onTaskSave_Due;
}
String formattedDate = dateUtilities.getDurationString(timeInSeconds, 2);
Toast.makeText(this,
getResources().getString(stringResource, formattedDate),
Toast.LENGTH_SHORT).show();
}
/**
* Displays a Toast reporting that the selected task has been saved.
* Use this version when no due Date has been set.
*/
private void showSaveToast() {
Toast.makeText(this, R.string.taskEdit_onTaskSave_notDue, Toast.LENGTH_SHORT).show();
}
/** Save task tags. Must be called after task already has an ID */
private void saveTags() {
Set<TagIdentifier> tagsToDelete;
Set<TagIdentifier> tagsToAdd;
HashSet<String> tagNames = new HashSet<String>();
for(int i = 0; i < tagsContainer.getChildCount(); i++) {
TextView tagName = (TextView)tagsContainer.getChildAt(i).findViewById(R.id.text1);
if(tagName.getText().length() == 0)
continue;
tagNames.add(tagName.getText().toString());
}
// map names to tag identifiers, creating them if necessary
/*HashSet<TagIdentifier> tagIds = new HashSet<TagIdentifier>();
HashMap<String, TagIdentifier> tagsByName = new HashMap<String, TagIdentifier>();
for(TagModelForView tag : tags)
tagsByName.put(tag.getName(), tag.getTagIdentifier());
for(String tagName : tagNames) {
if(tagsByName.containsKey(tagName))
tagIds.add(tagsByName.get(tagName));
else {
TagIdentifier newTagId = tagController.createTag(tagName);
tagIds.add(newTagId);
}
}
// intersect tags to figure out which we need to add / remove
tagsToDelete = new HashSet<TagIdentifier>(taskTags);
tagsToDelete.removeAll(tagIds);
tagsToAdd = tagIds;
tagsToAdd.removeAll(taskTags);
// perform the database updates
for(TagIdentifier tagId : tagsToDelete)
tagController.removeTag(model.getTaskIdentifier(), tagId);
for(TagIdentifier tagId : tagsToAdd)
tagController.addTag(model.getTaskIdentifier(), tagId);
if(tagsToDelete.size() > 0 || tagsToAdd.size() > 0)
SyncDataController.taskUpdated(this, model);*/
}
/** Helper method to save alerts for this task */
private void saveAlerts() {
/*alertController.removeAlerts(model.getTaskIdentifier());
for(int i = 0; i < alertsContainer.getChildCount(); i++) {
DateControlSet dateControlSet = (DateControlSet)alertsContainer.
getChildAt(i).getTag();
Date date = dateControlSet.getDate();
alertController.addAlert(model.getTaskIdentifier(), date);
}*/
}
/** Adds a tag to the tag field */
boolean addTag(String tagName) {
if (tagsContainer.getChildCount() >= MAX_TAGS) {
return false;
}
LayoutInflater inflater = getLayoutInflater();
final View tagItem = inflater.inflate(R.layout.edit_tag_item, null);
tagsContainer.addView(tagItem);
AutoCompleteTextView textView = (AutoCompleteTextView)tagItem.
findViewById(R.id.text1);
textView.setText(tagName);
ArrayAdapter<Tag> tagsAdapter =
new ArrayAdapter<Tag>(this,
android.R.layout.simple_dropdown_item_1line, tags);
textView.setAdapter(tagsAdapter);
textView.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before,
int count) {
if(start == 0 && tagsContainer.getChildAt(
tagsContainer.getChildCount()-1) == tagItem) {
addTag(""); //$NON-NLS-1$
}
}
public void afterTextChanged(Editable s) {
//
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
//
}
});
ImageButton reminderRemoveButton;
reminderRemoveButton = (ImageButton)tagItem.findViewById(R.id.button1);
reminderRemoveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
tagsContainer.removeView(tagItem);
}
});
return true;
}
/* ======================================================================
* ======================================================= event handlers
* ====================================================================== */
protected void saveButtonClick() {
setResult(RESULT_OK);
finish();
}
protected void discardButtonClick() {
shouldSaveState = false;
setResult(Constants.RESULT_DISCARD);
finish();
}
protected 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() {
public void onClick(DialogInterface dialog, int which) {
taskService.delete(model);
shouldSaveState = false;
setResult(Constants.RESULT_GO_HOME);
finish();
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
protected void repeatValueClick() {
final int tagValue = (Integer)repeatValue.getTag();
if(tagValue > 0)
repeatHelpShown = true;
final Runnable openDialogRunnable = new Runnable() {
public void run() {
repeatHelpShown = true;
int dialogValue = tagValue;
if(dialogValue == 0)
dialogValue = 1;
new NumberPickerDialog(TaskEditActivity.this, new OnNumberPickedListener() {
public void onNumberPicked(NumberPicker view, int number) {
setRepeatValue(number);
}
}, getResources().getString(R.string.repeat_picker_title),
dialogValue, 1, 0, 31).show();
}
};
if(repeatHelpShown || !Preferences.shouldShowRepeatHelp(this)) {
openDialogRunnable.run();
return;
}
new AlertDialog.Builder(this)
.setTitle(R.string.repeat_help_dialog_title)
.setMessage(R.string.repeat_help_dialog)
.setIcon(android.R.drawable.ic_dialog_info)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
openDialogRunnable.run();
}
})
.setNeutralButton(R.string.repeat_help_hide,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Preferences.setShowRepeatHelp(TaskEditActivity.this, false);
openDialogRunnable.run();
}
})
.show();
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch(item.getItemId()) {
case MENU_SAVE_ID:
saveButtonClick();
return true;
case MENU_DISCARD_ID:
discardButtonClick();
return true;
case MENU_DELETE_ID:
deleteButtonClick();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem item;
item = menu.add(Menu.NONE, MENU_SAVE_ID, 0, R.string.save_label);
item.setIcon(android.R.drawable.ic_menu_save);
item.setAlphabeticShortcut('s');
item = menu.add(Menu.NONE, MENU_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, MENU_DELETE_ID, 0, R.string.delete_label);
item.setIcon(android.R.drawable.ic_menu_delete);
item.setAlphabeticShortcut('d');
return true;
}
/** Take the values from the model and set the calendar start and end times
* based on these. Sets keys 'dtstart' and 'dtend'.
*
* @param preferred preferred due date or null
* @param definite definite due date or null
* @param estimatedSeconds estimated duration or null
* @param values
*/
public static void createCalendarStartEndTimes(Date preferred, Date definite,
Integer estimatedSeconds, ContentValues values) {
FlurryAgent.onEvent("create-calendar-event");
Long deadlineDate = null;
if (preferred != null && preferred.after(new Date()))
deadlineDate = preferred.getTime();
else if (definite != null)
deadlineDate = definite.getTime();
else
deadlineDate = System.currentTimeMillis() + 24*3600*1000L;
int estimatedTime = DEFAULT_CAL_TIME;
if(estimatedSeconds != null && estimatedSeconds > 0) {
estimatedTime = estimatedSeconds;
}
values.put("dtstart", deadlineDate - estimatedTime * 1000L);
values.put("dtend", deadlineDate);
}
@Override
protected void onPause() {
// create calendar event
/*if(addToCalendar.isChecked() && model.getCalendarUri() == null) {
Uri uri = Uri.parse("content://calendar/events");
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put("title", title.getText().toString());
values.put("calendar_id", Preferences.getDefaultCalendarIDSafe(this));
values.put("description", notes.getText().toString());
values.put("hasAlarm", 0);
values.put("transparency", 0);
values.put("visibility", 0);
createCalendarStartEndTimes(model.getPreferredDueDate(),
model.getDefiniteDueDate(), model.getEstimatedSeconds(),
values);
Uri result = null;
try{
result = cr.insert(uri, values);
model.setCalendarUri(result.toString());
} catch (IllegalArgumentException e) {
Log.e("astrid", "Error creating calendar event!", e);
}
}
if(shouldSaveState)
save();
if(addToCalendar.isChecked() && model.getCalendarUri() != null) {
Uri result = Uri.parse(model.getCalendarUri());
Intent intent = new Intent(Intent.ACTION_EDIT, result);
ContentValues values = new ContentValues();
createCalendarStartEndTimes(model.getPreferredDueDate(),
model.getDefiniteDueDate(), model.getEstimatedSeconds(),
values);
intent.putExtra("beginTime", values.getAsLong("dtstart"));
intent.putExtra("endTime", values.getAsLong("dtend"));
startActivity(intent);
}*/
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
// populateFields();
}
/* ======================================================================
* ========================================== UI component helper classes
* ====================================================================== */
/** Control set dealing with notification flags */
public class NotifyFlagControlSet {
private final CheckBox before, during, after, nonstop;
public NotifyFlagControlSet(int beforeId, int duringId,
int afterId, int nonstopId) {
before = (CheckBox)findViewById(beforeId);
during = (CheckBox)findViewById(duringId);
after = (CheckBox)findViewById(afterId);
nonstop = (CheckBox)findViewById(nonstopId);
}
public void setValue(int flags) {
before.setChecked((flags &
TaskModelForEdit.NOTIFY_BEFORE_DEADLINE) > 0);
during.setChecked((flags &
TaskModelForEdit.NOTIFY_AT_DEADLINE) > 0);
after.setChecked((flags &
TaskModelForEdit.NOTIFY_AFTER_DEADLINE) > 0);
nonstop.setChecked((flags &
TaskModelForEdit.NOTIFY_NONSTOP) > 0);
}
public int getValue() {
int value = 0;
if(before.isChecked())
value |= TaskModelForEdit.NOTIFY_BEFORE_DEADLINE;
if(during.isChecked())
value |= TaskModelForEdit.NOTIFY_AT_DEADLINE;
if(after.isChecked())
value |= TaskModelForEdit.NOTIFY_AFTER_DEADLINE;
if(nonstop.isChecked())
value |= TaskModelForEdit.NOTIFY_NONSTOP;
return value;
}
}
/** Control set dealing with importance */
public class ImportanceControlSet {
private final List<CompoundButton> buttons = new LinkedList<CompoundButton>();
private final int[] colors = Task.getImportanceColors(getResources());
public ImportanceControlSet(int containerId) {
LinearLayout layout = (LinearLayout)findViewById(containerId);
for(int i = Task.IMPORTANCE_MOST; i <= Task.IMPORTANCE_LEAST; i++) {
final ToggleButton button = new ToggleButton(TaskEditActivity.this);
button.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 1));
StringBuilder label = new StringBuilder();
for(int j = Task.IMPORTANCE_LEAST; j >= 0; j--)
label.append('!');
button.setTextColor(colors[i]);
button.setTextOff(label);
button.setTextOn(label);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
setImportance((Integer)button.getTag());
}
});
button.setTag(i);
buttons.add(button);
layout.addView(button);
}
}
public void setImportance(Integer i) {
for(CompoundButton b : buttons) {
if(b.getTag() == i) {
b.setTextSize(24);
b.setChecked(true);
} else {
b.setTextSize(16);
b.setChecked(false);
}
}
}
public int getImportance() {
for(CompoundButton b : buttons)
if(b.isChecked())
return (Integer) b.getTag();
return Task.getStaticDefaultValues().getAsInteger(Task.IMPORTANCE.name);
}
}
}

@ -1,10 +1,12 @@
package com.todoroo.astrid.activity;
import java.util.List;
import java.util.Map.Entry;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -32,7 +34,6 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
import com.timsu.astrid.activities.EditPreferences;
import com.timsu.astrid.activities.TaskEdit;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
@ -47,8 +48,10 @@ import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.TaskDetail;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.filters.CoreFilterExposer;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Constants;
@ -91,6 +94,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
@Autowired
protected TaskService taskService;
@Autowired
protected MetadataService metadataService;
@Autowired
protected DialogUtilities dialogUtilities;
@ -131,6 +137,9 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
filter = CoreFilterExposer.buildInboxFilter(getResources());
}
if(database == null)
return;
database.openForWriting();
setUpUiComponents();
setUpTaskList();
@ -205,17 +214,26 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
((ImageButton)findViewById(R.id.quickAddButton)).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
TextView quickAdd = (TextView)findViewById(R.id.quickAddText);
Task task = quickAddTask(quickAdd.getText().toString());
if(quickAdd.getText().length() > 0) {
Task task = quickAddTask(quickAdd.getText().toString());
quickAdd.setText(""); //$NON-NLS-1$
loadTaskListContent(true);
} else {
Intent intent = new Intent(TaskListActivity.this, TaskEdit.class);
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, task.getId());
Intent intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
}
}
});
((ImageButton)findViewById(R.id.extendedAddButton)).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
TextView quickAdd = (TextView)findViewById(R.id.quickAddText);
Task task = quickAddTask(quickAdd.getText().toString());
Intent intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
intent.putExtra(TaskEditActivity.ID_TOKEN, task.getId());
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
}
});
}
/**
@ -228,11 +246,30 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
try {
Task task = new Task();
task.setValue(Task.TITLE, title);
/*task.setValue(Task.DUE_DATE, Task.initializeDueDate(
task.getValue(Task.URGENCY)));
ContentValues forMetadata = null;
if(filter.valuesForNewTasks != null && filter.valuesForNewTasks.size() > 0) {
ContentValues forTask = new ContentValues();
forMetadata = new ContentValues();
for(Entry<String, Object> item : filter.valuesForNewTasks.valueSet()) {
if(item.getKey().startsWith(Task.TABLE.name))
AndroidUtilities.putInto(forTask, item.getKey(), item.getValue());
else
AndroidUtilities.putInto(forMetadata, item.getKey(), item.getValue());
}
task.mergeWith(forTask);
}
taskService.save(task, false);
if(filter.sqlForNewTasks != null)
taskService.invokeSqlForNewTask(filter, task); */ // TODO
if(forMetadata != null && forMetadata.size() > 0) {
Metadata metadata = new Metadata();
for(Entry<String, Object> item : forMetadata.valueSet()) {
metadata.setValue(Metadata.TASK, task.getId());
metadata.setValue(Metadata.KEY, item.getKey());
metadata.setValue(Metadata.VALUE, item.toString());
metadataService.save(metadata);
metadata.clear();
}
}
return task;
} catch (Exception e) {
exceptionService.displayAndReportError(this, "quick-add-task", e);
@ -417,7 +454,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
}
/** Show a dialog box and delete the task specified */
private void deleteTask(final long id) {
private void deleteTask(final Task task) {
new AlertDialog.Builder(this).setTitle(R.string.DLG_confirm_title)
.setMessage(R.string.DLG_delete_this_task_question).setIcon(
android.R.drawable.ic_dialog_alert).setPositiveButton(
@ -425,7 +462,7 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
taskService.delete(id);
taskService.delete(task);
loadTaskListContent(true);
}
}).setNegativeButton(android.R.string.cancel, null)
@ -440,8 +477,8 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
// handle my own menus
switch (item.getItemId()) {
case MENU_ADD_TASK_ID:
intent = new Intent(TaskListActivity.this, TaskEdit.class);
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, Task.NO_ID);
intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
intent.putExtra(TaskEditActivity.ID_TOKEN, Task.NO_ID);
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
return true;
case MENU_PLUGINS_ID:
@ -469,15 +506,17 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
case CONTEXT_MENU_EDIT_TASK_ID: {
itemId = item.getGroupId();
intent = new Intent(TaskListActivity.this, TaskEdit.class);
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, itemId);
intent = new Intent(TaskListActivity.this, TaskEditActivity.class);
intent.putExtra(TaskEditActivity.ID_TOKEN, itemId);
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
return true;
}
case CONTEXT_MENU_DELETE_TASK_ID:
itemId = item.getGroupId();
deleteTask(itemId);
Task task = new Task();
task.setId(itemId);
deleteTask(task);
return true;
}

@ -7,9 +7,9 @@ package com.todoroo.astrid.model;
import android.content.ContentValues;
import android.content.res.Resources;
import com.timsu.astrid.data.enums.RepeatInterval;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
@ -135,6 +135,21 @@ public final class Task extends AbstractModel {
public static final int IMPORTANCE_SHOULD_DO = 2;
public static final int IMPORTANCE_NONE = 3;
/**
* Get colors that correspond to importance values
*/
public static int[] getImportanceColors(Resources r) {
return new int[] {
r.getColor(R.color.importance_1),
r.getColor(R.color.importance_2),
r.getColor(R.color.importance_3),
r.getColor(R.color.importance_4),
};
}
public static final int IMPORTANCE_MOST = IMPORTANCE_DO_OR_DIE;
public static final int IMPORTANCE_LEAST = IMPORTANCE_NONE;
// --- defaults
/** Default values container */
@ -148,6 +163,16 @@ public final class Task extends AbstractModel {
defaultValues.put(DELETION_DATE.name, 0);
defaultValues.put(URGENCY.name, URGENCY_NONE);
defaultValues.put(IMPORTANCE.name, IMPORTANCE_NONE);
defaultValues.put(CALENDAR_URI.name, "");
defaultValues.put(REPEAT.name, 0);
defaultValues.put(NOTIFICATIONS.name, 0);
defaultValues.put(NOTIFICATION_FLAGS.name, 0);
defaultValues.put(ESTIMATED_SECONDS.name, 0);
defaultValues.put(ELAPSED_SECONDS.name, 0);
defaultValues.put(POSTPONE_COUNT.name, 0);
defaultValues.put(NOTES.name, "");
defaultValues.put(TIMER_START.name, 0);
}
private static boolean defaultValuesLoaded = false;
@ -232,23 +257,4 @@ public final class Task extends AbstractModel {
return getValue(DUE_DATE) > 0;
}
// --- data access methods for migration properties
/** Number of bits to shift repeat value by */
public static final int REPEAT_VALUE_OFFSET = 3;
/**
* @return RepeatInfo corresponding to
*/
public RepeatInfo getRepeatInfo() {
int repeat = getValue(REPEAT);
if(repeat == 0)
return null;
int value = repeat >> REPEAT_VALUE_OFFSET;
RepeatInterval interval = RepeatInterval.values()
[repeat - (value << REPEAT_VALUE_OFFSET)];
return new RepeatInfo(interval, value);
}
}

@ -16,6 +16,9 @@ public class FlurryReporter implements ErrorReporter {
@SuppressWarnings("nls")
public void handleError(String name, Throwable error) {
if(error == null)
return;
String message = error.toString();
StringWriter writer = new StringWriter();

@ -82,4 +82,12 @@ public class MetadataService {
public void deleteWhere(Criterion where) {
metadataDao.deleteWhere(where);
}
/**
* Save a single piece of metadata
* @param metadata
*/
public void save(Metadata metadata) {
metadataDao.saveItem(metadata);
}
}

@ -39,7 +39,7 @@ public class TaskService {
}
/**
* Mark the given action item as completed and save it.
* Mark the given task as completed and save it.
*
* @param item
*/
@ -65,12 +65,20 @@ public class TaskService {
}
/**
* Delete the given action item
* Delete the given task. If this task had a title, instead of deleting
* from the database, we set the deleted flag.
*
* @param model
*/
public void delete(long itemId) {
taskDao.delete(itemId);
public void delete(Task item) {
if(!item.isSaved())
return;
if(item.getValue(Task.TITLE).length() == 0)
taskDao.delete(item.getId());
else {
item.setValue(Task.DELETION_DATE, DateUtilities.now());
taskDao.save(item, false);
}
}
/**

Loading…
Cancel
Save