Calendar event gets updated when you change due dates / roll over a repeating task. (untested).

Also, dates are specified in absolute where appropriate
pull/14/head
Tim Su 17 years ago
parent d1f6853643
commit c6408f488c

@ -56,6 +56,7 @@
<item quantity="other">%d Tags</item> <item quantity="other">%d Tags</item>
</plurals> </plurals>
<!-- Time Constants --> <!-- Time Constants -->
<string name="dateFormatter">MMM d</string>
<string name="daysVertical">D\na\ny\ns</string> <string name="daysVertical">D\na\ny\ns</string>
<string name="hoursVertical">H\no\nu\nr\ns</string> <string name="hoursVertical">H\no\nu\nr\ns</string>
<plurals name="Ndays"> <plurals name="Ndays">
@ -96,7 +97,8 @@
<string name="addtask_label">New Task</string> <string name="addtask_label">New Task</string>
<string name="taskList_hiddenPrefix">H</string> <string name="taskList_hiddenPrefix">H</string>
<string name="taskList_dueIn">Due in</string> <string name="taskList_dueRelativeTime">Due in</string>
<string name="taskList_dueAbsoluteDate">Due on</string>
<string name="taskList_goalPrefix">Goal</string> <string name="taskList_goalPrefix">Goal</string>
<string name="taskList_overdueBy">Overdue by</string> <string name="taskList_overdueBy">Overdue by</string>
<string name="taskList_completedPrefix">Finished</string> <string name="taskList_completedPrefix">Finished</string>

