1.9 beta release:

- added tabbed interface for editor
   - added ability to set fixed-time notifications
   - fixed some crashes
pull/14/head
Tim Su 16 years ago
parent 8c3aaab57e
commit b78e5aa309

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.timsu.astrid"
android:versionCode="24"
android:versionName="1.8.1">
android:versionCode="25"
android:versionName="1.9">
<uses-permission android:name="android.permission.VIBRATE"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="@+id/date"
android:layout_weight="0.45"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/time"
android:layout_weight="0.45"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageButton android:id="@+id/button1"
style="?android:attr/buttonStyleInset"
android:src="@android:drawable/ic_delete"
android:layout_weight="0.1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginTop="2dip"
android:layout_marginRight="2dip"
android:layout_marginBottom="2dip"
android:gravity="center_vertical"
/>
</LinearLayout>

@ -19,291 +19,285 @@
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scroll_view"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ScrollView
android:id="@+id/tab_basic"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:id="@+id/event"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_height="fill_parent">
<!-- TASK NAME -->
<LinearLayout
android:orientation="vertical"
<TextView android:id="@+id/name_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/name_label"
style="@style/TextAppearance.EditEvent_Label"/>
<EditText android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip">
android:hint="@string/name_hint"
android:capitalize="words"/>
<TextView android:id="@+id/importance_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/importance_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Spinner android:id="@+id/importance"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView android:id="@+id/name_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/name_label"
style="@style/TextAppearance.EditEvent_Label"/>
<EditText android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/name_hint"
android:capitalize="words"/>
</LinearLayout>
<TextView android:id="@+id/estimatedDuration_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/estimatedDuration_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Button android:id="@+id/estimatedDuration"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/tags_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tags_label"
style="@style/TextAppearance.EditEvent_Label"/>
<!-- VITAL PROPERTIES -->
<LinearLayout android:id="@+id/tags_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark"
/>
<LinearLayout android:id="@+id/properties_container"
android:orientation="vertical"
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip">
<TextView android:id="@+id/importance_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/importance_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Spinner android:id="@+id/importance"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
android:paddingTop="5dip"
android:baselineAligned="false">
<TextView android:id="@+id/estimatedDuration_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/estimatedDuration_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Button android:id="@+id/estimatedDuration"
<Button android:id="@+id/save"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/notification_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Button android:id="@+id/notification"
android:layout_weight="1"
android:text="@string/save_label"
/>
<Button android:id="@+id/discard"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/tags_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tags_label"
style="@style/TextAppearance.EditEvent_Label"/>
android:layout_weight="1"
android:text="@string/discard_label"
/>
<LinearLayout android:id="@+id/tags_container"
android:orientation="vertical"
<Button android:id="@+id/delete"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</LinearLayout>
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/delete_label"
/>
</LinearLayout>
<!-- DATES -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="@android:drawable/divider_horizontal_dark"
/>
<LinearLayout android:id="@+id/dates_container"
android:orientation="vertical"
android:layout_width="fill_parent"
</LinearLayout>
</ScrollView>
<!-- DATES -->
<ScrollView
android:id="@+id/tab_dates"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:id="@+id/event"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/definiteDueDate_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip">
android:text="@string/definiteDueDate_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/definiteDueDate_label"
<CheckBox android:id="@+id/definiteDueDate_notnull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/definiteDueDate_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/definiteDueDate_notnull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/definiteDueDate_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/definiteDueDate_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView android:id="@+id/preferredDueDate_label"
android:layout_height="wrap_content"/>
<Button android:id="@+id/definiteDueDate_date"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/preferredDueDate_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/preferredDueDate_notnull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/preferredDueDate_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"/>
<Button android:id="@+id/definiteDueDate_time"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/preferredDueDate_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
<!-- HIDING -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="@android:drawable/divider_horizontal_dark"
/>
<LinearLayout android:id="@+id/hiding_container"
android:orientation="vertical"
android:layout_width="fill_parent"
<TextView android:id="@+id/preferredDueDate_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip">
android:text="@string/preferredDueDate_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/hiddenUntil_label"
<CheckBox android:id="@+id/preferredDueDate_notnull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hiddenUntil_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/hiddenUntil_notnull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/hiddenUntil_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/hiddenUntil_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
android:layout_height="wrap_content"/>
<!--<TextView android:id="@+id/blockingon_label"
<Button android:id="@+id/preferredDueDate_date"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/blockingon_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"/>
<Button android:id="@+id/preferredDueDate_time"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<CheckBox android:id="@+id/blockingOn_notnull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Spinner android:id="@+id/blockingon"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>-->
</LinearLayout>
<!-- MISC FIELDS -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="@android:drawable/divider_horizontal_dark"
/>
<LinearLayout android:id="@+id/misc_container"
android:orientation="vertical"
android:layout_width="fill_parent"
<TextView android:id="@+id/hiddenUntil_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip">
android:text="@string/hiddenUntil_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/notes_label"
<CheckBox android:id="@+id/hiddenUntil_notnull"
android:layout_weight="0.1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notes_label"
style="@style/TextAppearance.EditEvent_Label"/>
<EditText android:id="@+id/notes"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="vertical"
android:gravity="top"
android:hint="@string/notes_hint"
android:capitalize="sentences"
android:singleLine="false" />
android:layout_height="wrap_content"/>
<TextView android:id="@+id/elapsedDuration_label"
<Button android:id="@+id/hiddenUntil_date"
android:layout_weight="0.45"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/elapsedDuration_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Button android:id="@+id/elapsedDuration"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<Button android:id="@+id/hiddenUntil_time"
android:layout_weight="0.45"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- SAVE -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
<TextView android:id="@+id/elapsedDuration_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dip"
android:baselineAligned="false">
android:text="@string/elapsedDuration_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Button android:id="@+id/elapsedDuration"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<Button android:id="@+id/save"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/save_label"
/>
<TextView android:id="@+id/notes_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notes_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Button android:id="@+id/discard"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/discard_label"
/>
<EditText android:id="@+id/notes"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scrollbars="vertical"
android:gravity="top"
android:hint="@string/notes_hint"
android:capitalize="sentences"
android:singleLine="false" />
</LinearLayout>
</ScrollView>
<ScrollView
android:id="@+id/tab_notification"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:id="@+id/event"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/notification_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_label"
style="@style/TextAppearance.EditEvent_Label"/>
<Button android:id="@+id/notification"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<Button android:id="@+id/delete"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/delete_label"
/>
<TextView android:id="@+id/alerts_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alerts_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout android:id="@+id/alert_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</LinearLayout>
<Button android:id="@+id/addAlert"
android:text="@string/add_alert"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/flags_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/flags_label"
style="@style/TextAppearance.EditEvent_Label"/>
<CheckBox android:id="@+id/flag_before"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/flag_before"/>
<CheckBox android:id="@+id/flag_during"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/flag_during"/>
<CheckBox android:id="@+id/flag_after"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/flag_after"/>
</LinearLayout>
</ScrollView>
</FrameLayout>

@ -100,23 +100,39 @@
<string name="taskEdit_titleGeneric">Astrid: Editing Task</string>
<string name="taskEdit_titlePrefix">Astrid: Editing </string>
<string name="task_edit_tab_1">Basic</string>
<string name="task_edit_tab_2">Dates</string>
<string name="task_edit_tab_3">Alerts</string>
<!-- labels -->
<string name="name_label">What</string>
<string name="name_hint">Task Description</string>
<string name="estimatedDuration_label">How Long Will it Take?</string>
<string name="elapsedDuration_label">Time Already Spent on Task</string>
<string name="importance_label">How Important is it?</string>
<string name="tags_label">Tags:</string>
<string name="notification_label">Remind Me At Least</string>
<string name="notification_prefix">Every</string>
<string name="notes_label">Notes</string>
<string name="notes_hint">Enter Task Notes</string>
<string name="estimatedDuration_label">How Long Will it Take?</string>
<string name="elapsedDuration_label">Time Already Spent on Task</string>
<string name="definiteDueDate_label">Absolute Deadline</string>
<string name="preferredDueDate_label">Goal Deadline</string>
<string name="hiddenUntil_label">Hide Until This Date</string>
<string name="blockingOn_label">Hide Until This Task is Done</string>
<string name="notes_label">Notes</string>
<string name="notes_hint">Enter Task Notes</string>
<string name="notification_label">Periodic Reminders</string>
<string name="notification_prefix">Every</string>
<string name="flags_label">Notify me...</string>
<string name="flag_before">As Deadlines Approach</string>
<string name="flag_during">At Deadlines</string>
<string name="flag_after">After Absolute Deadline Passes</string>
<string name="alerts_label">Fixed Reminders</string>
<string name="add_alert">Add New Reminder</string>
<!-- dialog boxes -->
<string name="hour_minutes_dialog">Time (hours : minutes)</string>
<string name="notification_dialog">Remind Me Every</string>
<!-- buttons -->
<string name="save_label">Save</string>
<string name="discard_label">Discard</string>
<string name="delete_label">Delete</string>

