diff --git a/api/src/com/todoroo/andlib/sql/Functions.java b/api/src/com/todoroo/andlib/sql/Functions.java index 9770fcfdc..7a9ace07f 100644 --- a/api/src/com/todoroo/andlib/sql/Functions.java +++ b/api/src/com/todoroo/andlib/sql/Functions.java @@ -1,6 +1,7 @@ package com.todoroo.andlib.sql; import com.todoroo.andlib.data.Property.IntegerProperty; +import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.StringProperty; @@ -34,6 +35,10 @@ public final class Functions { return new Field("(strftime('%s','now')*1000 + " + millis + ")"); } + public static Field strftime(LongProperty field, String format) { + return new Field("(strftime('" + format + "', datetime(" + field.toString() + "/1000, 'unixepoch', 'localtime')))"); + } + public static Field cast(Field field, String newType) { return new Field("CAST(" + field.toString() + " AS " + newType + ")"); @@ -55,4 +60,5 @@ public final class Functions { return new Field(field.toString() + " & " + value); } + } diff --git a/api/src/com/todoroo/astrid/data/Task.java b/api/src/com/todoroo/astrid/data/Task.java index 777a3eafc..a677bd757 100644 --- a/api/src/com/todoroo/astrid/data/Task.java +++ b/api/src/com/todoroo/astrid/data/Task.java @@ -387,11 +387,11 @@ public final class Task extends RemoteModel { Date dueDate = new Date(date / 1000L * 1000L); // get rid of millis if(setting != URGENCY_SPECIFIC_DAY_TIME) { - dueDate.setHours(23); - dueDate.setMinutes(59); - dueDate.setSeconds(59); - } else if(isEndOfDay(dueDate)) { - dueDate.setSeconds(58); + dueDate.setHours(12); + dueDate.setMinutes(0); + dueDate.setSeconds(0); // Seconds == 0 means no due time + } else { + dueDate.setSeconds(1); // Seconds > 0 means due time exists } return dueDate.getTime(); } @@ -436,20 +436,12 @@ public final class Task extends RemoteModel { hideUntil.setHours(0); hideUntil.setMinutes(0); hideUntil.setSeconds(0); + } else { + hideUntil.setSeconds(1); } return hideUntil.getTime(); } - /** - * @return true if hours, minutes, and seconds indicate end of day - */ - private static boolean isEndOfDay(Date date) { - int hours = date.getHours(); - int minutes = date.getMinutes(); - int seconds = date.getSeconds(); - return hours == 23 && minutes == 59 && seconds == 59; - } - /** * Checks whether this due date has a due time or only a date */ @@ -463,7 +455,7 @@ public final class Task extends RemoteModel { * Checks whether provided due date has a due time or only a date */ public static boolean hasDueTime(long dueDate) { - return dueDate > 0 && !isEndOfDay(new Date(dueDate)); + return dueDate > 0 && (dueDate % 60000 > 0); } } diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index b7c59eba0..b063b245f 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionName="4.0.6" + android:versionCode="262"> diff --git a/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java new file mode 100644 index 000000000..df1d694e1 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java @@ -0,0 +1,83 @@ +package com.todoroo.astrid.helper; + +import java.util.Date; + +import android.content.Context; + +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.sql.Functions; +import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.dao.TaskDao; +import com.todoroo.astrid.data.Task; + +public class DueDateTimeMigrator { + + @Autowired TaskDao taskDao; + + private static final String PREF_MIGRATED_DUE_TIMES = "migrated_due_times"; //$NON-NLS-1$ + private static final String STRFTIME_FORMAT = "%H:%M%S"; //$NON-NLS-1$ + private static final String LEGACY_NO_TIME_STRING = "23:59:59"; //$NON-NLS-1$ + + public DueDateTimeMigrator() { + DependencyInjectionService.getInstance().inject(this); + } + + private interface TaskDateAdjuster { + public void adjust(Date date); + } + + public void migrateDueTimes(Context c) { + if (!Preferences.getBoolean(PREF_MIGRATED_DUE_TIMES, false)) { + // Get tasks with due time (i.e. due date != 23:59:59) + TodorooCursor tasksWithDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( + Criterion.and(Task.DUE_DATE.gt(0), + Criterion.not(Functions.strftime(Task.DUE_DATE, STRFTIME_FORMAT).eq(LEGACY_NO_TIME_STRING))))); + + // Get tasks with no due time (i.e. due date = 23:59:59) + TodorooCursor tasksWithoutDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( + Criterion.and(Task.DUE_DATE.gt(0), + Functions.strftime(Task.DUE_DATE, STRFTIME_FORMAT).eq(LEGACY_NO_TIME_STRING)))); + + try { + // Set tasks with time to have time HH:MM:01 + processCursor(tasksWithDueTime, new TaskDateAdjuster() { + @Override + public void adjust(Date date) { + date.setSeconds(1); + } + }); + + // Set tasks without time to 12:00:00 + processCursor(tasksWithoutDueTime, new TaskDateAdjuster() { + @Override + public void adjust(Date date) { + date.setHours(12); + date.setMinutes(0); + date.setSeconds(0); + } + }); + } finally { + tasksWithDueTime.close(); + tasksWithoutDueTime.close(); + } + Preferences.setBoolean(PREF_MIGRATED_DUE_TIMES, true); + } + } + + private void processCursor(TodorooCursor cursor, TaskDateAdjuster adjuster) { + Task curr = new Task(); + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + curr.readFromCursor(cursor); + long time = curr.getValue(Task.DUE_DATE) / 1000L * 1000L; + Date date = new Date(time); + adjuster.adjust(date); + curr.setValue(Task.DUE_DATE, date.getTime()); + taskDao.save(curr); + } + } + +} diff --git a/astrid/src/com/todoroo/astrid/service/UpgradeService.java b/astrid/src/com/todoroo/astrid/service/UpgradeService.java index 4c0423a04..f27c8f56a 100644 --- a/astrid/src/com/todoroo/astrid/service/UpgradeService.java +++ b/astrid/src/com/todoroo/astrid/service/UpgradeService.java @@ -9,6 +9,7 @@ import org.weloveastrid.rmilk.data.MilkNoteHelper; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -26,11 +27,13 @@ import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.activity.Eula; +import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.core.SortHelper; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.gtasks.GtasksPreferenceService; +import com.todoroo.astrid.helper.DueDateTimeMigrator; import com.todoroo.astrid.notes.NoteMetadata; import com.todoroo.astrid.producteev.sync.ProducteevDataService; import com.todoroo.astrid.service.abtesting.ABChooser; @@ -40,6 +43,7 @@ import com.todoroo.astrid.utility.AstridPreferences; public final class UpgradeService { + public static final int V4_0_6 = 262; public static final int V4_0_5_1 = 261; public static final int V4_0_5 = 260; public static final int V4_0_4_3 = 259; @@ -135,7 +139,7 @@ public final class UpgradeService { // long running tasks: pop up a progress dialog final ProgressDialog dialog; - if(from < V3_0_0 && context instanceof Activity) + if(from < V4_0_6 && context instanceof Activity) dialog = DialogUtilities.progressDialog(context, context.getString(R.string.DLG_upgrading)); else @@ -158,8 +162,13 @@ public final class UpgradeService { if(from < V3_8_4 && Preferences.getBoolean(R.string.p_showNotes, false)) taskService.clearDetails(Task.NOTES.neq("")); //$NON-NLS-1$ + + if (from < V4_0_6) + new DueDateTimeMigrator().migrateDueTimes(context); + } finally { DialogUtilities.dismissDialog((Activity)context, dialog); + context.sendBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH)); } } @@ -185,6 +194,10 @@ public final class UpgradeService { Preferences.clear(AstridPreferences.P_UPGRADE_FROM); StringBuilder changeLog = new StringBuilder(); + newVersionString(changeLog, "4.0.6 (3/29/12)", new String[] { + "Fixed a bug that could put duetimes on tasks when changing timezones" + }); + if (from >= V4_0_5 && from < V4_0_5_1) { newVersionString(changeLog, "4.0.5.1 (3/23/12)", new String[] { "Fixed a bug that would prevent widgets from displaying on Android 2.1" diff --git a/astrid/src/com/todoroo/astrid/ui/CalendarView.java b/astrid/src/com/todoroo/astrid/ui/CalendarView.java index 190e0f0c5..e4645d5b2 100644 --- a/astrid/src/com/todoroo/astrid/ui/CalendarView.java +++ b/astrid/src/com/todoroo/astrid/ui/CalendarView.java @@ -455,9 +455,9 @@ public class CalendarView extends View { private Date getToday(Calendar calendar) { Date today = calendar.getTime(); today.setTime(today.getTime() / 1000L * 1000L); - today.setHours(23); - today.setMinutes(59); - today.setSeconds(59); + today.setHours(12); + today.setMinutes(0); + today.setSeconds(0); return today; } diff --git a/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java b/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java index 26e3999dd..fb554fdb4 100644 --- a/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java +++ b/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java @@ -87,9 +87,9 @@ public class DateAndTimePicker extends LinearLayout { private Date getDateForCalendar(Date date) { Date forCalendar = new Date(date.getTime() / 1000L * 1000L); - forCalendar.setHours(23); - forCalendar.setMinutes(59); - forCalendar.setSeconds(59); + forCalendar.setHours(12); + forCalendar.setMinutes(0); + forCalendar.setSeconds(0); return forCalendar; }