@ -657,12 +657,40 @@ public class TaskEdit extends TaskModificationTabbedActivity<TaskModelForEdit> {
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
save(); save();
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
// save the tag name token for when we rotate the screen
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
if(extras != null && extras.containsKey(TAG_NAME_TOKEN)) if(extras != null && extras.containsKey(TAG_NAME_TOKEN))
outState.putString(TAG_NAME_TOKEN, outState.putString(TAG_NAME_TOKEN,
extras.getString(TAG_NAME_TOKEN)); extras.getString(TAG_NAME_TOKEN));
} }
/** 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) {
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 @Override
protected void onPause() { protected void onPause() {
// create calendar event // create calendar event
@ -678,21 +706,9 @@ public class TaskEdit extends TaskModificationTabbedActivity<TaskModelForEdit> {
values.put("transparency", 0); values.put("transparency", 0);
values.put("visibility", 0); values.put("visibility", 0);
Long deadlineDate = null; createCalendarStartEndTimes(model.getPreferredDueDate(),
if (model.getPreferredDueDate() != null) model.getDefiniteDueDate(), model.getEstimatedSeconds(),
deadlineDate = model.getPreferredDueDate().getTime(); values);
else if (model.getDefiniteDueDate() != null)
deadlineDate = model.getDefiniteDueDate().getTime();
else
deadlineDate = System.currentTimeMillis() + 24*3600*1000L;
int estimatedTime = DEFAULT_CAL_TIME;
if(model.getEstimatedSeconds() != null &&
model.getEstimatedSeconds() > 0) {
estimatedTime = model.getEstimatedSeconds();
}
values.put("dtstart", deadlineDate - estimatedTime * 1000L);
values.put("dtend", deadlineDate);
Uri result = cr.insert(uri, values); Uri result = cr.insert(uri, values);
if(result != null) if(result != null)
@ -708,22 +724,13 @@ public class TaskEdit extends TaskModificationTabbedActivity<TaskModelForEdit> {
Uri result = Uri.parse(model.getCalendarUri()); Uri result = Uri.parse(model.getCalendarUri());
Intent intent = new Intent(Intent.ACTION_EDIT, result); Intent intent = new Intent(Intent.ACTION_EDIT, result);
// recalculate dates ContentValues values = new ContentValues();
Long deadlineDate = null; createCalendarStartEndTimes(model.getPreferredDueDate(),
if (model.getPreferredDueDate() != null) model.getDefiniteDueDate(), model.getEstimatedSeconds(),
deadlineDate = model.getPreferredDueDate().getTime(); values);
else if (model.getDefiniteDueDate() != null)
deadlineDate = model.getDefiniteDueDate().getTime();
else
deadlineDate = System.currentTimeMillis() + 24*3600*1000L;
int estimatedTime = DEFAULT_CAL_TIME; intent.putExtra("beginTime", values.getAsLong("dtstart"));
if(model.getEstimatedSeconds() != null && intent.putExtra("endTime", values.getAsLong("dtend"));
model.getEstimatedSeconds() > 0) {
estimatedTime = model.getEstimatedSeconds();
}
intent.putExtra("beginTime", deadlineDate - estimatedTime * 1000L);
intent.putExtra("endTime", deadlineDate);
startActivity(intent); startActivity(intent);
} }

@ -87,6 +87,9 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
private static final String CACHE_TRUE = "y"; private static final String CACHE_TRUE = "y";
/** Number of seconds after which we display the full date deadline */
private static final int FULL_DATE_THRESHOLD = 7*24*3600;
// alarm date formatter // alarm date formatter
private static final Format alarmFormat = new SimpleDateFormat( private static final Format alarmFormat = new SimpleDateFormat(
"MM/dd hh:mm"); "MM/dd hh:mm");
@ -309,39 +312,60 @@ public class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
int secondsLeft = (int)((task.getCompletionDate().getTime() - int secondsLeft = (int)((task.getCompletionDate().getTime() -
System.currentTimeMillis()) / 1000); System.currentTimeMillis()) / 1000);
label.append(r.getString(R.string.taskList_completedPrefix)). label.append(r.getString(R.string.taskList_completedPrefix)).
append(" "). append(" ");
append(DateUtilities.getDurationString(r, Math.abs(secondsLeft), 1)). if(secondsLeft < FULL_DATE_THRESHOLD)
label.append(DateUtilities.getDurationString(r,
Math.abs(secondsLeft), 1)).
append(" " + r.getString(R.string.ago_suffix)); append(" " + r.getString(R.string.ago_suffix));
else
label.append(DateUtilities.getFormattedDate(r,
task.getCompletionDate()));
} }
} else { } else {
boolean taskOverdue = false; boolean taskOverdue = false;
if(task.getDefiniteDueDate() != null) { if(task.getDefiniteDueDate() != null) {
long timeLeft = task.getDefiniteDueDate().getTime() - long timeLeft = (task.getDefiniteDueDate().getTime() -
System.currentTimeMillis(); System.currentTimeMillis())/1000;
if(timeLeft > 0) { if(timeLeft > 0) {
label.append(r.getString(R.string.taskList_dueIn)).append(" "); if(timeLeft < FULL_DATE_THRESHOLD)
label.append(r.getString(R.string.taskList_dueRelativeTime)).append(" ");
else
label.append(r.getString(R.string.taskList_dueAbsoluteDate)).append(" ");
} else { } else {
taskOverdue = true; taskOverdue = true;
label.append(r.getString(R.string.taskList_overdueBy)).append(" "); label.append(r.getString(R.string.taskList_overdueBy)).append(" ");
task.putCachedLabel(KEY_OVERDUE, CACHE_TRUE); task.putCachedLabel(KEY_OVERDUE, CACHE_TRUE);
} }
if(timeLeft < FULL_DATE_THRESHOLD)
label.append(DateUtilities.getDurationString(r, label.append(DateUtilities.getDurationString(r,
(int)Math.abs(timeLeft/1000), 1)); (int)Math.abs(timeLeft/1000), 1));
else
label.append(DateUtilities.getFormattedDate(r,
task.getDefiniteDueDate()));
} }
if(!taskOverdue && task.getPreferredDueDate() != null) { if(!taskOverdue && task.getPreferredDueDate() != null) {
if(task.getDefiniteDueDate() != null) if(task.getDefiniteDueDate() != null)
label.append(" / "); label.append(" / ");
long timeLeft = task.getPreferredDueDate().getTime() - long timeLeft = (task.getPreferredDueDate().getTime() -
System.currentTimeMillis(); System.currentTimeMillis())/1000;
label.append(r.getString(R.string.taskList_goalPrefix)).append(" "); label.append(r.getString(R.string.taskList_goalPrefix)).append(" ");
if(timeLeft > 0) { if(timeLeft > 0) {
label.append(r.getString(R.string.taskList_dueIn)).append(" "); if(timeLeft < FULL_DATE_THRESHOLD)
label.append(r.getString(R.string.taskList_dueRelativeTime)).append(" ");
else
label.append(r.getString(R.string.taskList_dueAbsoluteDate)).append(" ");
} else { } else {
label.append(r.getString(R.string.taskList_overdueBy)).append(" "); label.append(r.getString(R.string.taskList_overdueBy)).append(" ");
task.putCachedLabel(KEY_OVERDUE, CACHE_TRUE); task.putCachedLabel(KEY_OVERDUE, CACHE_TRUE);
} }
if(timeLeft < FULL_DATE_THRESHOLD)
label.append(DateUtilities.getDurationString(r, label.append(DateUtilities.getDurationString(r,
(int)Math.abs(timeLeft/1000), 1)).append(" "); (int)Math.abs(timeLeft/1000), 1));
else
label.append(DateUtilities.getFormattedDate(r,
task.getPreferredDueDate()));
} }
} }
cachedResult = label.toString(); cachedResult = label.toString();