@ -9,215 +9,307 @@ package com.timsu.astrid;
public final class R {
public static final class array {
public static final int availability=0x7f040006;
/** Order matters, and note that the preference for which day the week starts on is handled
elsewhere (and needn't be addressed here).
/** Astrid says... (user should answer yes or no)
*/
public static final int day_labels=0x7f040008;
/** The corresponding indices are defined in DeleteEventHelper.java
public static final int reminder_responses=0x7f050001;
/** Make these < 20 chars so the task name is displayed
*/
public static final int delete_repeating_labels=0x7f04000c;
/** The corresponding indices are defined in DeleteEventHelper.java
This is the same array as above (the "delete_repeating_labels" array,
except that the first element "Only this event" is removed. This
array exists to work-around a bug in the CalendarProvider and sync
code where you can't delete one instance of a repeating event that
was created on the phone until that event has been synced to the server.
*/
public static final int delete_repeating_labels_no_selected=0x7f04000d;
public static final int ordinal_labels=0x7f040009;
public static final int preferences_alert_type_labels=0x7f040004;
public static final int preferences_alert_type_values=0x7f040005;
public static final int preferences_default_reminder_labels=0x7f040002;
public static final int preferences_default_reminder_values=0x7f040003;
/** Choices for the "Reminder minutes" spinner.
These must be kept in sync with the reminder_minutes_values array.
*/
public static final int reminder_minutes_labels=0x7f040000;
public static final int reminder_minutes_values=0x7f040001;
/** Invitation responses
*/
public static final int response_labels1=0x7f04000a;
public static final int response_labels2=0x7f04000b;
public static final int visibility=0x7f040007;
public static final int reminders=0x7f050000;
}
public static final class attr {
}
public static final class color {
public static final int importance_1=0x7f050005;
public static final int importance_2=0x7f050006;
public static final int importance_3=0x7f050007;
public static final int importance_4=0x7f050008;
public static final int task_list_done=0x7f050001;
public static final int task_list_overdue=0x7f050000;
public static final int view_header_done=0x7f050002;
public static final int view_table_overdue=0x7f050004;
public static final int view_table_values=0x7f050003;
public static final int importance_1=0x7f060009;
public static final int importance_2=0x7f06000a;
public static final int importance_3=0x7f06000b;
public static final int importance_4=0x7f06000c;
public static final int taskList_completedDate=0x7f060004;
public static final int taskList_dueDate=0x7f060003;
public static final int taskList_dueDateOverdue=0x7f060002;
public static final int taskList_tags=0x7f060005;
public static final int task_list_done=0x7f060001;
public static final int task_list_overdue=0x7f060000;
public static final int view_header_done=0x7f060006;
public static final int view_table_overdue=0x7f060008;
public static final int view_table_values=0x7f060007;
}
public static final class drawable {
public static final int highlight_pressed=0x7f020000;
public static final int highlight_selected=0x7f020001;
public static final int ic_dialog_time=0x7f020002;
public static final int icon=0x7f020003;
public static final int strikeout=0x7f020004;
public static final int timepicker_down_btn=0x7f020005;
public static final int timepicker_down_disabled=0x7f020006;
public static final int timepicker_down_disabled_focused=0x7f020007;
public static final int timepicker_down_normal=0x7f020008;
public static final int timepicker_down_pressed=0x7f020009;
public static final int timepicker_down_selected=0x7f02000a;
public static final int timepicker_input=0x7f02000b;
public static final int timepicker_input_disabled=0x7f02000c;
public static final int timepicker_input_normal=0x7f02000d;
public static final int timepicker_input_pressed=0x7f02000e;
public static final int timepicker_input_selected=0x7f02000f;
public static final int timepicker_up_btn=0x7f020010;
public static final int timepicker_up_disabled=0x7f020011;
public static final int timepicker_up_disabled_focused=0x7f020012;
public static final int timepicker_up_normal=0x7f020013;
public static final int timepicker_up_pressed=0x7f020014;
public static final int timepicker_up_selected=0x7f020015;
public static final int transparent_button=0x7f020016;
public static final int btn_check0=0x7f020000;
public static final int btn_check25=0x7f020001;
public static final int btn_check50=0x7f020002;
public static final int btn_check75=0x7f020003;
public static final int btn_check_0=0x7f020004;
public static final int btn_check_25=0x7f020005;
public static final int btn_check_50=0x7f020006;
public static final int btn_check_75=0x7f020007;
public static final int btn_check_off=0x7f020008;
public static final int btn_check_off_disable=0x7f020009;
public static final int btn_check_off_disable_focused=0x7f02000a;
public static final int btn_check_off_longpress=0x7f02000b;
public static final int btn_check_off_pressed=0x7f02000c;
public static final int btn_check_off_selected=0x7f02000d;
public static final int btn_check_on=0x7f02000e;
public static final int btn_check_on_disable=0x7f02000f;
public static final int btn_check_on_disable_focused=0x7f020010;
public static final int btn_check_on_longpress=0x7f020011;
public static final int btn_check_on_pressed=0x7f020012;
public static final int btn_check_on_selected=0x7f020013;
public static final int highlight_longpress=0x7f020014;
public static final int highlight_pressed=0x7f020015;
public static final int highlight_selected=0x7f020016;
public static final int ic_dialog_alert_c=0x7f020017;
public static final int ic_dialog_info_c=0x7f020018;
public static final int ic_dialog_time=0x7f020019;
public static final int ic_dialog_time_c=0x7f02001a;
public static final int icon=0x7f02001b;
public static final int strikeout=0x7f02001c;
public static final int timepicker_down_btn=0x7f02001d;
public static final int timepicker_down_disabled=0x7f02001e;
public static final int timepicker_down_disabled_focused=0x7f02001f;
public static final int timepicker_down_normal=0x7f020020;
public static final int timepicker_down_pressed=0x7f020021;
public static final int timepicker_down_selected=0x7f020022;
public static final int timepicker_input=0x7f020023;
public static final int timepicker_input_disabled=0x7f020024;
public static final int timepicker_input_normal=0x7f020025;
public static final int timepicker_input_pressed=0x7f020026;
public static final int timepicker_input_selected=0x7f020027;
public static final int timepicker_up_btn=0x7f020028;
public static final int timepicker_up_disabled=0x7f020029;
public static final int timepicker_up_disabled_focused=0x7f02002a;
public static final int timepicker_up_normal=0x7f02002b;
public static final int timepicker_up_pressed=0x7f02002c;
public static final int timepicker_up_selected=0x7f02002d;
public static final int transparent_button=0x7f02002e;
public static final int transparent_button_transition=0x7f02002f;
}
public static final class id {
public static final int addtask=0x7f090023;
public static final int button_layout=0x7f090029;
public static final int cb1=0x7f090025;
public static final int cell_definiteDueDate=0x7f09002f;
public static final int cell_elapsed=0x7f09002d;
public static final int cell_estimated=0x7f09002e;
public static final int cell_notes=0x7f090031;
public static final int cell_preferredDueDate=0x7f090030;
public static final int dates_container=0x7f09000d;
public static final int decrement=0x7f090002;
public static final int definiteDueDate_date=0x7f090010;
public static final int definiteDueDate_label=0x7f09000e;
public static final int definiteDueDate_notnull=0x7f09000f;
public static final int definiteDueDate_time=0x7f090011;
public static final int delete=0x7f090020;
public static final int discard=0x7f09001f;
public static final int edit=0x7f09002c;
public static final int elapsedDuration=0x7f09001d;
public static final int elapsedDuration_label=0x7f09001c;
public static final int estimatedDuration=0x7f09000a;
public static final int estimatedDuration_label=0x7f090009;
public static final int event=0x7f090005;
public static final int hiddenUntil_date=0x7f090018;
public static final int hiddenUntil_label=0x7f090016;
public static final int hiddenUntil_notnull=0x7f090017;
public static final int hiddenUntil_time=0x7f090019;
public static final int image1=0x7f090026;
public static final int importance=0x7f09000c;
public static final int importance_label=0x7f09000b;
public static final int increment=0x7f090000;
public static final int name=0x7f090007;
public static final int name_label=0x7f090006;
public static final int notes=0x7f09001b;
public static final int notes_label=0x7f09001a;
public static final int numberPicker=0x7f090003;
public static final int preferredDueDate_date=0x7f090014;
public static final int preferredDueDate_label=0x7f090012;
public static final int preferredDueDate_notnull=0x7f090013;
public static final int preferredDueDate_time=0x7f090015;
public static final int progress=0x7f09002b;
public static final int properties_container=0x7f090008;
public static final int row_layout=0x7f090024;
public static final int save=0x7f09001e;
public static final int scroll_view=0x7f090004;
public static final int tasklist=0x7f090022;
public static final int tasklist_layout=0x7f090021;
public static final int text1=0x7f090027;
public static final int timepicker_input=0x7f090001;
public static final int timerButton=0x7f09002a;
public static final int view_layout=0x7f090028;
public static final int addAlert=0x7f0a002f;
public static final int addtask=0x7f0a0036;
public static final int alert_container=0x7f0a002e;
public static final int alerts_label=0x7f0a002d;
public static final int btn_tasklist=0x7f0a0041;
public static final int btn_viewtask=0x7f0a0040;
public static final int button1=0x7f0a0002;
public static final int button_layout=0x7f0a0044;
public static final int cb1=0x7f0a0038;
public static final int cell_creationDate=0x7f0a004b;
public static final int cell_definiteDueDate=0x7f0a0049;
public static final int cell_elapsed=0x7f0a0047;
public static final int cell_estimated=0x7f0a0048;
public static final int cell_notes=0x7f0a004c;
public static final int cell_preferredDueDate=0x7f0a004a;
public static final int container=0x7f0a0004;
public static final int date=0x7f0a0000;
public static final int decrement=0x7f0a0007;
public static final int definiteDueDate_date=0x7f0a001c;
public static final int definiteDueDate_label=0x7f0a001a;
public static final int definiteDueDate_notnull=0x7f0a001b;
public static final int definiteDueDate_time=0x7f0a001d;
public static final int delete=0x7f0a0018;
public static final int discard=0x7f0a0017;
public static final int edit=0x7f0a004d;
public static final int elapsedDuration=0x7f0a0027;
public static final int elapsedDuration_label=0x7f0a0026;
public static final int estimatedDuration=0x7f0a0013;
public static final int estimatedDuration_label=0x7f0a0012;
public static final int event=0x7f0a000d;
public static final int flag_after=0x7f0a0033;
public static final int flag_before=0x7f0a0031;
public static final int flag_during=0x7f0a0032;
public static final int flags_label=0x7f0a0030;
public static final int frame=0x7f0a000b;
public static final int greeting=0x7f0a003e;
public static final int hiddenUntil_date=0x7f0a0024;
public static final int hiddenUntil_label=0x7f0a0022;
public static final int hiddenUntil_notnull=0x7f0a0023;
public static final int hiddenUntil_time=0x7f0a0025;
public static final int image1=0x7f0a0039;
public static final int importance=0x7f0a0011;
public static final int importance_label=0x7f0a0010;
public static final int increment=0x7f0a0005;
public static final int name=0x7f0a000f;
public static final int name_label=0x7f0a000e;
public static final int notes=0x7f0a0029;
public static final int notes_label=0x7f0a0028;
public static final int notification=0x7f0a002c;
public static final int notification_label=0x7f0a002b;
public static final int numberPicker=0x7f0a0008;
public static final int preferredDueDate_date=0x7f0a0020;
public static final int preferredDueDate_label=0x7f0a001e;
public static final int preferredDueDate_notnull=0x7f0a001f;
public static final int preferredDueDate_time=0x7f0a0021;
public static final int progress=0x7f0a0046;
public static final int prop_layout=0x7f0a003b;
public static final int row_layout=0x7f0a0037;
public static final int save=0x7f0a0016;
public static final int scroll_view=0x7f0a0042;
public static final int tab_basic=0x7f0a000c;
public static final int tab_dates=0x7f0a0019;
public static final int tab_notification=0x7f0a002a;
public static final int taglist=0x7f0a000a;
public static final int taglist_layout=0x7f0a0009;
public static final int tags_container=0x7f0a0015;
public static final int tags_label=0x7f0a0014;
public static final int tasklist=0x7f0a0035;
public static final int tasklist_layout=0x7f0a0034;
public static final int taskname=0x7f0a003f;
public static final int text1=0x7f0a0003;
public static final int text_dueDate=0x7f0a003c;
public static final int text_layout=0x7f0a003a;
public static final int text_tags=0x7f0a003d;
public static final int time=0x7f0a0001;
public static final int timepicker_input=0x7f0a0006;
public static final int timerButton=0x7f0a0045;
public static final int view_layout=0x7f0a0043;
}
public static final class layout {
public static final int number_picker=0x7f030000;
public static final int number_picker_dialog=0x7f030001;
public static final int task_edit=0x7f030002;
public static final int task_list=0x7f030003;
public static final int task_list_row=0x7f030004;
public static final int task_view=0x7f030005;
public static final int edit_alert_item=0x7f030000;
public static final int edit_tag_item=0x7f030001;
public static final int importance_spinner_dropdown=0x7f030002;
public static final int n_number_picker_dialog=0x7f030003;
public static final int number_picker=0x7f030004;
public static final int number_picker_dialog=0x7f030005;
public static final int tag_list=0x7f030006;
public static final int task_edit=0x7f030007;
public static final int task_list=0x7f030008;
public static final int task_list_row=0x7f030009;
public static final int task_notify=0x7f03000a;
public static final int task_view=0x7f03000b;
}
public static final class plurals {
public static final int NactiveTasks=0x7f080001;
/** Time Constants
*/
public static final int Ndays=0x7f070001;
public static final int Nhours=0x7f070002;
public static final int Nminutes=0x7f070003;
public static final int Nseconds=0x7f070004;
public static final int Ndays=0x7f080003;
public static final int Nhours=0x7f080004;
public static final int Nminutes=0x7f080005;
public static final int Nseconds=0x7f080006;
public static final int Ntags=0x7f080002;
/** Plurals
*/
public static final int Ntasks=0x7f070000;
public static final int Ntasks=0x7f080000;
}
public static final class string {
public static final int addtask_label=0x7f060007;
public static final int add_alert=0x7f070036;
public static final int addtask_label=0x7f07000f;
public static final int ago_suffix=0x7f07004c;
public static final int alerts_label=0x7f070035;
/** application
*/
public static final int app_name=0x7f060000;
public static final int blank_button_title=0x7f060023;
public static final int blockingOn_label=0x7f06001c;
public static final int definiteDueDate_label=0x7f060019;
public static final int delete_label=0x7f060022;
public static final int delete_this_task_title=0x7f060032;
public static final int delete_title=0x7f060031;
public static final int discard_label=0x7f060021;
public static final int edit_label=0x7f060029;
public static final int elapsedDuration_label=0x7f060016;
public static final int estimatedDuration_label=0x7f060015;
public static final int hiddenUntil_label=0x7f06001b;
public static final int app_name=0x7f070000;
public static final int blank_button_title=0x7f07003c;
public static final int blockingOn_label=0x7f07002e;
public static final int days=0x7f070005;
public static final int definiteDueDate_label=0x7f07002b;
public static final int delete_label=0x7f07003b;
public static final int delete_this_tag_title=0x7f07005c;
public static final int delete_this_task_title=0x7f07005b;
public static final int delete_title=0x7f07005a;
public static final int discard_label=0x7f07003a;
public static final int edit_label=0x7f070043;
public static final int elapsedDuration_label=0x7f07002a;
public static final int error_opening=0x7f070060;
public static final int error_saving=0x7f070061;
public static final int estimatedDuration_label=0x7f070029;
public static final int flag_after=0x7f070034;
public static final int flag_before=0x7f070032;
public static final int flag_during=0x7f070033;
public static final int flags_label=0x7f070031;
public static final int hiddenUntil_label=0x7f07002d;
/** dialog boxes
*/
public static final int hour_minutes_dialog=0x7f070037;
public static final int hours=0x7f070006;
/** Importance Labels
*/
public static final int importance_1=0x7f060001;
public static final int importance_2=0x7f060002;
public static final int importance_3=0x7f060003;
public static final int importance_4=0x7f060004;
public static final int importance_label=0x7f060017;
public static final int minutes_dialog=0x7f06001f;
public static final int name_hint=0x7f060014;
public static final int name_label=0x7f060013;
public static final int notes_hint=0x7f06001e;
public static final int notes_label=0x7f06001d;
public static final int overdue_suffix=0x7f06002f;
public static final int preferredDueDate_label=0x7f06001a;
public static final int progress_dialog=0x7f060030;
public static final int progress_suffix=0x7f060028;
public static final int save_label=0x7f060020;
public static final int startTimer_label=0x7f060026;
public static final int stopTimer_label=0x7f060027;
public static final int tags_label=0x7f060018;
public static final int taskEdit_menu_save=0x7f060024;
public static final int taskEdit_titleGeneric=0x7f060011;
public static final int taskEdit_titlePrefix=0x7f060012;
public static final int taskList_context_delete=0x7f06000d;
public static final int taskList_context_edit=0x7f06000c;
public static final int taskList_filter_done=0x7f060010;
public static final int taskList_filter_hidden=0x7f06000f;
public static final int taskList_filter_title=0x7f06000e;
public static final int taskList_hiddenSuffix=0x7f060006;
public static final int taskList_menu_filters=0x7f06000b;
public static final int taskList_menu_insert=0x7f060008;
public static final int taskList_menu_settings=0x7f06000a;
public static final int taskList_menu_tags=0x7f060009;
public static final int taskList_titlePrefix=0x7f060005;
public static final int taskView_definiteDueDate=0x7f06002c;
public static final int taskView_elapsed=0x7f06002a;
public static final int taskView_estimated=0x7f06002b;
public static final int taskView_notes=0x7f06002e;
public static final int taskView_preferredDueDate=0x7f06002d;
public static final int taskView_title=0x7f060025;
public static final int importance_1=0x7f070001;
public static final int importance_2=0x7f070002;
public static final int importance_3=0x7f070003;
public static final int importance_4=0x7f070004;
public static final int importance_label=0x7f070025;
public static final int information_title=0x7f070056;
public static final int name_hint=0x7f070024;
/** labels
*/
public static final int name_label=0x7f070023;
public static final int no_tags=0x7f070011;
public static final int notes_hint=0x7f070028;
public static final int notes_label=0x7f070027;
public static final int notif_definiteDueDate=0x7f07005e;
public static final int notif_preferredDueDate=0x7f07005f;
public static final int notification_dialog=0x7f070038;
public static final int notification_label=0x7f07002f;
public static final int notification_prefix=0x7f070030;
public static final int notify_no=0x7f070059;
public static final int notify_yes=0x7f070058;
public static final int overdue_suffix=0x7f07004b;
public static final int p_notif_quietEnd=0x7f070063;
public static final int p_notif_quietStart=0x7f070062;
public static final int preferredDueDate_label=0x7f07002c;
public static final int progress_dialog=0x7f07004d;
public static final int progress_suffix=0x7f070042;
public static final int question_title=0x7f070057;
/** buttons
*/
public static final int save_label=0x7f070039;
public static final int startTimer_label=0x7f070040;
public static final int stopTimer_label=0x7f070041;
public static final int stop_timer_title=0x7f07005d;
public static final int tagList_context_create=0x7f07004f;
public static final int tagList_context_delete=0x7f070051;
public static final int tagList_context_edit=0x7f070050;
public static final int tagList_context_hideTag=0x7f070053;
public static final int tagList_context_showTag=0x7f070052;
public static final int tagList_menu_sortAlpha=0x7f070054;
public static final int tagList_menu_sortSize=0x7f070055;
public static final int tagList_titlePrefix=0x7f07004e;
public static final int tags_label=0x7f070026;
public static final int tags_prefix=0x7f070010;
public static final int taskEdit_menu_save=0x7f07003d;
public static final int taskEdit_titleGeneric=0x7f07001e;
public static final int taskEdit_titlePrefix=0x7f07001f;
public static final int taskList_completedPrefix=0x7f07000c;
public static final int taskList_context_delete=0x7f070017;
public static final int taskList_context_edit=0x7f070016;
public static final int taskList_context_startTimer=0x7f070018;
public static final int taskList_context_stopTimer=0x7f070019;
public static final int taskList_dueIn=0x7f07000a;
public static final int taskList_filter_done=0x7f07001c;
public static final int taskList_filter_hidden=0x7f07001b;
public static final int taskList_filter_tagged=0x7f07001d;
public static final int taskList_filter_title=0x7f07001a;
public static final int taskList_goalPrefix=0x7f07000b;
public static final int taskList_hiddenPrefix=0x7f07000e;
public static final int taskList_hiddenSuffix=0x7f070009;
public static final int taskList_menu_filters=0x7f070015;
public static final int taskList_menu_insert=0x7f070012;
public static final int taskList_menu_settings=0x7f070014;
public static final int taskList_menu_tags=0x7f070013;
public static final int taskList_overdueBy=0x7f07000d;
public static final int taskList_titlePrefix=0x7f070007;
public static final int taskList_titleTagPrefix=0x7f070008;
public static final int taskView_creationDate=0x7f070048;
public static final int taskView_definiteDueDate=0x7f070046;
public static final int taskView_elapsed=0x7f070044;
public static final int taskView_estimated=0x7f070045;
public static final int taskView_notes=0x7f07004a;
public static final int taskView_notifyTitle=0x7f07003f;
public static final int taskView_preferredDueDate=0x7f070047;
public static final int taskView_tags=0x7f070049;
public static final int taskView_title=0x7f07003e;
public static final int task_edit_tab_1=0x7f070020;
public static final int task_edit_tab_2=0x7f070021;
public static final int task_edit_tab_3=0x7f070022;
}
public static final class style {
public static final int Alert=0x7f080000;
public static final int MonthView_DayLabel=0x7f080001;
public static final int TextAppearance=0x7f080002;
public static final int TextAppearance_AgendaView_ValueLabel=0x7f080004;
public static final int TextAppearance_Alert_Label=0x7f080007;
public static final int TextAppearance_Alert_Title=0x7f080006;
public static final int TextAppearance_Alert_Value=0x7f080008;
public static final int TextAppearance_EditEvent_Label=0x7f080005;
public static final int TextAppearance_MonthView_DayLabel=0x7f080003;
public static final int Alert=0x7f090000;
public static final int TextAppearance=0x7f090001;
public static final int TextAppearance_EditEvent_Label=0x7f090004;
public static final int TextAppearance_TaskList_Detail=0x7f090003;
public static final int TextAppearance_TaskList_Task=0x7f090002;
}
public static final class xml {
public static final int preferences=0x7f040000;
}
}

