diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index 983e0cf75..6ee64e42b 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -213,6 +213,12 @@ + + + + + + diff --git a/astrid/astrid.launch b/astrid/astrid.launch index 2ac1bca93..cb6cda0f4 100644 --- a/astrid/astrid.launch +++ b/astrid/astrid.launch @@ -6,7 +6,7 @@ - + diff --git a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java index c3a0a7d84..797291d0d 100644 --- a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java @@ -11,13 +11,13 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; import android.widget.Spinner; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.CompoundButton.OnCheckedChangeListener; import com.google.ical.values.Frequency; import com.google.ical.values.RRule; @@ -159,6 +159,8 @@ public class RepeatControlSet implements TaskEditControlSet { @Override public void readFromTask(Task task) { String recurrence = task.getValue(Task.RECURRENCE); + if(recurrence == null) + recurrence = ""; //$NON-NLS-1$ // read recurrence rule if(recurrence.length() > 0) { diff --git a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatDetailExposer.java b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatDetailExposer.java new file mode 100644 index 000000000..2121bcebc --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatDetailExposer.java @@ -0,0 +1,118 @@ +/** + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.repeats; + +import java.text.DateFormatSymbols; +import java.text.ParseException; +import java.util.List; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; + +import com.google.ical.values.Frequency; +import com.google.ical.values.RRule; +import com.google.ical.values.WeekdayNum; +import com.timsu.astrid.R; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.api.TaskDetail; +import com.todoroo.astrid.model.Task; +import com.todoroo.astrid.service.TaskService; + +/** + * Exposes {@link TaskDetail} for tags, i.e. "Tags: frogs, animals" + * + * @author Tim Su + * + */ +public class RepeatDetailExposer extends BroadcastReceiver { + + @Autowired + TaskService taskService; + + @Override + public void onReceive(Context context, Intent intent) { + // get tags associated with this task + long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); + if(taskId == -1) + return; + + DependencyInjectionService.getInstance().inject(this); + Task task = taskService.fetchById(taskId, Task.FLAGS, Task.RECURRENCE); + if(task == null) + return; + + Resources r = context.getResources(); + + String recurrence = task.getValue(Task.RECURRENCE); + if(recurrence != null && recurrence.length() > 0) { + RRule rrule; + try { + rrule = new RRule(recurrence); + } catch (ParseException e) { + return; + } + String interval; + switch(rrule.getFreq()) { + case HOURLY: + interval = r.getQuantityString(R.plurals.DUt_hours, rrule.getInterval(), + rrule.getInterval()); + break; + case DAILY: + interval = r.getQuantityString(R.plurals.DUt_days, rrule.getInterval(), + rrule.getInterval()); + break; + case WEEKLY: + interval = r.getQuantityString(R.plurals.DUt_weeks, rrule.getInterval(), + rrule.getInterval()); + break; + case MONTHLY: + interval = r.getQuantityString(R.plurals.DUt_months, rrule.getInterval(), + rrule.getInterval()); + break; + default: + // not designed to be used, only a fail-safe + interval = rrule.getInterval() + "-" + rrule.getFreq().name(); //$NON-NLS-1$ + } + + interval = "" + interval + ""; //$NON-NLS-1$//$NON-NLS-2$ + if(rrule.getFreq() == Frequency.WEEKLY) { + List byDay = rrule.getByDay(); + if(byDay.size() > 0) { + StringBuilder byDayString = new StringBuilder(); + DateFormatSymbols dfs = new DateFormatSymbols(); + String[] weekdays = dfs.getShortWeekdays(); + for(int i = 0; i < byDay.size(); i++) { + byDayString.append(weekdays[byDay.get(i).wday.javaDayNum]); + if(i < byDay.size() - 1) + byDayString.append(", "); //$NON-NLS-1$ + } + interval = r.getString(R.string.repeat_detail_byday).replace("$I", //$NON-NLS-1$ + interval).replace("$D", byDayString); //$NON-NLS-1$ + } + } + + + String detail; + if(task.getFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION)) + detail = context.getString(R.string.repeat_detail_completion, interval); + else + detail = context.getString(R.string.repeat_detail_duedate, interval); + + + TaskDetail taskDetail = new TaskDetail(RepeatsPlugin.IDENTIFIER, detail); + + // transmit + Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS); + broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail); + broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId); + context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); + } + + } + +} diff --git a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java index 3b03285e5..4e97b4cf6 100644 --- a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java +++ b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java @@ -40,7 +40,7 @@ public class RepeatTaskCompleteListener extends BroadcastReceiver { DependencyInjectionService.getInstance().inject(this); Task task = taskService.fetchById(taskId, Task.ID, Task.RECURRENCE, - Task.DUE_DATE, Task.FLAGS); + Task.DUE_DATE, Task.FLAGS, Task.HIDE_UNTIL); if(task == null) return; @@ -102,8 +102,14 @@ public class RepeatTaskCompleteListener extends BroadcastReceiver { } } + long hideUntil = task.getValue(Task.HIDE_UNTIL); + if(hideUntil > 0 && task.getValue(Task.DUE_DATE) > 0) { + hideUntil += newDueDate - task.getValue(Task.DUE_DATE); + } + task = taskService.clone(task); task.setValue(Task.DUE_DATE, newDueDate); + task.setValue(Task.HIDE_UNTIL, hideUntil); task.setValue(Task.COMPLETION_DATE, 0L); taskService.save(task, false); } catch (ParseException e) { diff --git a/astrid/res/values/strings-repeat.xml b/astrid/res/values/strings-repeat.xml index 8e92a885b..cb4a4a99c 100644 --- a/astrid/res/values/strings-repeat.xml +++ b/astrid/res/values/strings-repeat.xml @@ -33,4 +33,13 @@ from completion date + + $I on $D + + + Repeats every %s + + + Repeats %s after completion + diff --git a/tests/src/com/todoroo/astrid/repeats/RepeatTests.java b/tests/src/com/todoroo/astrid/repeats/RepeatTests.java index 3a1a4e435..2e0dd6172 100644 --- a/tests/src/com/todoroo/astrid/repeats/RepeatTests.java +++ b/tests/src/com/todoroo/astrid/repeats/RepeatTests.java @@ -254,4 +254,44 @@ public class RepeatTests extends DatabaseTestCase { } } + /** test hide unitl date is repeated */ + public void testHideUntilRepeated() throws Exception { + Task task = new Task(); + task.setValue(Task.TITLE, "hideUntil"); + RRule rrule = new RRule(); + rrule.setInterval(1); + rrule.setFreq(Frequency.WEEKLY); + task.setValue(Task.RECURRENCE, rrule.toIcal()); + task.setValue(Task.DUE_DATE, task.createDueDate(Task.URGENCY_TODAY, 0)); + task.setValue(Task.HIDE_UNTIL, task.createHideUntil(Task.HIDE_UNTIL_DAY_BEFORE, 0)); + taskDao.save(task, false); + + task.setValue(Task.COMPLETION_DATE, DateUtilities.now()); + taskDao.save(task, false); + + // wait for repeat handler + Thread.sleep(REPEAT_WAIT); + + TodorooCursor cursor = taskDao.query(Query.select(Task.PROPERTIES)); + try { + assertEquals(2, cursor.getCount()); + cursor.moveToFirst(); + task.readFromCursor(cursor); + + assertTrue(task.hasDueDate()); + assertTrue(task.isCompleted()); + assertFalse(task.isHidden()); + + cursor.moveToNext(); + task.readFromCursor(cursor); + assertFalse(task.isCompleted()); + assertTrue(task.isHidden()); + long date = task.getValue(Task.HIDE_UNTIL); + assertTrue("Hide Until date is '" + new Date(date) + "', expected more like '" + + new Date(DateUtilities.now() + 6 * DateUtilities.ONE_DAY) + "'", + Math.abs(date - DateUtilities.now() - 6 * DateUtilities.ONE_DAY) < DateUtilities.ONE_DAY); + } finally { + cursor.close(); + } + } }