diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index 8ab344d7a..983e0cf75 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -207,6 +207,12 @@ + + + + + + diff --git a/astrid/common-src/com/todoroo/andlib/sql/DBObject.java b/astrid/common-src/com/todoroo/andlib/sql/DBObject.java index 7d27d70a6..c01b20af7 100644 --- a/astrid/common-src/com/todoroo/andlib/sql/DBObject.java +++ b/astrid/common-src/com/todoroo/andlib/sql/DBObject.java @@ -31,7 +31,7 @@ public abstract class DBObject> implements Cloneable { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - DBObject dbObject = (DBObject) o; + DBObject dbObject = (DBObject) o; if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) return false; if (expression != null ? !expression.equals(dbObject.expression) : dbObject.expression != null) return false; diff --git a/astrid/common-src/com/todoroo/andlib/utility/UserTask.java b/astrid/common-src/com/todoroo/andlib/utility/UserTask.java index 9440a49ae..6c11101eb 100644 --- a/astrid/common-src/com/todoroo/andlib/utility/UserTask.java +++ b/astrid/common-src/com/todoroo/andlib/utility/UserTask.java @@ -415,7 +415,7 @@ public abstract class UserTask { } protected static class InternalHandler extends Handler { - @SuppressWarnings({"unchecked"}) + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public void handleMessage(Message msg) { UserTaskResult result = (UserTaskResult) msg.obj; diff --git a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java index 98caab507..2c1fe8bfc 100644 --- a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java @@ -38,11 +38,18 @@ import com.todoroo.astrid.model.Task; */ public class RepeatControlSet implements TaskEditControlSet { + // --- spinner constants + private static final int INTERVAL_DAYS = 0; private static final int INTERVAL_WEEKS = 1; private static final int INTERVAL_MONTHS = 2; private static final int INTERVAL_YEARS = 3; + private static final int TYPE_DUE_DATE = 0; + private static final int TYPE_COMPLETION_DATE = 1; + + // --- instance variables + private final Activity activity; private final CheckBox enabled; private final Button value; @@ -52,6 +59,8 @@ public class RepeatControlSet implements TaskEditControlSet { private final LinearLayout daysOfWeekContainer; private final CompoundButton[] daysOfWeek = new CompoundButton[7]; + // --- implementation + public RepeatControlSet(final Activity activity, ViewGroup parent) { this.activity = activity; LayoutInflater.from(activity).inflate(R.layout.repeat_control, parent, true); @@ -143,6 +152,7 @@ public class RepeatControlSet implements TaskEditControlSet { public void readFromTask(Task task) { String recurrence = task.getValue(Task.RECURRENCE); + // read recurrence rule if(recurrence.length() > 0) { try { RRule rrule = new RRule(recurrence); @@ -174,9 +184,14 @@ public class RepeatControlSet implements TaskEditControlSet { recurrence = ""; //$NON-NLS-1$ } } - enabled.setChecked(recurrence.length() > 0); repeatContainer.setVisibility(enabled.isChecked() ? View.VISIBLE : View.GONE); + + // read flag + if(task.getFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION)) + type.setSelection(TYPE_COMPLETION_DATE); + else + type.setSelection(TYPE_DUE_DATE); } @@ -210,5 +225,16 @@ public class RepeatControlSet implements TaskEditControlSet { result = rrule.toIcal(); } task.setValue(Task.RECURRENCE, result); + + switch(type.getSelectedItemPosition()) { + case TYPE_DUE_DATE: + task.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, false); + break; + case TYPE_COMPLETION_DATE: + task.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, true); + } + + if(task.getFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION)) + type.setSelection(1); } } \ No newline at end of file diff --git a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java new file mode 100644 index 000000000..7a45f876d --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java @@ -0,0 +1,99 @@ +package com.todoroo.astrid.repeats; + +import java.text.ParseException; +import java.util.Date; +import java.util.TimeZone; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.google.ical.iter.RecurrenceIterator; +import com.google.ical.iter.RecurrenceIteratorFactory; +import com.google.ical.values.DateTimeValueImpl; +import com.google.ical.values.DateValue; +import com.google.ical.values.DateValueImpl; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.service.ExceptionService; +import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.model.Task; +import com.todoroo.astrid.service.TaskService; + +public class RepeatTaskCompleteListener extends BroadcastReceiver { + + @Autowired + private TaskService taskService; + + @Autowired + private ExceptionService exceptionService; + + @Override + public void onReceive(Context context, Intent intent) { + long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); + if(taskId == -1) + return; + + DependencyInjectionService.getInstance().inject(this); + + Task task = taskService.fetchById(taskId, Task.ID, Task.RECURRENCE, + Task.DUE_DATE, Task.FLAGS); + if(task == null) + return; + + String recurrence = task.getValue(Task.RECURRENCE); + if(recurrence.length() > 0) { + Date date = new Date(); + DateValue today = new DateValueImpl(date.getYear() + 1900, + date.getMonth() + 1, date.getDate()); + + DateValue repeatFrom; + if(task.hasDueDate() && !task.getFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION)) { + date = new Date(task.getValue(Task.DUE_DATE)); + repeatFrom = new DateTimeValueImpl(date.getYear() + 1900, + date.getMonth() + 1, date.getDate(), + date.getHours(), date.getMinutes(), date.getSeconds()); + } else { + repeatFrom = today; + } + + // invoke the recurrence iterator + try { + RecurrenceIterator iterator = RecurrenceIteratorFactory.createRecurrenceIterator(recurrence, + repeatFrom, TimeZone.getDefault()); + if(repeatFrom.compareTo(today) < 0) + repeatFrom = today; + // go to the latest value and advance one more + iterator.advanceTo(repeatFrom); + if(!iterator.hasNext()) + return; + DateValue nextDate = iterator.next(); + if(nextDate.equals(repeatFrom)) { + if(!iterator.hasNext()) + return; + nextDate = iterator.next(); + } + + long newDueDate; + if(nextDate instanceof DateTimeValueImpl) { + DateTimeValueImpl newDateTime = (DateTimeValueImpl)nextDate; + newDueDate = task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, + new Date(newDateTime.year() - 1900, newDateTime.month() - 1, + newDateTime.day(), newDateTime.hour(), + newDateTime.minute(), newDateTime.second()).getTime()); + } else { + newDueDate = task.createDueDate(Task.URGENCY_SPECIFIC_DAY, + new Date(nextDate.year() - 1900, nextDate.month() - 1, + nextDate.day()).getTime()); + } + + Task newTask = taskService.clone(task); + task.setValue(Task.DUE_DATE, newDueDate); + taskService.save(newTask, false); + } catch (ParseException e) { + exceptionService.reportError("recurrence-rule: " + recurrence, e); //$NON-NLS-1$ + } + } + } + +} diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagFilterExposer.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagFilterExposer.java index 1f48c3234..099c503c9 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagFilterExposer.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagFilterExposer.java @@ -78,8 +78,8 @@ public class TagFilterExposer extends BroadcastReceiver { FilterListHeader tagsHeader = new FilterListHeader(TagsPlugin.IDENTIFIER, context.getString(R.string.tag_FEx_header)); Filter untagged = new Filter(TagsPlugin.IDENTIFIER, - "Untagged", - "Untagged", + r.getString(R.string.tag_FEx_untagged), + r.getString(R.string.tag_FEx_untagged), tagService.untaggedTemplate(), null); untagged.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_untagged)).getBitmap(); diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java new file mode 100644 index 000000000..50fb93488 --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java @@ -0,0 +1,127 @@ +package com.todoroo.astrid.tags; + +import java.util.ArrayList; + +import android.app.Activity; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.timsu.astrid.R; +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet; +import com.todoroo.astrid.model.Metadata; +import com.todoroo.astrid.model.Task; +import com.todoroo.astrid.tags.TagService.Tag; + +/** + * Control set to manage adding and removing tags + * + * @author Tim Su + * + */ +public final class TagsControlSet implements TaskEditControlSet { + + // --- constants + + /** Number of tags a task can have */ + static final int MAX_TAGS = 5; + + // --- instance variables + + private final TagService tagService = new TagService(); + private final Tag[] allTags; + private final LinearLayout tagsContainer; + private final Activity activity; + + public TagsControlSet(Activity activity, int tagsContainer) { + allTags = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE); + this.activity = activity; + this.tagsContainer = (LinearLayout) activity.findViewById(tagsContainer); + } + + @SuppressWarnings("nls") + @Override + public void readFromTask(Task task) { + // tags (only configure if not already set) + if(tagsContainer.getChildCount() == 0) { + TodorooCursor cursor = tagService.getTags(task.getId()); + try { + for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) + addTag(cursor.get(Metadata.VALUE)); + } finally { + cursor.close(); + } + addTag(""); + } + } + + @Override + public void writeToModel(Task task) { + ArrayList tags = new ArrayList(); + + for(int i = 0; i < tagsContainer.getChildCount(); i++) { + TextView tagName = (TextView)tagsContainer.getChildAt(i).findViewById(R.id.text1); + if(tagName.getText().length() == 0) + continue; + tags.add(tagName.getText().toString()); + } + + tagService.synchronizeTags(task.getId(), tags); + } + + /** Adds a tag to the tag field */ + boolean addTag(String tagName) { + if (tagsContainer.getChildCount() >= MAX_TAGS) { + return false; + } + + LayoutInflater inflater = activity.getLayoutInflater(); + final View tagItem = inflater.inflate(R.layout.tag_edit_row, null); + tagsContainer.addView(tagItem); + + AutoCompleteTextView textView = (AutoCompleteTextView)tagItem. + findViewById(R.id.text1); + textView.setText(tagName); + ArrayAdapter tagsAdapter = + new ArrayAdapter(activity, + android.R.layout.simple_dropdown_item_1line, allTags); + textView.setAdapter(tagsAdapter); + textView.addTextChangedListener(new TextWatcher() { + @SuppressWarnings("nls") + public void onTextChanged(CharSequence s, int start, int before, + int count) { + if(start == 0 && tagsContainer.getChildAt( + tagsContainer.getChildCount()-1) == tagItem) { + addTag(""); + } + } + + 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; + } +} \ No newline at end of file diff --git a/astrid/res/values/arrays.xml b/astrid/res/values/arrays.xml index 0e8246a35..19b46080c 100644 --- a/astrid/res/values/arrays.xml +++ b/astrid/res/values/arrays.xml @@ -24,7 +24,7 @@ minimizing the annoyance. --> - + diff --git a/astrid/res/values/colors.xml b/astrid/res/values/colors.xml index 42220ddd1..bb2ccbbe2 100644 --- a/astrid/res/values/colors.xml +++ b/astrid/res/values/colors.xml @@ -1,5 +1,5 @@ - + #FFFB6666 #FFFFFFFF #ff777777 diff --git a/astrid/res/values/strings-3.0.xml b/astrid/res/values/strings-3.0.xml index cb00216b9..52ac44c60 100644 --- a/astrid/res/values/strings-3.0.xml +++ b/astrid/res/values/strings-3.0.xml @@ -1,6 +1,6 @@ - + @@ -298,12 +298,6 @@ to the plugin creator for fastest service. No Repeat Set - - Tags: - - - Tag Name - Repeat Every (0 to disable) Help: Astrid Repeats diff --git a/astrid/res/values/strings-filters.xml b/astrid/res/values/strings-filters.xml index d8921a5e0..7fb0ce1dd 100644 --- a/astrid/res/values/strings-filters.xml +++ b/astrid/res/values/strings-filters.xml @@ -1,6 +1,6 @@ - + diff --git a/astrid/res/values/strings-legacy.xml b/astrid/res/values/strings-legacy.xml index 2603d4245..6d512cb4f 100644 --- a/astrid/res/values/strings-legacy.xml +++ b/astrid/res/values/strings-legacy.xml @@ -19,7 +19,7 @@ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --> - + diff --git a/astrid/res/values/strings-reminders.xml b/astrid/res/values/strings-reminders.xml index 4c214dfbc..30c6faaa9 100644 --- a/astrid/res/values/strings-reminders.xml +++ b/astrid/res/values/strings-reminders.xml @@ -1,6 +1,6 @@ - + diff --git a/astrid/res/values/strings-repeat.xml b/astrid/res/values/strings-repeat.xml index 452d396f7..7d306614b 100644 --- a/astrid/res/values/strings-repeat.xml +++ b/astrid/res/values/strings-repeat.xml @@ -1,6 +1,6 @@ - + diff --git a/astrid/res/values/strings-tags.xml b/astrid/res/values/strings-tags.xml index cf7ba787b..9e2e164aa 100644 --- a/astrid/res/values/strings-tags.xml +++ b/astrid/res/values/strings-tags.xml @@ -1,24 +1,32 @@ - + - Add Tags - Tags: %s - - Tags: %s - - Tags - By Size - Alphabetical - - - $T ($C) - - Tagged \'%s\' + + + + Tags: + + + Tag Name + + + + Tags: %s - Type In a Tag - Edit Tags + + + Tags + By Size + Alphabetical + Untagged + + + $T ($C) + + + Tagged \'%s\' diff --git a/astrid/res/values/styles-3.0.xml b/astrid/res/values/styles-3.0.xml index f13d6c3ca..9d65e463c 100644 --- a/astrid/res/values/styles-3.0.xml +++ b/astrid/res/values/styles-3.0.xml @@ -1,6 +1,6 @@ - + diff --git a/astrid/res/values/styles-legacy.xml b/astrid/res/values/styles-legacy.xml index 4433d17c4..c6f8f3053 100644 --- a/astrid/res/values/styles-legacy.xml +++ b/astrid/res/values/styles-legacy.xml @@ -19,7 +19,7 @@ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --> - +