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();
+ }
+ }
}