@ -19,6 +19,7 @@
*/
package com.timsu.astrid.activities;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@ -50,10 +51,12 @@ import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SimpleCursorAdapter;
import android.widget.Spinner;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.timsu.astrid.R;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.enums.Importance;
import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagIdentifier;
@ -63,10 +66,11 @@ import com.timsu.astrid.data.task.TaskModelForEdit;
import com.timsu.astrid.data.task.TaskModelForList;
import com.timsu.astrid.utilities.Notifications;
import com.timsu.astrid.widget.DateControlSet;
import com.timsu.astrid.widget.DateWithNullControlSet;
import com.timsu.astrid.widget.TimeDurationControlSet;
import com.timsu.astrid.widget.TimeDurationControlSet.TimeDurationType;
public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
public class TaskEdit extends TaskModificationTabbedActivity<TaskModelForEdit> {
// bundle arguments
public static final String TAG_NAME_TOKEN = "tag";
@ -81,6 +85,10 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
// other constants
private static final int MAX_TAGS = 5;
private static final int MAX_ALERTS = 5;
private static final String TAB_BASIC = "basic";
private static final String TAB_DATES = "dates";
private static final String TAB_ALERTS = "alerts";
// UI components
private EditText name;
@ -91,31 +99,50 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
private DateControlSet definiteDueDate;
private DateControlSet preferredDueDate;
private DateControlSet hiddenUntil;
private BlockingOnControlSet blockingOn;
private EditText notes;
private LinearLayout tagsContainer;
private NotificationFlagControlSet flags;
private LinearLayout alertsContainer;
// other instance variables
private boolean shouldSaveState = true;
private TagController tagController;
private List<TagModelForView> tags;
private AlertController alertController;
private List<TagModelForView> tags;
private List<TagIdentifier> taskTags;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tagController = new TagController(this);
tagController.open();
setContentView(R.layout.task_edit);
alertController = new AlertController(this);
alertController.open();
TabHost tabHost = getTabHost();
Resources r = getResources();
LayoutInflater.from(this).inflate(R.layout.task_edit,
tabHost.getTabContentView(), true);
tabHost.addTab(tabHost.newTabSpec(TAB_BASIC)
.setIndicator("Basic",
r.getDrawable(R.drawable.ic_dialog_info_c))
.setContent(R.id.tab_basic));
tabHost.addTab(tabHost.newTabSpec(TAB_DATES)
.setIndicator("Details",
r.getDrawable(R.drawable.ic_dialog_time_c))
.setContent(R.id.tab_dates));
tabHost.addTab(tabHost.newTabSpec(TAB_ALERTS)
.setIndicator("Alerts",
r.getDrawable(R.drawable.ic_dialog_alert_c))
.setContent(R.id.tab_notification));
setUpUIComponents();
setUpListeners();
Bundle extras = getIntent().getExtras();
if(extras != null && extras.containsKey(TAG_NAME_TOKEN)) {
addTag(extras.getString(TAG_NAME_TOKEN));
}
}
@Override
protected TaskModelForEdit getModel(TaskIdentifier identifier) {
if (identifier != null)
@ -146,8 +173,8 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
definiteDueDate.setDate(model.getDefiniteDueDate());
preferredDueDate.setDate(model.getPreferredDueDate());
hiddenUntil.setDate(model.getHiddenUntil());
// blockingOn.setBlockingOn(model.getBlockingOn());
notification.setTimeDuration(model.getNotificationIntervalSeconds());
flags.setValue(model.getNotificationFlags());
notes.setText(model.getNotes());
// tags
@ -167,10 +194,24 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
addTag(tag.getName());
}
}
} else
} else {
taskTags = new LinkedList<TagIdentifier>();
Bundle extras = getIntent().getExtras();
if(extras != null && extras.containsKey(TAG_NAME_TOKEN)) {
addTag(extras.getString(TAG_NAME_TOKEN));
}
}
addTag("");
// alerts
if(model.getTaskIdentifier() != null) {
List<Date> alerts = alertController.getTaskAlerts(this,
model.getTaskIdentifier());
for(Date alert : alerts) {
addAlert(alert);
}
}
}
private void save() {
@ -186,7 +227,7 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
model.setDefiniteDueDate(definiteDueDate.getDate());
model.setPreferredDueDate(preferredDueDate.getDate());
model.setHiddenUntil(hiddenUntil.getDate());
// model.setBlockingOn(blockingOn.getBlockingOn());
model.setNotificationFlags(flags.getValue());
model.setNotes(notes.getText().toString());
model.setNotificationIntervalSeconds(notification.getTimeDurationInSeconds());
@ -194,12 +235,11 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
// write out to database
controller.saveTask(model);
saveTags();
saveAlerts();
Notifications.updateAlarm(this, controller, alertController, model);
} catch (Exception e) {
showErrorAndFinish(R.string.error_saving, e);
Log.e("astrid", "Error saving", e);
}
// set up notification
Notifications.updateAlarm(this, model, true);
}
/** Save task tags. Must be called after task already has an ID */
@ -240,6 +280,17 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
tagController.addTag(model.getTaskIdentifier(), tagId);
}
private void saveAlerts() {
alertController.removeAlerts(model.getTaskIdentifier());
for(int i = 0; i < alertsContainer.getChildCount(); i++) {
DateControlSet dateControlSet = (DateControlSet)alertsContainer.
getChildAt(i).getTag();
Date date = dateControlSet.getDate();
alertController.addAlert(model.getTaskIdentifier(), date);
}
}
/* ======================================================================
* ==================================================== UI initialization
* ====================================================================== */
@ -263,15 +314,16 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
notification = new TimeDurationControlSet(this, R.id.notification,
R.string.notification_prefix, R.string.notification_dialog,
TimeDurationType.DAYS_HOURS);
definiteDueDate = new DateControlSet(this, R.id.definiteDueDate_notnull,
definiteDueDate = new DateWithNullControlSet(this, R.id.definiteDueDate_notnull,
R.id.definiteDueDate_date, R.id.definiteDueDate_time);
preferredDueDate = new DateControlSet(this, R.id.preferredDueDate_notnull,
preferredDueDate = new DateWithNullControlSet(this, R.id.preferredDueDate_notnull,
R.id.preferredDueDate_date, R.id.preferredDueDate_time);
hiddenUntil = new DateControlSet(this, R.id.hiddenUntil_notnull,
hiddenUntil = new DateWithNullControlSet(this, R.id.hiddenUntil_notnull,
R.id.hiddenUntil_date, R.id.hiddenUntil_time);
notes = (EditText)findViewById(R.id.notes);
// blockingOn = new BlockingOnControlSet(R.id.blockingOn_notnull,
// R.id.blockingon);
flags = new NotificationFlagControlSet(R.id.flag_before,
R.id.flag_during, R.id.flag_after);
alertsContainer = (LinearLayout)findViewById(R.id.alert_container);
// individual ui component initialization
ImportanceAdapter importanceAdapter = new ImportanceAdapter(this,
@ -307,6 +359,40 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
}
});
}
Button addAlertButton = (Button) findViewById(R.id.addAlert);
addAlertButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
addAlert(null);
}
});
}
/** Adds an alert to the alert field */
private boolean addAlert(Date alert) {
if(alertsContainer.getChildCount() >= MAX_ALERTS)
return false;
LayoutInflater inflater = getLayoutInflater();
final View alertItem = inflater.inflate(R.layout.edit_alert_item, null);
alertsContainer.addView(alertItem);
DateControlSet dcs = new DateControlSet(this,
(Button)alertItem.findViewById(R.id.date),
(Button)alertItem.findViewById(R.id.time));
alertItem.setTag(dcs);
ImageButton reminderRemoveButton;
reminderRemoveButton = (ImageButton)alertItem.findViewById(R.id.button1);
reminderRemoveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
alertsContainer.removeView(alertItem);
}
});
return true;
}
/** Adds a tag to the tag field */
@ -437,6 +523,10 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
protected void onSaveInstanceState(Bundle outState) {
save();
super.onSaveInstanceState(outState);
Bundle extras = getIntent().getExtras();
if(extras != null && extras.containsKey(TAG_NAME_TOKEN))
outState.putString(TAG_NAME_TOKEN,
extras.getString(TAG_NAME_TOKEN));
}
@Override
@ -514,6 +604,39 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
}
}
/** Control set dealing with notification flags */
public class NotificationFlagControlSet {
private CheckBox before, during, after;
public NotificationFlagControlSet(int beforeId, int duringId,
int afterId) {
before = (CheckBox)findViewById(beforeId);
during = (CheckBox)findViewById(duringId);
after = (CheckBox)findViewById(afterId);
}
public void setValue(int flags) {
before.setChecked((flags &
TaskModelForEdit.NOTIFY_BEFORE_DEADLINE) > 0);
during.setChecked((flags &
TaskModelForEdit.NOTIFY_AT_DEADLINE) > 0);
after.setChecked((flags &
TaskModelForEdit.NOTIFY_AFTER_DEADLINE) > 0);
}
public int getValue() {
int value = 0;
if(before.isChecked())
value |= TaskModelForEdit.NOTIFY_BEFORE_DEADLINE;
if(during.isChecked())
value |= TaskModelForEdit.NOTIFY_AT_DEADLINE;
if(after.isChecked())
value |= TaskModelForEdit.NOTIFY_AFTER_DEADLINE;
return value;
}
}
/** Control set dealing with "blocking on" */
public class BlockingOnControlSet {
private CheckBox activatedCheckBox;

@ -78,8 +78,6 @@ public abstract class TaskModificationActivity<MODEL_TYPE extends
abstract protected MODEL_TYPE getModel(TaskIdentifier identifier);
@Override
protected void onDestroy() {
super.onDestroy();

@ -0,0 +1,92 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.activities;
import android.app.TabActivity;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import com.timsu.astrid.R;
import com.timsu.astrid.data.task.AbstractTaskModel;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.utilities.DialogUtilities;
/** Hack hack for tabbed activity. Should provide better interaction
*
* @author timsu
*/
public abstract class TaskModificationTabbedActivity<MODEL_TYPE extends
AbstractTaskModel> extends TabActivity {
protected static final String LOAD_INSTANCE_TOKEN = TaskModificationActivity.LOAD_INSTANCE_TOKEN;
protected TaskController controller;
protected MODEL_TYPE model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
controller = new TaskController(this);
controller.open();
try {
// check if we have a TaskIdentifier
TaskIdentifier identifier = null;
Bundle extras = getIntent().getExtras();
if(savedInstanceState != null && savedInstanceState.containsKey(LOAD_INSTANCE_TOKEN)) {
identifier = new TaskIdentifier(savedInstanceState.getLong(
LOAD_INSTANCE_TOKEN));
} else if(extras != null && extras.containsKey(LOAD_INSTANCE_TOKEN))
identifier = new TaskIdentifier(extras.getLong(
LOAD_INSTANCE_TOKEN));
model = getModel(identifier);
} catch (Exception e) {
showErrorAndFinish(R.string.error_opening, e);
}
}
protected void showErrorAndFinish(int prefix, Throwable e) {
Resources r = getResources();
DialogUtilities.okDialog(this,
r.getString(prefix) + " " +
e.getLocalizedMessage(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
}
abstract protected MODEL_TYPE getModel(TaskIdentifier identifier);
@Override
protected void onDestroy() {
super.onDestroy();
controller.close();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(model.getTaskIdentifier() != null)
outState.putLong(LOAD_INSTANCE_TOKEN, model.getTaskIdentifier().getId());
}
}

@ -31,7 +31,6 @@ public class TaskViewNotifier extends TaskView {
// clear notifications
Notifications.clearAllNotifications(this, model.getTaskIdentifier());
Notifications.updateAlarm(this, model, true);
String[] responses = r.getStringArray(R.array.reminder_responses);
String response = responses[new Random().nextInt(responses.length)];

@ -39,6 +39,7 @@ abstract public class AbstractController {
protected static final String TASK_TABLE_NAME = "tasks";
protected static final String TAG_TABLE_NAME = "tags";
protected static final String TAG_TASK_MAP_NAME = "tagTaskMap";
protected static final String ALERT_TABLE_NAME = "alerts";
// cursor iterator

@ -0,0 +1,133 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.alerts;
import java.util.Date;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.AbstractModel;
import com.timsu.astrid.data.task.TaskIdentifier;
/** A single tag on a task */
public class Alert extends AbstractModel {
/** Version number of this model */
static final int VERSION = 1;
// field names
static final String TASK = "task";
static final String DATE = "date";
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
@Override
public ContentValues getDefaultValues() {
return defaultValues;
}
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
TASK,
DATE,
};
// --- database helper
/** Database Helper manages creating new tables and updating old ones */
static class AlertDatabaseHelper extends SQLiteOpenHelper {
String tableName;
AlertDatabaseHelper(Context context, String databaseName, String tableName) {
super(context, databaseName, null, VERSION);
this.tableName = tableName;
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = new StringBuilder().
append("CREATE TABLE ").append(tableName).append(" (").
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
append(TASK).append(" integer not null,").
append(DATE).append(" integer not null,").
append("unique (").append(TASK).append(",").append(DATE).append(")").
append(");").toString();
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
oldVersion + " to " + newVersion + ".");
switch(oldVersion) {
default:
// we don't know how to handle it... do the unfortunate thing
Log.e(getClass().getSimpleName(), "Unsupported migration, table dropped!");
db.execSQL("DROP TABLE IF EXISTS " + tableName);
onCreate(db);
}
}
}
// --- constructor pass-through
Alert(TaskIdentifier task, Date date) {
super();
setTask(task);
setDate(date);
}
public Alert(Cursor cursor) {
super(cursor);
}
// --- getters and setters: expose them as you see fit
public boolean isNew() {
return getCursor() == null;
}
public TaskIdentifier getTask() {
return new TaskIdentifier(retrieveInteger(TASK));
}
public Date getDate() {
return new Date(retrieveLong(DATE));
}
private void setTask(TaskIdentifier task) {
setValues.put(TASK, task.getId());
}
private void setDate(Date date) {
setValues.put(DATE, date.getTime());
}
}

@ -0,0 +1,117 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.data.alerts;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.Alert.AlertDatabaseHelper;
import com.timsu.astrid.data.task.TaskIdentifier;
/** Controller for Tag-related operations */
public class AlertController extends AbstractController {
private SQLiteDatabase alertDatabase;
/** Get a cursor to tag identifiers */
public Cursor getTaskAlertsCursor(TaskIdentifier taskId) throws SQLException {
Cursor cursor = alertDatabase.query(ALERT_TABLE_NAME,
Alert.FIELD_LIST, Alert.TASK + " = ?",
new String[] { taskId.idAsString() }, null, null, null);
return cursor;
}
/** Get a list of tag identifiers for the given task */
public List<Date> getTaskAlerts(Activity activity, TaskIdentifier
taskId) throws SQLException {
List<Date> list = new LinkedList<Date>();
Cursor cursor = alertDatabase.query(ALERT_TABLE_NAME,
Alert.FIELD_LIST, Alert.TASK + " = ?",
new String[] { taskId.idAsString() }, null, null, null);
activity.startManagingCursor(cursor);
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new Alert(cursor).getDate());
} while(!cursor.isLast());
return list;
}
/** Remove all alerts from the task */
public boolean removeAlerts(TaskIdentifier taskId)
throws SQLException{
return alertDatabase.delete(ALERT_TABLE_NAME,
String.format("%s = ?",
Alert.TASK),
new String[] { taskId.idAsString() }) > 0;
}
/** Add the given tag to the task */
public boolean addAlert(TaskIdentifier taskId, Date date)
throws SQLException {
ContentValues values = new ContentValues();
values.put(Alert.DATE, date.getTime());
values.put(Alert.TASK, taskId.getId());
return alertDatabase.insert(ALERT_TABLE_NAME, Alert.TASK,
values) >= 0;
}
// --- boilerplate
/**
* Constructor - takes the context to allow the database to be
* opened/created
*/
public AlertController(Context context) {
this.context = context;
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
public AlertController open() throws SQLException {
alertDatabase = new AlertDatabaseHelper(context,
ALERT_TABLE_NAME, ALERT_TABLE_NAME).getWritableDatabase();
return this;
}
/** Closes database resource */
public void close() {
alertDatabase.close();
}
}

@ -43,31 +43,38 @@ import com.timsu.astrid.data.enums.Importance;
public abstract class AbstractTaskModel extends AbstractModel {
/** Version number of this model */
static final int VERSION = 1;
static final int VERSION = 2;
public static final int COMPLETE_PERCENTAGE = 100;
public static final int COMPLETE_PERCENTAGE = 100;
// field names
static final String NAME = "name";
static final String NOTES = "notes";
static final String PROGRESS_PERCENTAGE = "progressPercentage";
static final String IMPORTANCE = "importance";
static final String ESTIMATED_SECONDS = "estimatedSeconds";
static final String ELAPSED_SECONDS = "elapsedSeconds";
static final String TIMER_START = "timerStart";
static final String DEFINITE_DUE_DATE = "definiteDueDate";
static final String PREFERRED_DUE_DATE = "preferredDueDate";
static final String HIDDEN_UNTIL = "hiddenUntil";
static final String NAME = "name";
static final String NOTES = "notes";
static final String PROGRESS_PERCENTAGE = "progressPercentage";
static final String IMPORTANCE = "importance";
static final String ESTIMATED_SECONDS = "estimatedSeconds";
static final String ELAPSED_SECONDS = "elapsedSeconds";
static final String TIMER_START = "timerStart";
static final String DEFINITE_DUE_DATE = "definiteDueDate";
static final String PREFERRED_DUE_DATE = "preferredDueDate";
static final String HIDDEN_UNTIL = "hiddenUntil";
static final String NOTIFICATIONS = "notifications";
static final String NOTIFICATION_FLAGS = "notificationFlags";
static final String LAST_NOTIFIED = "lastNotified";
// reserved fields
static final String BLOCKING_ON = "blockingOn";
static final String NOTIFICATIONS = "notifications";
static final String BLOCKING_ON = "blockingOn";
// end reserved fields
static final String CREATION_DATE = "creationDate";
static final String COMPLETION_DATE = "completionDate";
static final String CREATION_DATE = "creationDate";
static final String COMPLETION_DATE = "completionDate";
// notification flags
public static final int NOTIFY_BEFORE_DEADLINE = 1;
public static final int NOTIFY_AT_DEADLINE = 2;
public static final int NOTIFY_AFTER_DEADLINE = 4;
/** Default values container */
private static final ContentValues defaultValues = new ContentValues();
private static final ContentValues defaultValues = new ContentValues();
static {
defaultValues.put(NAME, "");
@ -82,6 +89,8 @@ public abstract class AbstractTaskModel extends AbstractModel {
defaultValues.put(HIDDEN_UNTIL, (Long)null);
defaultValues.put(BLOCKING_ON, (Long)null);
defaultValues.put(NOTIFICATIONS, 0);
defaultValues.put(NOTIFICATION_FLAGS, NOTIFY_AT_DEADLINE);
defaultValues.put(LAST_NOTIFIED, (Long)null);
defaultValues.put(COMPLETION_DATE, (Long)null);
}
@ -98,7 +107,6 @@ public abstract class AbstractTaskModel extends AbstractModel {
TaskModelDatabaseHelper(Context context, String databaseName, String tableName) {
super(context, databaseName, null, VERSION);
this.tableName = tableName;
}
@ -119,6 +127,8 @@ public abstract class AbstractTaskModel extends AbstractModel {
append(HIDDEN_UNTIL).append(" integer,").
append(BLOCKING_ON).append(" integer,").
append(NOTIFICATIONS).append(" integer,").
append(NOTIFICATION_FLAGS).append(" integer,").
append(LAST_NOTIFIED).append(" integer,").
append(CREATION_DATE).append(" integer,").
append(COMPLETION_DATE).append(" integer").
append(");").toString();
@ -126,11 +136,23 @@ public abstract class AbstractTaskModel extends AbstractModel {
}
@Override
@SuppressWarnings("fallthrough")
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
oldVersion + " to " + newVersion + ".");
switch(oldVersion) {
case 1:
String sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(LAST_NOTIFIED).append(" integer").toString();
db.execSQL(sql);
sql = new StringBuilder().append("ALTER TABLE ").
append(tableName).append(" ADD COLUMN ").
append(NOTIFICATION_FLAGS).append(" integer").toString();
db.execSQL(sql);
break;
default:
// we don't know how to handle it... do the unfortunate thing
Log.e(getClass().getSimpleName(), "Unsupported migration, table dropped!");
@ -306,6 +328,14 @@ public abstract class AbstractTaskModel extends AbstractModel {
return retrieveInteger(NOTIFICATIONS);
}
protected int getNotificationFlags() {
return retrieveInteger(NOTIFICATION_FLAGS);
}
protected Date getLastNotificationDate() {
return retrieveDate(LAST_NOTIFIED);
}
// --- setters
protected void setName(String name) {
@ -371,6 +401,14 @@ public abstract class AbstractTaskModel extends AbstractModel {
putIfChangedFromDatabase(NOTIFICATIONS, intervalInSeconds);
}
protected void setNotificationFlags(int flags) {
putIfChangedFromDatabase(NOTIFICATION_FLAGS, flags);
}
protected void setLastNotificationTime(Date date) {
putDate(LAST_NOTIFIED, date);
}
// --- utility methods
protected void putDate(String fieldName, Date date) {

@ -20,6 +20,7 @@
package com.timsu.astrid.data.task;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.app.Activity;
@ -176,6 +177,14 @@ public class TaskController extends AbstractController {
return saveSucessful;
}
/** Set last notification date */
public boolean setLastNotificationTime(TaskIdentifier taskId, Date date) {
ContentValues values = new ContentValues();
values.put(AbstractTaskModel.LAST_NOTIFIED, date.getTime());
return database.update(TASK_TABLE_NAME, values,
KEY_ROWID + "=" + taskId.getId(), null) > 0;
}
// --- fetching different models
/** Creates a new task and returns the task identifier */
@ -239,6 +248,23 @@ public class TaskController extends AbstractController {
throw new SQLException("Returned empty set!");
}
/** Returns a TaskModelForView corresponding to the given TaskIdentifier */
public TaskModelForNotify fetchTaskForNotify(TaskIdentifier taskId) throws SQLException {
long id = taskId.getId();
Cursor cursor = database.query(true, TASK_TABLE_NAME,
TaskModelForNotify.FIELD_LIST,
KEY_ROWID + "=" + id, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
TaskModelForNotify model = new TaskModelForNotify(cursor);
cursor.close();
return model;
}
throw new SQLException("Returned empty set!");
}
// --- boilerplate
/**

@ -41,6 +41,7 @@ public class TaskModelForEdit extends AbstractTaskModel implements Notifiable {
HIDDEN_UNTIL,
BLOCKING_ON,
NOTIFICATIONS,
NOTIFICATION_FLAGS,
PROGRESS_PERCENTAGE,
NOTES,
};
@ -118,6 +119,16 @@ public class TaskModelForEdit extends AbstractTaskModel implements Notifiable {
return super.getBlockingOn();
}
@Override
public int getNotificationFlags() {
return super.getNotificationFlags();
}
@Override
public Date getLastNotificationDate() {
return super.getLastNotificationDate();
}
@Override
public void setDefiniteDueDate(Date definiteDueDate) {
super.setDefiniteDueDate(definiteDueDate);
@ -162,4 +173,10 @@ public class TaskModelForEdit extends AbstractTaskModel implements Notifiable {
public void setBlockingOn(TaskIdentifier blockingOn) {
super.setBlockingOn(blockingOn);
}
@Override
public void setNotificationFlags(int flags) {
super.setNotificationFlags(flags);
}
}

@ -33,7 +33,10 @@ public class TaskModelForNotify extends AbstractTaskModel implements Notifiable
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
ESTIMATED_SECONDS,
NOTIFICATIONS,
NOTIFICATION_FLAGS,
LAST_NOTIFIED,
HIDDEN_UNTIL,
PROGRESS_PERCENTAGE,
DEFINITE_DUE_DATE,
@ -48,7 +51,12 @@ public class TaskModelForNotify extends AbstractTaskModel implements Notifiable
prefetchData(FIELD_LIST);
}
// --- getters and setters
// --- getters
@Override
public Integer getEstimatedSeconds() {
return super.getEstimatedSeconds();
}
@Override
public boolean isTaskCompleted() {
@ -74,4 +82,21 @@ public class TaskModelForNotify extends AbstractTaskModel implements Notifiable
public Date getPreferredDueDate() {
return super.getPreferredDueDate();
}
@Override
public int getNotificationFlags() {
return super.getNotificationFlags();
}
@Override
public Date getLastNotificationDate() {
return super.getLastNotificationDate();
}
// --- setters
@Override
public void setLastNotificationTime(Date date) {
super.setLastNotificationTime(date);
}
}

@ -25,12 +25,11 @@ import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.enums.Importance;
import com.timsu.astrid.utilities.Notifications.Notifiable;
/** Fields that you would want to see in the TaskView activity */
public class TaskModelForView extends AbstractTaskModel implements Notifiable {
public class TaskModelForView extends AbstractTaskModel {
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
@ -44,7 +43,6 @@ public class TaskModelForView extends AbstractTaskModel implements Notifiable {
PREFERRED_DUE_DATE,
HIDDEN_UNTIL,
CREATION_DATE,
NOTIFICATIONS,
NOTES,
};

@ -1,5 +0,0 @@
package com.timsu.astrid.data.task;
public class VisibilityProperty {
}

@ -13,10 +13,13 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.activities.TaskViewNotifier;
import com.timsu.astrid.data.alerts.Alert;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForList;
@ -28,25 +31,18 @@ public class Notifications extends BroadcastReceiver {
private static final String FLAGS_KEY = "flags";
// stuff for scheduling
private static final int MIN_INTERVAL_SECONDS = 300;
private static final float FUDGE_MIN = -0.5f;
private static final float FUDGE_MAX = 0.5f;
/** # of seconds before a deadline to notify */
/** min # of seconds before a deadline to notify */
private static final int DEADLINE_NOTIFY_SECS = 3600;
/** # of seconds after now, if a deadline is in the past */
private static final int TIME_IN_PAST_OFFSET = 120;
/** # of seconds after first deadline reminder to repeat */
private static final int DEADLINE_REPEAT = 600;
/** Minimum number of seconds before you see a notification on something
* you just touched */
private static final int SNOOZE_TIME = 600;
/** # of seconds after deadline to repeat */
private static final int DEADLINE_REPEAT = 300;
// flags
public static final int FLAG_DEFINITE_DEADLINE = 1;
public static final int FLAG_PREFERRED_DEADLINE = 2;
public static final int FLAG_OVERDUE = 4;
private static Random random = new Random();
private static boolean alarmsSet = false;
/** Something we can create a notification for */
public interface Notifiable {
@ -56,6 +52,9 @@ public class Notifications extends BroadcastReceiver {
public Date getHiddenUntil();
public Date getDefiniteDueDate();
public Date getPreferredDueDate();
public Date getLastNotificationDate();
public int getNotificationFlags();
public Integer getEstimatedSeconds();
}
@Override
@ -88,26 +87,25 @@ public class Notifications extends BroadcastReceiver {
if(task.isTaskCompleted())
return true;
if(task.getNotificationIntervalSeconds() == 0)
return true;
return false;
}
public static void scheduleAllAlarms(Context context) {
TaskController controller = new TaskController(context);
controller.open();
List<TaskModelForNotify> tasks = controller.getTasksWithNotifications();
TaskController taskController = new TaskController(context);
taskController.open();
AlertController alertController = new AlertController(context);
alertController.open();
List<TaskModelForNotify> tasks = taskController.getTasksWithNotifications();
for(TaskModelForNotify task : tasks)
updateAlarm(context, task, false);
alarmsSet = true;
controller.close();
updateAlarm(context, taskController, alertController, task);
alertController.close();
taskController.close();
}
/** Schedules the next notification for this task */
public static void updateAlarm(Context context, Notifiable task,
boolean shouldSnooze) {
public static void updateAlarm(Context context, TaskController taskController,
AlertController alertController, Notifiable task) {
if(task.getTaskIdentifier() == null)
return;
@ -116,63 +114,74 @@ public class Notifications extends BroadcastReceiver {
return;
}
Long when = null; // when to schedule alarm (ms)
Integer interval = null; // how often to repeat (s)
// periodic reminders
if(task.getNotificationIntervalSeconds() > 0) {
// compute, and add a fudge factor to mix things up a bit
interval = task.getNotificationIntervalSeconds();
int currentSeconds = (int)(System.currentTimeMillis() / 1000);
int untilNextInterval = interval - currentSeconds % interval;
untilNextInterval += interval * (FUDGE_MIN + random.nextFloat()
* (FUDGE_MAX - FUDGE_MIN));
if(untilNextInterval < MIN_INTERVAL_SECONDS)
untilNextInterval = MIN_INTERVAL_SECONDS;
when = System.currentTimeMillis() + untilNextInterval * 1000;
long interval = task.getNotificationIntervalSeconds() * 1000;
long when;
// get or make up a last notification time
if(task.getLastNotificationDate() == null) {
when = System.currentTimeMillis() +
(long)(interval * random.nextFloat());
taskController.setLastNotificationTime(task.getTaskIdentifier(),
new Date(when));
} else {
when = task.getLastNotificationDate().getTime();
}
if(when < System.currentTimeMillis())
when += ((System.currentTimeMillis() - when)/interval + 1) * interval;
scheduleRepeatingAlarm(context, task.getTaskIdentifier().getId(),
when, 0, interval);
}
// if deadlines come before, do that instead
int flags = 0;
if(task.getDefiniteDueDate() != null) {
long deadlineWhen = task.getDefiniteDueDate().getTime() -
DEADLINE_NOTIFY_SECS * 1000;
if(when == null || deadlineWhen < when) {
when = deadlineWhen;
interval = DEADLINE_REPEAT;
flags = FLAG_DEFINITE_DEADLINE;
}
// before, during, and after deadlines
int estimatedDuration = DEADLINE_NOTIFY_SECS;
if(task.getEstimatedSeconds() != null && task.getEstimatedSeconds() > DEADLINE_NOTIFY_SECS)
estimatedDuration = (int)(task.getEstimatedSeconds() * 1.5f);
if((task.getNotificationFlags() & TaskModelForList.NOTIFY_BEFORE_DEADLINE) > 0) {
scheduleDeadline(context, task.getDefiniteDueDate(), -estimatedDuration,
0, FLAG_DEFINITE_DEADLINE, task);
scheduleDeadline(context, task.getPreferredDueDate(), -estimatedDuration,
0, FLAG_PREFERRED_DEADLINE, task);
}
// for goal deadlines, once it's overdue, forget about it.
if(task.getPreferredDueDate() != null &&
task.getPreferredDueDate().getTime() > System.currentTimeMillis()) {
long deadlineWhen = task.getPreferredDueDate().getTime() -
DEADLINE_NOTIFY_SECS * 1000;
if(when == null || deadlineWhen < when) {
when = deadlineWhen;
interval = DEADLINE_REPEAT;
flags = FLAG_PREFERRED_DEADLINE;
}
if((task.getNotificationFlags() & TaskModelForList.NOTIFY_AT_DEADLINE) > 0) {
scheduleDeadline(context, task.getDefiniteDueDate(), 0,
0, FLAG_DEFINITE_DEADLINE | FLAG_OVERDUE, task);
scheduleDeadline(context, task.getPreferredDueDate(), 0,
0, FLAG_PREFERRED_DEADLINE | FLAG_OVERDUE, task);
}
if((task.getNotificationFlags() & TaskModelForList.NOTIFY_AFTER_DEADLINE) > 0) {
scheduleDeadline(context, task.getDefiniteDueDate(), DEADLINE_REPEAT,
DEADLINE_REPEAT, FLAG_DEFINITE_DEADLINE | FLAG_OVERDUE,
task);
}
if(when == null) {
deleteAlarm(context, task.getTaskIdentifier().getId());
return;
// fixed alerts
Cursor cursor = alertController.getTaskAlertsCursor(task.getTaskIdentifier());
while(!cursor.isLast()) {
cursor.moveToNext();
Date alert = new Alert(cursor).getDate();
scheduleAlarm(context, task.getTaskIdentifier().getId(),
alert.getTime(), 0);
}
cursor.close();
}
private static void scheduleDeadline(Context context, Date deadline, int
offsetSeconds, int intervalSeconds, int flags, Notifiable task) {
if(deadline == null)
return;
long when = deadline.getTime() + offsetSeconds * 1000;
if(when < System.currentTimeMillis() && intervalSeconds == 0)
return;
// snooze if the user just interacted with this item
if(shouldSnooze) {
long snoozeWhen = System.currentTimeMillis() +
SNOOZE_TIME * 1000;
if(when < snoozeWhen)
when = snoozeWhen;
} else if(when < System.currentTimeMillis())
when = System.currentTimeMillis() + TIME_IN_PAST_OFFSET*1000;
if(interval == null)
scheduleAlarm(context, task.getTaskIdentifier().getId(), when, flags);
if (intervalSeconds == 0)
scheduleAlarm(context, task.getTaskIdentifier().getId(), when,
flags);
else
scheduleRepeatingAlarm(context, task.getTaskIdentifier().getId(),
when, flags, interval*1000);
when, flags, intervalSeconds * 1000);
}
private static PendingIntent createPendingIntent(Context context,
@ -208,9 +217,12 @@ public class Notifications extends BroadcastReceiver {
/** Schedules a recurring alarm for a single task */
public static void scheduleRepeatingAlarm(Context context, long id, long when,
int flags, long interval) {
if(when < System.currentTimeMillis())
return;
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Log.e("ALARM", "Alarm set for " + new Date(when) + " every " + interval);
Log.e("ALARM", "Alarm set for " + new Date(when) + " every " + interval/1000 + " s");
am.setRepeating(AlarmManager.RTC_WAKEUP, when, interval,
createPendingIntent(context, id, flags));
}
@ -233,22 +245,8 @@ public class Notifications extends BroadcastReceiver {
/** Schedule a new notification about the given task. Returns false if there was
* some sort of error or the alarm should be disabled. */
public static boolean showNotification(Context context, long id, int flags,
String reminder) {
// quiet hours?
Integer quietHoursStart = Preferences.getQuietHourStart(context);
Integer quietHoursEnd = Preferences.getQuietHourEnd(context);
if(quietHoursStart != null && quietHoursEnd != null) {
int hour = new Date().getHours();
if(quietHoursStart < quietHoursEnd) {
if(hour >= quietHoursStart && hour < quietHoursEnd)
return true;
} else { // wrap across 24/hour boundary
if(hour >= quietHoursStart || hour < quietHoursEnd)
return true;
}
}
public static boolean showNotification(Context context, long id,
int flags, String reminder) {
String taskName;
TaskController controller = new TaskController(context);
@ -270,6 +268,8 @@ public class Notifications extends BroadcastReceiver {
taskName = task.getName();
controller.setLastNotificationTime(task.getTaskIdentifier(), new Date());
} catch (Exception e) {
// task could be deleted, for example
Log.e(Notifications.class.getSimpleName(),
@ -279,6 +279,21 @@ public class Notifications extends BroadcastReceiver {
controller.close();
}
// quiet hours?
boolean quietHours = false;
Integer quietHoursStart = Preferences.getQuietHourStart(context);
Integer quietHoursEnd = Preferences.getQuietHourEnd(context);
if(quietHoursStart != null && quietHoursEnd != null) {
int hour = new Date().getHours();
if(quietHoursStart < quietHoursEnd) {
if(hour >= quietHoursStart && hour < quietHoursEnd)
quietHours = true;
} else { // wrap across 24/hour boundary
if(hour >= quietHoursStart || hour < quietHoursEnd)
quietHours = true;
}
}
NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources r = context.getResources();
@ -289,21 +304,21 @@ public class Notifications extends BroadcastReceiver {
notifyIntent.putExtra(TaskViewNotifier.FROM_NOTIFICATION_TOKEN, true);
notifyIntent.putExtra(TaskViewNotifier.NOTIF_FLAGS_TOKEN, flags);
PendingIntent pendingIntent = PendingIntent.getActivity(context,
0, notifyIntent, PendingIntent.FLAG_ONE_SHOT);
(int)id, notifyIntent, PendingIntent.FLAG_ONE_SHOT);
// notification text
// create notification object
String appName = r.getString(R.string.app_name);
Notification notification = new Notification(
android.R.drawable.stat_notify_chat, reminder,
System.currentTimeMillis());
notification.setLatestEventInfo(context,
appName,
reminder + " " + taskName,
pendingIntent);
notification.defaults = Notification.DEFAULT_ALL;
if(!quietHours)
notification.defaults = 0;
else
notification.defaults = Notification.DEFAULT_ALL;
Log.w("Notifications", "Logging notification: " + reminder);
nm.notify((int)id, notification);

@ -30,11 +30,8 @@ import android.app.DatePickerDialog.OnDateSetListener;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.TimePicker;
import android.widget.CompoundButton.OnCheckedChangeListener;
public class DateControlSet implements OnTimeSetListener,
OnDateSetListener, View.OnClickListener {
@ -42,34 +39,27 @@ public class DateControlSet implements OnTimeSetListener,
private static final Format dateFormatter = new SimpleDateFormat("EEE, MMM d, yyyy");
private static final Format timeFormatter = new SimpleDateFormat("h:mm a");
private final Activity activity;
private CheckBox activatedCheckBox;
private Button dateButton;
private Button timeButton;
private Date date;
protected final Activity activity;
protected Button dateButton;
protected Button timeButton;
protected Date date;
public DateControlSet(Activity activity, int checkBoxId, int dateButtonId, int timeButtonId) {
protected DateControlSet(Activity activity) {
this.activity = activity;
activatedCheckBox = (CheckBox)activity.findViewById(checkBoxId);
dateButton = (Button)activity.findViewById(dateButtonId);
timeButton = (Button)activity.findViewById(timeButtonId);
activatedCheckBox.setOnCheckedChangeListener(
new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
dateButton.setEnabled(isChecked);
timeButton.setEnabled(isChecked);
}
});
}
public DateControlSet(Activity activity, Button dateButton, Button timeButton) {
this.activity = activity;
this.dateButton = dateButton;
this.timeButton = timeButton;
dateButton.setOnClickListener(this);
timeButton.setOnClickListener(this);
setDate(null);
}
public Date getDate() {
if(!activatedCheckBox.isChecked())
return null;
return date;
}
@ -82,10 +72,6 @@ public class DateControlSet implements OnTimeSetListener,
date.setMinutes(0);
}
activatedCheckBox.setChecked(newDate != null);
dateButton.setEnabled(newDate != null);
timeButton.setEnabled(newDate != null);
updateDate();
updateTime();
}

@ -0,0 +1,70 @@
/*
* ASTRID: Android's Simple Task Recording Dashboard
*
* Copyright (c) 2009 Tim Su
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.timsu.astrid.widget;
import java.util.Date;
import android.app.Activity;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
/** Date Control Set with an "enabled" checkbox" to toggle date / null */
public class DateWithNullControlSet extends DateControlSet {
private CheckBox activatedCheckBox;
public DateWithNullControlSet(Activity activity, int checkBoxId, int dateButtonId, int timeButtonId) {
super(activity);
activatedCheckBox = (CheckBox)activity.findViewById(checkBoxId);
dateButton = (Button)activity.findViewById(dateButtonId);
timeButton = (Button)activity.findViewById(timeButtonId);
activatedCheckBox.setOnCheckedChangeListener(
new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
dateButton.setEnabled(isChecked);
timeButton.setEnabled(isChecked);
}
});
dateButton.setOnClickListener(this);
timeButton.setOnClickListener(this);
}
@Override
public Date getDate() {
if(!activatedCheckBox.isChecked())
return null;
return super.getDate();
}
/** Initialize the components for the given date field */
@Override
public void setDate(Date newDate) {
activatedCheckBox.setChecked(newDate != null);
dateButton.setEnabled(newDate != null);
timeButton.setEnabled(newDate != null);
super.setDate(newDate);
}
}
Loading…
Cancel
Save