@ -63,11 +63,11 @@ public abstract class AbstractTagModel extends AbstractModel {
static { static {
defaultValues.put(NAME, ""); defaultValues.put(NAME, "");
defaultValues.put(NOTES, ""); defaultValues.put(NOTES, "");
defaultValues.put(ICON, (Integer)null); defaultValues.put(ICON, 0);
defaultValues.put(PARENT, (Long)null); defaultValues.put(PARENT, 0);
defaultValues.put(FLAGS, (Integer)0); defaultValues.put(FLAGS, 0);
defaultValues.put(LOCATION_LAT, (Integer)null); defaultValues.put(LOCATION_LAT, 0);
defaultValues.put(LOCATION_LONG, (Integer)null); defaultValues.put(LOCATION_LONG, 0);
defaultValues.put(NOTIFICATIONS, 0); defaultValues.put(NOTIFICATIONS, 0);
} }
@ -92,11 +92,11 @@ public abstract class AbstractTagModel extends AbstractModel {
String sql = new StringBuilder(). String sql = new StringBuilder().
append("CREATE TABLE ").append(tableName).append(" ("). append("CREATE TABLE ").append(tableName).append(" (").
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, "). append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
append(NAME).append(" text unique not null,"). append(NAME).append(" text unique,").
append(NOTES).append(" text not null,"). append(NOTES).append(" text,").
append(ICON).append(" integer,"). append(ICON).append(" integer,").
append(PARENT).append(" integer,"). append(PARENT).append(" integer,").
append(FLAGS).append(" integer not null,"). append(FLAGS).append(" integer,").
append(LOCATION_LAT).append(" integer,"). append(LOCATION_LAT).append(" integer,").
append(LOCATION_LONG).append(" integer,"). append(LOCATION_LONG).append(" integer,").
append(NOTIFICATIONS).append(" integer,"). append(NOTIFICATIONS).append(" integer,").

@ -35,6 +35,7 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri; import android.net.Uri;
import android.util.Log; import android.util.Log;
import com.timsu.astrid.activities.TaskEdit;
import com.timsu.astrid.data.AbstractController; import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.sync.SyncDataController; import com.timsu.astrid.data.sync.SyncDataController;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo; import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
@ -204,7 +205,7 @@ public class TaskController extends AbstractController {
if(taskId == null) if(taskId == null)
throw new UnsupportedOperationException("Cannot delete uncreated task!"); throw new UnsupportedOperationException("Cannot delete uncreated task!");
long id = taskId.getId(); long id = taskId.getId();
cleanupTask(taskId); cleanupTask(taskId, false);
return database.delete(TASK_TABLE_NAME, KEY_ROWID + "=" + id, null) > 0; return database.delete(TASK_TABLE_NAME, KEY_ROWID + "=" + id, null) > 0;
} }
@ -255,7 +256,7 @@ public class TaskController extends AbstractController {
onTaskSetCompleted(task, values); onTaskSetCompleted(task, values);
} }
// task timer was updated // task timer was updated, update notification bar
if(values.containsKey(AbstractTaskModel.TIMER_START)) { if(values.containsKey(AbstractTaskModel.TIMER_START)) {
// show notification bar if timer was started // show notification bar if timer was started
if(values.get(AbstractTaskModel.TIMER_START) != null) { if(values.get(AbstractTaskModel.TIMER_START) != null) {
@ -265,6 +266,41 @@ public class TaskController extends AbstractController {
Notifications.clearAllNotifications(context, task.getTaskIdentifier()); Notifications.clearAllNotifications(context, task.getTaskIdentifier());
} }
} }
// due date was updated, update calendar event
if(values.containsKey(AbstractTaskModel.DEFINITE_DUE_DATE) ||
values.containsKey(AbstractTaskModel.PREFERRED_DUE_DATE)) {
try {
Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(),
new String[] { AbstractTaskModel.CALENDAR_URI });
cursor.moveToFirst();
String uriAsString = cursor.getString(0);
cursor.close();
if(uriAsString != null && uriAsString.length() > 0) {
ContentResolver cr = context.getContentResolver();
Uri uri = Uri.parse(uriAsString);
Integer estimated = null;
if(values.containsKey(AbstractTaskModel.ESTIMATED_SECONDS))
estimated = values.getAsInteger(AbstractTaskModel.ESTIMATED_SECONDS);
else { // read from event
Cursor event = cr.query(uri, new String[] {"dtstart", "dtend"},
null, null, null);
event.moveToFirst();
estimated = (event.getInt(1) - event.getInt(0))/1000;
}
// create new start and end date for this event
ContentValues newValues = new ContentValues();
TaskEdit.createCalendarStartEndTimes(task.getPreferredDueDate(),
task.getDefiniteDueDate(), estimated, newValues);
cr.update(uri, newValues, null, null);
}
} catch (Exception e) {
// ignore calendar event - event could be deleted or whatever
Log.e("astrid", "Error moving calendar event", e);
}
}
} }
@ -286,15 +322,16 @@ public class TaskController extends AbstractController {
repeatModel.repeatTaskBy(context, this, repeatInfo); repeatModel.repeatTaskBy(context, this, repeatInfo);
cursor.close(); cursor.close();
cleanupTask(task.getTaskIdentifier()); cleanupTask(task.getTaskIdentifier(), repeatInfo != null);
} }
/** Clean up state from a task. Called when deleting or completing it */ /** Clean up state from a task. Called when deleting or completing it */
private void cleanupTask(TaskIdentifier taskId) { private void cleanupTask(TaskIdentifier taskId, boolean isRepeating) {
// delete notifications & alarms // delete notifications & alarms
Notifications.deleteAlarm(context, null, taskId.getId()); Notifications.deleteAlarm(context, null, taskId.getId());
// delete calendar event // delete calendar event if not repeating
if(!isRepeating) {
try { try {
Cursor cursor = fetchTaskCursor(taskId, new String[] { Cursor cursor = fetchTaskCursor(taskId, new String[] {
AbstractTaskModel.CALENDAR_URI }); AbstractTaskModel.CALENDAR_URI });
@ -313,6 +350,7 @@ public class TaskController extends AbstractController {
Log.e("astrid", "Error deleting calendar event", e); Log.e("astrid", "Error deleting calendar event", e);
} }
} }
}
/** Set last notification date */ /** Set last notification date */
public boolean setLastNotificationTime(TaskIdentifier taskId, Date date) { public boolean setLastNotificationTime(TaskIdentifier taskId, Date date) {

@ -19,12 +19,22 @@
*/ */
package com.timsu.astrid.utilities; package com.timsu.astrid.utilities;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.res.Resources; import android.content.res.Resources;
import com.timsu.astrid.R; import com.timsu.astrid.R;
public class DateUtilities { public class DateUtilities {
/** Format a time into a medium length absolute format */
public static String getFormattedDate(Resources r, Date date) {
SimpleDateFormat format = new SimpleDateFormat(r.getString(R.string.dateFormatter));
return format.format(date);
}
/** /**
* Format a time into the format: 5 days, 3 hours, 2 minutes * Format a time into the format: 5 days, 3 hours, 2 minutes
* *

Loading…
Cancel
Save