@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="lib" path="lib/android-src.jar"/>
|
||||
<classpathentry kind="lib" path="lib/android.jar" sourcepath="/home/timsu/projects/android-astrid/lib/android-src.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>astrid</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -0,0 +1,60 @@
|
||||
#Wed Dec 17 03:02:43 PST 2008
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.timsu.astrid"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0.0">
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
|
||||
<activity android:name=".activities.TaskList"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".activities.TaskView"/>
|
||||
|
||||
<activity android:name=".activities.TaskEdit"/>
|
||||
|
||||
</application>
|
||||
</manifest>
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 203 B |
@ -0,0 +1,30 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="false" android:state_enabled="true"
|
||||
android:state_focused="false" android:drawable="@drawable/timepicker_down_normal" />
|
||||
<item android:state_pressed="true" android:state_enabled="true"
|
||||
android:drawable="@drawable/timepicker_down_pressed" />
|
||||
<item android:state_pressed="false" android:state_enabled="true"
|
||||
android:state_focused="true" android:drawable="@drawable/timepicker_down_selected" />
|
||||
<item android:state_pressed="false" android:state_enabled="false"
|
||||
android:state_focused="false" android:drawable="@drawable/timepicker_down_disabled" />
|
||||
<item android:state_pressed="false" android:state_enabled="false"
|
||||
android:state_focused="true" android:drawable="@drawable/timepicker_down_disabled_focused" />
|
||||
|
||||
</selector>
|
After Width: | Height: | Size: 956 B |
After Width: | Height: | Size: 938 B |
After Width: | Height: | Size: 884 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,30 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="false" android:state_enabled="true"
|
||||
android:state_focused="false" android:drawable="@drawable/timepicker_input_normal" />
|
||||
<item android:state_pressed="true" android:state_enabled="true"
|
||||
android:drawable="@drawable/timepicker_input_pressed" />
|
||||
<item android:state_pressed="false" android:state_enabled="true"
|
||||
android:state_focused="true" android:drawable="@drawable/timepicker_input_selected" />
|
||||
<item android:state_pressed="false" android:state_enabled="false"
|
||||
android:state_focused="false" android:drawable="@drawable/timepicker_input_disabled" />
|
||||
<item android:state_pressed="false" android:state_enabled="false"
|
||||
android:state_focused="true" android:drawable="@drawable/timepicker_input_normal" />
|
||||
|
||||
</selector>
|
After Width: | Height: | Size: 484 B |
After Width: | Height: | Size: 567 B |
After Width: | Height: | Size: 593 B |
After Width: | Height: | Size: 578 B |
@ -0,0 +1,30 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="false" android:state_enabled="true"
|
||||
android:state_focused="false" android:drawable="@drawable/timepicker_up_normal" />
|
||||
<item android:state_pressed="true" android:state_enabled="true"
|
||||
android:drawable="@drawable/timepicker_up_pressed" />
|
||||
<item android:state_pressed="false" android:state_enabled="true"
|
||||
android:state_focused="true" android:drawable="@drawable/timepicker_up_selected" />
|
||||
<item android:state_pressed="false" android:state_enabled="false"
|
||||
android:state_focused="false" android:drawable="@drawable/timepicker_up_disabled" />
|
||||
<item android:state_pressed="false" android:state_enabled="false"
|
||||
android:state_focused="true" android:drawable="@drawable/timepicker_up_disabled_focused" />
|
||||
|
||||
</selector>
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_focused="true" android:state_pressed="false"
|
||||
android:drawable="@drawable/highlight_selected" />
|
||||
<item android:state_focused="true" android:state_pressed="true"
|
||||
android:drawable="@drawable/highlight_pressed" />
|
||||
<item android:state_focused="false" android:state_pressed="true"
|
||||
android:drawable="@drawable/highlight_pressed" />
|
||||
</selector>
|
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<com.timsu.astrid.widget.NumberPickerButton android:id="@+id/increment"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/timepicker_up_btn"
|
||||
/>
|
||||
|
||||
<EditText android:id="@+id/timepicker_input"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
style="?android:attr/textAppearanceLargeInverse"
|
||||
android:textSize="30sp"
|
||||
android:background="@drawable/timepicker_input"
|
||||
/>
|
||||
|
||||
<com.timsu.astrid.widget.NumberPickerButton android:id="@+id/decrement"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/timepicker_down_btn"
|
||||
/>
|
||||
|
||||
</merge>
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dip">
|
||||
<com.timsu.astrid.widget.NumberPicker android:id="@+id/numberPicker"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
</FrameLayout>
|
@ -0,0 +1,266 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
ASTRID: Android's Simple Task Recording Dame
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/scroll_view"
|
||||
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">
|
||||
|
||||
<!-- TASK NAME -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dip">
|
||||
|
||||
<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>
|
||||
|
||||
<!-- PROPERTIES -->
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark"
|
||||
/>
|
||||
|
||||
<LinearLayout android:id="@+id/properties_container"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dip">
|
||||
|
||||
<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/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/tags_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/tags_label"
|
||||
style="@style/TextAppearance.EditEvent_Label"/>
|
||||
|
||||
<LinearLayout android:id="@+id/tags_container"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</LinearLayout> -->
|
||||
</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"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dip">
|
||||
|
||||
<TextView android:id="@+id/definiteDueDate_label"
|
||||
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_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"/>
|
||||
|
||||
<Button android:id="@+id/preferredDueDate_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/hiddenUntil_label"
|
||||
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>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- TODO: blocking on -->
|
||||
|
||||
<!-- MISC FIELDS -->
|
||||
<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"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dip">
|
||||
|
||||
<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"/>
|
||||
|
||||
<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" />
|
||||
|
||||
|
||||
<TextView android:id="@+id/elapsedDuration_label"
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- SAVE -->
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dip"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<Button android:id="@+id/save"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/save_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"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/delete"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/delete_label"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout android:id="@+id/tasklist_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ListView android:id="@+id/tasklist"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<Button android:id="@+id/addtask"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:text="@string/addtask_label"/>
|
||||
</LinearLayout>
|
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout android:id="@+id/row_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:focusable="true"
|
||||
android:background="@drawable/transparent_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<CheckBox android:id="@+id/cb1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dip"/>
|
||||
|
||||
<ImageView android:id="@+id/image1"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:paddingLeft="5dip"/>
|
||||
|
||||
<TextView android:id="@+id/text1"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:layout_width="fill_parent"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="5dip"
|
||||
android:singleLine="true"/>
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,173 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout android:id="@+id/view_layout"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView android:id="@+id/name"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:textAppearance="?android:attr/textAppearanceLargeInverse"
|
||||
android:gravity="center_horizontal"
|
||||
android:padding="5dip"/>
|
||||
|
||||
<!-- Button Row -->
|
||||
<LinearLayout android:id="@+id/button_layout"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="15dip">
|
||||
|
||||
<Button android:id="@+id/timerButton"
|
||||
android:gravity="center"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/startTimer_label"/>
|
||||
|
||||
<Button android:id="@+id/progress"
|
||||
android:gravity="center"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5px" />
|
||||
|
||||
<Button android:id="@+id/edit"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/edit_label"/>
|
||||
|
||||
<!-- Elapsed Time -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5px"
|
||||
android:text="@string/taskView_elapsed"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
<TextView android:id="@+id/cell_elapsed"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:colorForeground="@color/view_table_values" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Estimated Time -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5px"
|
||||
android:src="@android:drawable/divider_horizontal_bright" />
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:text="@string/taskView_estimated"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
<TextView android:id="@+id/cell_estimated"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:colorForeground="@color/view_table_values" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Absolute Deadline -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5px"
|
||||
android:src="@android:drawable/divider_horizontal_bright" />
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:text="@string/taskView_definiteDueDate"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
<TextView android:id="@+id/cell_definiteDueDate"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:colorForeground="@color/view_table_values" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Goal Deadline -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5px"
|
||||
android:src="@android:drawable/divider_horizontal_bright" />
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:text="@string/taskView_preferredDueDate"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
<TextView android:id="@+id/cell_preferredDueDate"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:colorForeground="@color/view_table_values" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Notes -->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5px"
|
||||
android:src="@android:drawable/divider_horizontal_bright" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:text="@string/taskView_notes"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<TextView android:id="@+id/cell_notes"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5px"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:colorForeground="@color/view_table_values" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2007 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Choices for the "Reminder minutes" spinner.
|
||||
These must be kept in sync with the reminder_minutes_values array.
|
||||
-->
|
||||
<string-array name="reminder_minutes_labels">
|
||||
<item>5 minutes</item>
|
||||
<item>10 minutes</item>
|
||||
<item>15 minutes</item>
|
||||
<item>20 minutes</item>
|
||||
<item>25 minutes</item>
|
||||
<item>30 minutes</item>
|
||||
<item>45 minutes</item>
|
||||
<item>1 hour</item>
|
||||
<item>2 hours</item>
|
||||
<item>3 hours</item>
|
||||
<item>12 hours</item>
|
||||
<item>24 hours</item>
|
||||
<item>2 days</item>
|
||||
<item>1 week</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="reminder_minutes_values">
|
||||
<item>"5"</item>
|
||||
<item>"10"</item>
|
||||
<item>"15"</item>
|
||||
<item>"20"</item>
|
||||
<item>"25"</item>
|
||||
<item>"30"</item>
|
||||
<item>"45"</item>
|
||||
<item>"60"</item>
|
||||
<item>"120"</item>
|
||||
<item>"180"</item>
|
||||
<item>"720"</item>
|
||||
<item>"1440"</item>
|
||||
<item>"2880"</item>
|
||||
<item>"10080"</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="preferences_default_reminder_labels">
|
||||
<item>None</item>
|
||||
<item>5 minutes</item>
|
||||
<item>10 minutes</item>
|
||||
<item>15 minutes</item>
|
||||
<item>20 minutes</item>
|
||||
<item>25 minutes</item>
|
||||
<item>30 minutes</item>
|
||||
<item>45 minutes</item>
|
||||
<item>1 hour</item>
|
||||
<item>2 hours</item>
|
||||
<item>3 hours</item>
|
||||
<item>12 hours</item>
|
||||
<item>24 hours</item>
|
||||
<item>2 days</item>
|
||||
<item>1 week</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="preferences_default_reminder_values">
|
||||
<item>"0"</item>
|
||||
<item>"5"</item>
|
||||
<item>"10"</item>
|
||||
<item>"15"</item>
|
||||
<item>"20"</item>
|
||||
<item>"25"</item>
|
||||
<item>"30"</item>
|
||||
<item>"45"</item>
|
||||
<item>"60"</item>
|
||||
<item>"120"</item>
|
||||
<item>"180"</item>
|
||||
<item>"720"</item>
|
||||
<item>"1440"</item>
|
||||
<item>"2880"</item>
|
||||
<item>"10080"</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="preferences_alert_type_labels">
|
||||
<item>Alert</item>
|
||||
<item>Status bar notification</item>
|
||||
<item>Off</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="preferences_alert_type_values">
|
||||
<item>"0"</item>
|
||||
<item>"1"</item>
|
||||
<item>"2"</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="availability">
|
||||
<item>Busy</item>
|
||||
<item>Available</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="visibility">
|
||||
<item>Default</item>
|
||||
<item>Private</item>
|
||||
<item>Public</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Order matters, and note that the preference for which day the week starts on is handled
|
||||
elsewhere (and needn't be addressed here). -->
|
||||
<string-array name="day_labels">
|
||||
<item>Sunday</item>
|
||||
<item>Monday</item>
|
||||
<item>Tuesday</item>
|
||||
<item>Wednesday</item>
|
||||
<item>Thursday</item>
|
||||
<item>Friday</item>
|
||||
<item>Saturday</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="ordinal_labels">
|
||||
<item>first</item>
|
||||
<item>second</item>
|
||||
<item>third</item>
|
||||
<item>fourth</item>
|
||||
<item>last</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Invitation responses -->
|
||||
<string-array name="response_labels1">
|
||||
<item>(No response)</item>
|
||||
<item>Yes</item>
|
||||
<item>Maybe</item>
|
||||
<item>No</item>
|
||||
</string-array>
|
||||
<string-array name="response_labels2">
|
||||
<item>Yes</item>
|
||||
<item>Maybe</item>
|
||||
<item>No</item>
|
||||
</string-array>
|
||||
|
||||
<!-- The corresponding indices are defined in DeleteEventHelper.java -->
|
||||
<string-array name="delete_repeating_labels">
|
||||
<item>Only this event</item>
|
||||
<item>This & future events</item>
|
||||
<item>All events</item>
|
||||
</string-array>
|
||||
|
||||
<!-- 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.
|
||||
-->
|
||||
<string-array name="delete_repeating_labels_no_selected">
|
||||
<item>This & future events</item>
|
||||
<item>All events</item>
|
||||
</string-array>
|
||||
</resources>
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* //device/apps/Calendar/assets/res/any/colors.xml
|
||||
**
|
||||
** Copyright 2006, 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.
|
||||
*/
|
||||
-->
|
||||
<resources>
|
||||
<color name="task_list_overdue">#ffff4444</color>
|
||||
<color name="task_list_done">#ffaaaaaa</color>
|
||||
|
||||
<color name="view_header_done">#ff83ffa9</color>
|
||||
<color name="view_table_values">#ffbbbbbb</color>
|
||||
<color name="view_table_overdue">#ffff0000</color>
|
||||
|
||||
<color name="importance_1">#ffe36150</color>
|
||||
<color name="importance_2">#ffe3ad50</color>
|
||||
<color name="importance_3">#ffffffff</color>
|
||||
<color name="importance_4">#ffb5b0a8</color>
|
||||
</resources>
|
||||
|
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<!-- application -->
|
||||
<string name="app_name">Astrid</string>
|
||||
|
||||
<!-- General String Constants -->
|
||||
<skip />
|
||||
|
||||
<!-- Importance Labels -->
|
||||
<string name="importance_1">I need to do this</string>
|
||||
<string name="importance_2">I really should do this</string>
|
||||
<string name="importance_3">It would be nice to do this</string>
|
||||
<string name="importance_4">Who cares!</string>
|
||||
|
||||
<!-- Plurals -->
|
||||
<plurals name="Ntasks">
|
||||
<item quantity="one">1 Task</item>
|
||||
<item quantity="other">%d Tasks</item>
|
||||
</plurals>
|
||||
<!-- Time Constants -->
|
||||
<plurals name="Ndays">
|
||||
<item quantity="one">1 Day</item>
|
||||
<item quantity="other">%d Days</item>
|
||||
</plurals>
|
||||
<plurals name="Nhours">
|
||||
<item quantity="one">1 Hour</item>
|
||||
<item quantity="other">%d Hours</item>
|
||||
</plurals>
|
||||
<plurals name="Nminutes">
|
||||
<item quantity="one">1 Minute</item>
|
||||
<item quantity="other">%d Minutes</item>
|
||||
</plurals>
|
||||
<plurals name="Nseconds">
|
||||
<item quantity="one">1 Second</item>
|
||||
<item quantity="other">%d Seconds</item>
|
||||
</plurals>
|
||||
|
||||
<!-- TaskList -->
|
||||
<skip />
|
||||
<string name="taskList_titlePrefix">Astrid: </string>
|
||||
<string name="taskList_hiddenSuffix"> hidden</string>
|
||||
<string name="addtask_label">New Task</string>
|
||||
|
||||
<string name="taskList_menu_insert">Add</string>
|
||||
<string name="taskList_menu_tags">Tags</string>
|
||||
<string name="taskList_menu_settings">Settings</string>
|
||||
<string name="taskList_menu_filters">Filters</string>
|
||||
|
||||
<string name="taskList_context_edit">Edit Task</string>
|
||||
<string name="taskList_context_delete">Delete Task</string>
|
||||
<string name="taskList_filter_title">Filters</string>
|
||||
<string name="taskList_filter_hidden">Hidden/Blocked Tasks</string>
|
||||
<string name="taskList_filter_done">Completed Tasks</string>
|
||||
|
||||
<!-- TaskEdit -->
|
||||
<skip />
|
||||
|
||||
<string name="taskEdit_titleGeneric">Astrid: Editing Task</string>
|
||||
<string name="taskEdit_titlePrefix">Astrid: Editing </string>
|
||||
|
||||
<string name="name_label">What</string>
|
||||
<string name="name_hint">Task Description</string>
|
||||
<string name="estimatedDuration_label">Estimated Time Needed</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="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">Blocking On</string>
|
||||
<string name="notes_label">Notes</string>
|
||||
<string name="notes_hint">Enter Task Notes</string>
|
||||
<string name="minutes_dialog">Time (in minutes)</string>
|
||||
|
||||
<string name="save_label">Save</string>
|
||||
<string name="discard_label">Discard</string>
|
||||
<string name="delete_label">Delete</string>
|
||||
<string name="blank_button_title">Click to Set</string>
|
||||
|
||||
<string name="taskEdit_menu_save">Save</string>
|
||||
|
||||
<!-- TaskView -->
|
||||
<skip />
|
||||
|
||||
<string name="taskView_title">Astrid: Task Properties</string>
|
||||
<string name="startTimer_label">Start Timer</string>
|
||||
<string name="stopTimer_label">Stop Timer</string>
|
||||
<string name="progress_suffix">% Done</string>
|
||||
<string name="edit_label">Edit Task</string>
|
||||
<string name="taskView_elapsed">Elapsed Time</string>
|
||||
<string name="taskView_estimated">Estimated Time</string>
|
||||
<string name="taskView_definiteDueDate">Absolute Deadline</string>
|
||||
<string name="taskView_preferredDueDate">Goal Deadline</string>
|
||||
<string name="taskView_notes">Task Notes</string>
|
||||
<string name="overdue_suffix"> Overdue</string>
|
||||
<string name="progress_dialog">% of Task Finished</string>
|
||||
|
||||
<!-- Utilities -->
|
||||
<skip />
|
||||
<string name="delete_title">Delete</string>
|
||||
<string name="delete_this_task_title">Delete this task?</string>
|
||||
|
||||
</resources>
|
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* //device/apps/Calendar/assets/res/any/styles.xml
|
||||
**
|
||||
** Copyright 2006, 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.
|
||||
*/
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<style name="Alert" parent="android:Theme.Dialog">
|
||||
<item name="android:windowBackground">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="MonthView_DayLabel">
|
||||
<item name="android:layout_width">29dip</item>
|
||||
<item name="android:layout_height">fill_parent</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:paddingTop">2dip</item>
|
||||
<item name="android:paddingBottom">2dip</item>
|
||||
<item name="android:textAppearance">@style/TextAppearance.MonthView_DayLabel</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance" parent="android:TextAppearance">
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.MonthView_DayLabel">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.AgendaView_ValueLabel">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.EditEvent_Label">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Alert_Title">
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Alert_Label">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Alert_Value">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -0,0 +1,223 @@
|
||||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
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).
|
||||
*/
|
||||
public static final int day_labels=0x7f040008;
|
||||
/** The corresponding indices are defined in DeleteEventHelper.java
|
||||
*/
|
||||
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 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 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 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 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 class plurals {
|
||||
/** 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;
|
||||
/** Plurals
|
||||
*/
|
||||
public static final int Ntasks=0x7f070000;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int addtask_label=0x7f060007;
|
||||
/** 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;
|
||||
/** 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 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dame
|
||||
*
|
||||
* 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 java.text.Format;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.app.DatePickerDialog.OnDateSetListener;
|
||||
import android.app.TimePickerDialog.OnTimeSetListener;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.timsu.astrid.data.enums.Importance;
|
||||
import com.timsu.astrid.data.task.TaskIdentifier;
|
||||
import com.timsu.astrid.data.task.TaskModelForEdit;
|
||||
import com.timsu.astrid.utilities.DateUtilities;
|
||||
import com.timsu.astrid.widget.NumberPicker;
|
||||
import com.timsu.astrid.widget.NumberPickerDialog;
|
||||
import com.timsu.astrid.widget.NumberPickerDialog.OnNumberPickedListener;
|
||||
|
||||
public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
|
||||
private static final int SAVE_ID = Menu.FIRST;
|
||||
private static final int DISCARD_ID = Menu.FIRST + 1;
|
||||
private static final int DELETE_ID = Menu.FIRST + 2;
|
||||
|
||||
private EditText name;
|
||||
private Spinner importance;
|
||||
private TimeDurationControlSet estimatedDuration;
|
||||
private TimeDurationControlSet elapsedDuration;
|
||||
private DateControlSet definiteDueDate;
|
||||
private DateControlSet preferredDueDate;
|
||||
private DateControlSet hiddenUntil;
|
||||
private EditText notes;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.task_edit);
|
||||
|
||||
setUpUIComponents();
|
||||
setUpListeners();
|
||||
populateFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TaskModelForEdit getModel(TaskIdentifier identifier) {
|
||||
if (identifier != null)
|
||||
return controller.fetchTaskForEdit(identifier);
|
||||
else
|
||||
return controller.createNewTaskForEdit();
|
||||
}
|
||||
|
||||
// --- data saving and retrieving
|
||||
|
||||
private void populateFields() {
|
||||
Resources r = getResources();
|
||||
if(model.getCursor() != null)
|
||||
startManagingCursor(model.getCursor());
|
||||
|
||||
name.setText(model.getName());
|
||||
if(model.getName().length() > 0)
|
||||
setTitle(new StringBuilder().
|
||||
append(r.getString(R.string.taskEdit_titlePrefix)).
|
||||
append(" ").
|
||||
append(model.getName()));
|
||||
|
||||
estimatedDuration.setTimeElapsed(model.getEstimatedSeconds());
|
||||
elapsedDuration.setTimeElapsed(model.getElapsedSeconds());
|
||||
importance.setSelection(model.getImportance().ordinal());
|
||||
|
||||
definiteDueDate.setDate(model.getDefiniteDueDate());
|
||||
preferredDueDate.setDate(model.getPreferredDueDate());
|
||||
hiddenUntil.setDate(model.getHiddenUntil());
|
||||
|
||||
notes.setText(model.getNotes());
|
||||
}
|
||||
|
||||
private void save() {
|
||||
model.setName(name.getText().toString());
|
||||
model.setEstimatedSeconds(estimatedDuration.getTimeDurationInSeconds());
|
||||
model.setElapsedSeconds(elapsedDuration.getTimeDurationInSeconds());
|
||||
model.setImportance(Importance.values()[importance.getSelectedItemPosition()]);
|
||||
|
||||
model.setDefiniteDueDate(definiteDueDate.getDate());
|
||||
model.setPreferredDueDate(preferredDueDate.getDate());
|
||||
model.setHiddenUntil(hiddenUntil.getDate());
|
||||
|
||||
model.setNotes(notes.getText().toString());
|
||||
|
||||
try {
|
||||
if(!controller.saveTask(model))
|
||||
throw new RuntimeException("Unable to save task: false");
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(getClass().getSimpleName(), "Error saving task!", e);
|
||||
}
|
||||
}
|
||||
|
||||
// --- user interface components
|
||||
|
||||
private void setUpUIComponents() {
|
||||
Resources r = getResources();
|
||||
setTitle(new StringBuilder()
|
||||
.append(r.getString(R.string.app_name))
|
||||
.append(": ")
|
||||
.append(r.getString(R.string.taskEdit_titleGeneric)));
|
||||
|
||||
name = (EditText)findViewById(R.id.name);
|
||||
importance = (Spinner)findViewById(R.id.importance);
|
||||
|
||||
estimatedDuration = new TimeDurationControlSet(R.id.estimatedDuration);
|
||||
elapsedDuration = new TimeDurationControlSet(R.id.elapsedDuration);
|
||||
definiteDueDate = new DateControlSet(R.id.definiteDueDate_notnull,
|
||||
R.id.definiteDueDate_date, R.id.definiteDueDate_time);
|
||||
preferredDueDate = new DateControlSet(R.id.preferredDueDate_notnull,
|
||||
R.id.preferredDueDate_date, R.id.preferredDueDate_time);
|
||||
hiddenUntil = new DateControlSet(R.id.hiddenUntil_notnull,
|
||||
R.id.hiddenUntil_date, R.id.hiddenUntil_time);
|
||||
|
||||
notes = (EditText)findViewById(R.id.notes);
|
||||
|
||||
// set up for each field
|
||||
|
||||
ImportanceAdapter importanceAdapter = new ImportanceAdapter(this,
|
||||
android.R.layout.simple_spinner_item,
|
||||
android.R.layout.simple_spinner_dropdown_item,
|
||||
Importance.values());
|
||||
importance.setAdapter(importanceAdapter);
|
||||
}
|
||||
|
||||
/** Display importance with proper formatting */
|
||||
private class ImportanceAdapter extends ArrayAdapter<Importance> {
|
||||
private int textViewResourceId, dropDownResourceId;
|
||||
private LayoutInflater inflater;
|
||||
|
||||
public ImportanceAdapter(Context context, int textViewResourceId,
|
||||
int dropDownResourceId, Importance[] objects) {
|
||||
super(context, textViewResourceId, objects);
|
||||
|
||||
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
this.textViewResourceId = textViewResourceId;
|
||||
this.dropDownResourceId = dropDownResourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
return getView(position, convertView, parent, textViewResourceId, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||
return getView(position, convertView, parent, dropDownResourceId, true);
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent,
|
||||
int resource, boolean setColors) {
|
||||
View view;
|
||||
TextView text;
|
||||
Resources r = getResources();
|
||||
|
||||
if (convertView == null) {
|
||||
view = inflater.inflate(resource, parent, false);
|
||||
} else {
|
||||
view = convertView;
|
||||
}
|
||||
|
||||
try {
|
||||
text = (TextView) view;
|
||||
} catch (ClassCastException e) {
|
||||
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
|
||||
throw new IllegalStateException(
|
||||
"ArrayAdapter requires the resource ID to be a TextView", e);
|
||||
}
|
||||
|
||||
text.setText(r.getString(getItem(position).getLabelResource()));
|
||||
if(setColors)
|
||||
text.setBackgroundColor(r.getColor(getItem(position).getColorResource()));
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
/** Set up button listeners */
|
||||
private void setUpListeners() {
|
||||
|
||||
Button saveButton = (Button) findViewById(R.id.save);
|
||||
saveButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
saveButtonClick();
|
||||
}
|
||||
});
|
||||
|
||||
Button discardButton = (Button) findViewById(R.id.discard);
|
||||
discardButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
discardButtonClick();
|
||||
}
|
||||
});
|
||||
|
||||
Button deleteButton = (Button) findViewById(R.id.delete);
|
||||
if(model.getTaskIdentifier() == null)
|
||||
deleteButton.setVisibility(View.GONE);
|
||||
deleteButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
deleteButtonClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void saveButtonClick() {
|
||||
save();
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void discardButtonClick() {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void deleteButtonClick() {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.delete_title)
|
||||
.setMessage(R.string.delete_this_task_title)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
controller.deleteTask(model.getTaskIdentifier());
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
case SAVE_ID:
|
||||
saveButtonClick();
|
||||
return true;
|
||||
case DISCARD_ID:
|
||||
discardButtonClick();
|
||||
return true;
|
||||
case DELETE_ID:
|
||||
deleteButtonClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onMenuItemSelected(featureId, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
MenuItem item;
|
||||
|
||||
item = menu.add(Menu.NONE, SAVE_ID, 0, R.string.save_label);
|
||||
item.setIcon(android.R.drawable.ic_menu_save);
|
||||
item.setAlphabeticShortcut('s');
|
||||
|
||||
item = menu.add(Menu.NONE, DISCARD_ID, 0, R.string.discard_label);
|
||||
item.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
||||
item.setAlphabeticShortcut('c');
|
||||
|
||||
item = menu.add(Menu.NONE, DISCARD_ID, 0, R.string.delete_label);
|
||||
item.setIcon(android.R.drawable.ic_menu_delete);
|
||||
item.setAlphabeticShortcut('d');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
save();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
populateFields();
|
||||
}
|
||||
|
||||
// --- date/time methods and helper classes
|
||||
|
||||
private class TimeDurationControlSet implements OnNumberPickedListener,
|
||||
View.OnClickListener {
|
||||
private Button timeButton;
|
||||
private int timeDuration;
|
||||
private final NumberPickerDialog dialog =
|
||||
new NumberPickerDialog(TaskEdit.this, this,
|
||||
getResources().getString(R.string.minutes_dialog),
|
||||
0, 5, 0, 999);
|
||||
|
||||
public TimeDurationControlSet(int timeButtonId) {
|
||||
timeButton = (Button)findViewById(timeButtonId);
|
||||
timeButton.setOnClickListener(this);
|
||||
}
|
||||
|
||||
public int getTimeDurationInSeconds() {
|
||||
return timeDuration;
|
||||
}
|
||||
|
||||
public void setTimeElapsed(Integer timeDurationInSeconds) {
|
||||
if(timeDurationInSeconds == null)
|
||||
timeDurationInSeconds = 0;
|
||||
|
||||
timeDuration = timeDurationInSeconds;
|
||||
|
||||
Resources r = getResources();
|
||||
if(timeDurationInSeconds == 0) {
|
||||
timeButton.setText(r.getString(R.string.blank_button_title));
|
||||
return;
|
||||
}
|
||||
|
||||
timeButton.setText(DateUtilities.getDurationString(r,
|
||||
timeDurationInSeconds, 2));
|
||||
dialog.setInitialValue(timeDuration/60);
|
||||
}
|
||||
|
||||
@Override
|
||||
/** Called when NumberPicker activity is completed */
|
||||
public void onNumberPicked(NumberPicker view, int value) {
|
||||
setTimeElapsed(value * 60);
|
||||
}
|
||||
|
||||
/** Called when time button is clicked */
|
||||
public void onClick(View v) {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static final Format dateFormatter = new SimpleDateFormat("EEE, MMM d, yyyy");
|
||||
private static final Format timeFormatter = new SimpleDateFormat("h:mm a");
|
||||
|
||||
private class DateControlSet implements OnTimeSetListener,
|
||||
OnDateSetListener, View.OnClickListener {
|
||||
private CheckBox activatedCheckBox;
|
||||
private Button dateButton;
|
||||
private Button timeButton;
|
||||
private Date date;
|
||||
|
||||
public DateControlSet(int checkBoxId, int dateButtonId, int timeButtonId) {
|
||||
activatedCheckBox = (CheckBox)findViewById(checkBoxId);
|
||||
dateButton = (Button)findViewById(dateButtonId);
|
||||
timeButton = (Button)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);
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
if(!activatedCheckBox.isChecked())
|
||||
return null;
|
||||
return date;
|
||||
}
|
||||
|
||||
/** Initialize the components for the given date field */
|
||||
public void setDate(Date newDate) {
|
||||
this.date = newDate;
|
||||
if(newDate == null) {
|
||||
date = new Date();
|
||||
date.setMinutes(0);
|
||||
}
|
||||
|
||||
activatedCheckBox.setChecked(newDate != null);
|
||||
dateButton.setEnabled(newDate != null);
|
||||
timeButton.setEnabled(newDate != null);
|
||||
|
||||
updateDate();
|
||||
updateTime();
|
||||
}
|
||||
|
||||
public void onDateSet(DatePicker view, int year, int month, int monthDay) {
|
||||
date.setYear(year - 1900);
|
||||
date.setMonth(month);
|
||||
date.setDate(monthDay);
|
||||
updateDate();
|
||||
}
|
||||
|
||||
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
|
||||
date.setHours(hourOfDay);
|
||||
date.setMinutes(minute);
|
||||
updateTime();
|
||||
}
|
||||
|
||||
public void updateDate() {
|
||||
dateButton.setText(dateFormatter.format(date));
|
||||
|
||||
}
|
||||
|
||||
public void updateTime() {
|
||||
timeButton.setText(timeFormatter.format(date));
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if(v == timeButton)
|
||||
new TimePickerDialog(TaskEdit.this, this, date.getHours(),
|
||||
date.getMinutes(), false).show();
|
||||
else
|
||||
new DatePickerDialog(TaskEdit.this, this, 1900 +
|
||||
date.getYear(), date.getMonth(), date.getDate()).show();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,401 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dame
|
||||
*
|
||||
* 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 java.util.List;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View.OnCreateContextMenuListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.timsu.astrid.data.task.TaskController;
|
||||
import com.timsu.astrid.data.task.TaskIdentifier;
|
||||
import com.timsu.astrid.data.task.TaskModelForList;
|
||||
|
||||
|
||||
/** Primary view for the Astrid Application. Lists all of the tasks in the
|
||||
* system, and allows users to edit them.
|
||||
*
|
||||
* @author Tim Su (timsu@stanfordalumni.org)
|
||||
*
|
||||
*/
|
||||
public class TaskList extends Activity {
|
||||
private static final int ACTIVITY_CREATE = 0;
|
||||
private static final int ACTIVITY_VIEW = 1;
|
||||
private static final int ACTIVITY_EDIT = 2;
|
||||
|
||||
private static final int INSERT_ID = Menu.FIRST;
|
||||
private static final int FILTERS_ID = Menu.FIRST + 1;
|
||||
private static final int TAGS_ID = Menu.FIRST + 2;
|
||||
|
||||
private static final int CONTEXT_EDIT_ID = Menu.FIRST + 10;
|
||||
private static final int CONTEXT_DELETE_ID = Menu.FIRST + 11;
|
||||
|
||||
private static final int CONTEXT_FILTER_HIDDEN = Menu.FIRST + 20;
|
||||
private static final int CONTEXT_FILTER_DONE = Menu.FIRST + 21;
|
||||
|
||||
private TaskController controller;
|
||||
private ListView listView;
|
||||
private Button addButton;
|
||||
|
||||
private boolean filterShowHidden = false;
|
||||
private boolean filterShowDone = false;
|
||||
|
||||
/** Called when loading up the activity for the first time */
|
||||
private void onLoad() {
|
||||
controller = new TaskController(this);
|
||||
controller.open();
|
||||
|
||||
listView = (ListView)findViewById(R.id.tasklist);
|
||||
|
||||
addButton = (Button)findViewById(R.id.addtask);
|
||||
addButton.setOnClickListener(new
|
||||
View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
createTask();
|
||||
}
|
||||
});
|
||||
|
||||
fillData();
|
||||
|
||||
// filters context menu
|
||||
listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
if(menu.hasVisibleItems())
|
||||
return;
|
||||
|
||||
MenuItem item = menu.add(Menu.NONE, CONTEXT_FILTER_HIDDEN, Menu.NONE,
|
||||
R.string.taskList_filter_hidden);
|
||||
item.setCheckable(true);
|
||||
item.setChecked(filterShowHidden);
|
||||
|
||||
item = menu.add(Menu.NONE, CONTEXT_FILTER_DONE, Menu.NONE,
|
||||
R.string.taskList_filter_done);
|
||||
item.setCheckable(true);
|
||||
item.setChecked(filterShowDone);
|
||||
|
||||
menu.setHeaderTitle(R.string.taskList_filter_title);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Fill in the Task List with our tasks */
|
||||
private void fillData() {
|
||||
Resources r = getResources();
|
||||
|
||||
// get the database cursor
|
||||
Cursor tasksCursor;
|
||||
if(filterShowDone)
|
||||
tasksCursor = controller.getAllTaskListCursor();
|
||||
else
|
||||
tasksCursor = controller.getActiveTaskListCursor();
|
||||
|
||||
startManagingCursor(tasksCursor);
|
||||
int totalTasks = tasksCursor.getCount();
|
||||
List<TaskModelForList> taskArray =
|
||||
controller.createTaskListFromCursor(tasksCursor, !filterShowHidden);
|
||||
int hiddenTasks = totalTasks - taskArray.size();
|
||||
|
||||
// hide "add" button if we have a few tasks
|
||||
if(taskArray.size() > 2)
|
||||
addButton.setVisibility(View.GONE);
|
||||
|
||||
// set up the title
|
||||
StringBuilder title = new StringBuilder().
|
||||
append(r.getString(R.string.taskList_titlePrefix)).
|
||||
append(" ").append(r.getQuantityString(R.plurals.Ntasks,
|
||||
taskArray.size(), taskArray.size()));
|
||||
if(hiddenTasks > 0)
|
||||
title.append(" (").append(hiddenTasks).append(" ").
|
||||
append(r.getString(R.string.taskList_hiddenSuffix)).append(")");
|
||||
setTitle(title);
|
||||
|
||||
// set up our adapter
|
||||
TaskListAdapter tasks = new TaskListAdapter(this,
|
||||
R.layout.task_list_row, taskArray);
|
||||
listView.setAdapter(tasks);
|
||||
listView.setItemsCanFocus(true);
|
||||
|
||||
// list view listener
|
||||
listView.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view,
|
||||
int position, long id) {
|
||||
TaskModelForList task = (TaskModelForList)view.getTag();
|
||||
|
||||
Intent intent = new Intent(TaskList.this, TaskView.class);
|
||||
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, task.
|
||||
getTaskIdentifier().getId());
|
||||
startActivityForResult(intent, ACTIVITY_VIEW);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent intent) {
|
||||
fillData();
|
||||
}
|
||||
|
||||
// --- list adapter
|
||||
|
||||
private class TaskListAdapter extends ArrayAdapter<TaskModelForList> {
|
||||
|
||||
private List<TaskModelForList> objects;
|
||||
private int resource;
|
||||
private LayoutInflater inflater;
|
||||
|
||||
public TaskListAdapter(Context context, int resource,
|
||||
List<TaskModelForList> objects) {
|
||||
super(context, resource, objects);
|
||||
|
||||
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
this.objects = objects;
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view;
|
||||
|
||||
view = inflater.inflate(resource, parent, false);
|
||||
setupView(view, objects.get(position));
|
||||
addListeners(position, view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public void setupView(View view, final TaskModelForList task) {
|
||||
Resources r = getResources();
|
||||
|
||||
// set up basic properties
|
||||
final TextView name = ((TextView)view.findViewById(R.id.text1));
|
||||
final CheckBox progress = ((CheckBox)view.findViewById(R.id.cb1));
|
||||
final ImageView timer = ((ImageView)view.findViewById(R.id.image1));
|
||||
|
||||
view.setTag(task);
|
||||
progress.setTag(task);
|
||||
|
||||
name.setText(task.getName());
|
||||
|
||||
if(task.getTimerStart() != null)
|
||||
timer.setImageDrawable(r.getDrawable(R.drawable.ic_dialog_time));
|
||||
progress.setChecked(task.isTaskCompleted());
|
||||
setTaskAppearance(name, task);
|
||||
}
|
||||
|
||||
public void addListeners(final int position, final View view) {
|
||||
final CheckBox progress = ((CheckBox)view.findViewById(R.id.cb1));
|
||||
final TextView name = ((TextView)view.findViewById(R.id.text1));
|
||||
|
||||
// clicking the check box
|
||||
progress.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView,
|
||||
boolean isChecked) {
|
||||
TaskModelForList task = (TaskModelForList)buttonView.getTag();
|
||||
|
||||
int newProgressPercentage;
|
||||
if(isChecked)
|
||||
newProgressPercentage = TaskModelForList.getCompletedPercentage();
|
||||
else
|
||||
newProgressPercentage = 0;
|
||||
|
||||
// this takes care of initial checked change
|
||||
if(newProgressPercentage != task.getProgressPercentage()) {
|
||||
task.setProgressPercentage(newProgressPercentage);
|
||||
controller.saveTask(task);
|
||||
setTaskAppearance(name, task);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// interacting with the text field
|
||||
view.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
listView.performItemClick(view, position, 0);
|
||||
}
|
||||
});
|
||||
|
||||
view.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
TaskModelForList task = (TaskModelForList)v.getTag();
|
||||
int id = (int)task.getTaskIdentifier().getId();
|
||||
|
||||
menu.add(id, CONTEXT_EDIT_ID, Menu.NONE,
|
||||
R.string.taskList_context_edit);
|
||||
menu.add(id, CONTEXT_DELETE_ID, Menu.NONE,
|
||||
R.string.taskList_context_delete);
|
||||
|
||||
menu.setHeaderTitle(task.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTaskAppearance(TextView name, TaskModelForList task) {
|
||||
Resources r = getResources();
|
||||
|
||||
if(task.isTaskCompleted()) {
|
||||
name.setBackgroundDrawable(r.getDrawable(R.drawable.strikeout));
|
||||
name.setTextColor(r.getColor(R.color.task_list_done));
|
||||
} else {
|
||||
name.setBackgroundDrawable(null);
|
||||
name.setTextColor(r.getColor(task.getTaskColorResource()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- ui control handlers
|
||||
|
||||
private void createTask() {
|
||||
Intent i = new Intent(this, TaskEdit.class);
|
||||
startActivityForResult(i, ACTIVITY_CREATE);
|
||||
}
|
||||
|
||||
private void deleteTask(final TaskIdentifier taskId) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.delete_title)
|
||||
.setMessage(R.string.delete_this_task_title)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
controller.deleteTask(taskId);
|
||||
fillData();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
case INSERT_ID:
|
||||
createTask();
|
||||
return true;
|
||||
case FILTERS_ID:
|
||||
listView.showContextMenu();
|
||||
return true;
|
||||
case TAGS_ID:
|
||||
// TODO
|
||||
return true;
|
||||
|
||||
case CONTEXT_EDIT_ID:
|
||||
long id = item.getGroupId(); // hackhack =(
|
||||
|
||||
Intent intent = new Intent(TaskList.this, TaskEdit.class);
|
||||
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, id);
|
||||
startActivityForResult(intent, ACTIVITY_EDIT);
|
||||
return true;
|
||||
case CONTEXT_DELETE_ID:
|
||||
id = item.getGroupId();
|
||||
|
||||
deleteTask(new TaskIdentifier(id));
|
||||
return true;
|
||||
|
||||
case CONTEXT_FILTER_HIDDEN:
|
||||
filterShowHidden = !filterShowHidden;
|
||||
fillData();
|
||||
return true;
|
||||
case CONTEXT_FILTER_DONE:
|
||||
filterShowDone = !filterShowDone;
|
||||
fillData();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onMenuItemSelected(featureId, item);
|
||||
}
|
||||
|
||||
// --- creating stuff
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.task_list);
|
||||
|
||||
onLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
MenuItem item;
|
||||
|
||||
item = menu.add(Menu.NONE, INSERT_ID, Menu.NONE,
|
||||
R.string.taskList_menu_insert);
|
||||
item.setIcon(android.R.drawable.ic_menu_add);
|
||||
item.setAlphabeticShortcut('n');
|
||||
|
||||
item = menu.add(Menu.NONE, FILTERS_ID, Menu.NONE,
|
||||
R.string.taskList_menu_filters);
|
||||
item.setIcon(android.R.drawable.ic_menu_view);
|
||||
item.setAlphabeticShortcut('f');
|
||||
|
||||
/*item = menu.add(Menu.NONE, TAGS_ID, Menu.NONE,
|
||||
R.string.taskList_menu_tags);
|
||||
item.setIcon(android.R.drawable.ic_menu_myplaces);
|
||||
item.setAlphabeticShortcut('t');*/
|
||||
|
||||
/*item = menu.add(Menu.NONE, SETTINGS_ID, Menu.NONE,
|
||||
R.string.taskList_menu_settings);
|
||||
item.setIcon(android.R.drawable.ic_menu_preferences);
|
||||
item.setAlphabeticShortcut('p');*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
controller.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.timsu.astrid.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.timsu.astrid.data.task.AbstractTaskModel;
|
||||
import com.timsu.astrid.data.task.TaskController;
|
||||
import com.timsu.astrid.data.task.TaskIdentifier;
|
||||
|
||||
public abstract class TaskModificationActivity<MODEL_TYPE extends
|
||||
AbstractTaskModel> extends Activity {
|
||||
public static final String LOAD_INSTANCE_TOKEN = "id";
|
||||
protected TaskController controller;
|
||||
protected MODEL_TYPE model;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
controller = new TaskController(this);
|
||||
controller.open();
|
||||
|
||||
// check if we have a TaskIdentifier
|
||||
TaskIdentifier identifier = null;
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if(savedInstanceState != null) {
|
||||
identifier = new TaskIdentifier(savedInstanceState.getLong(
|
||||
LOAD_INSTANCE_TOKEN));
|
||||
} else if(extras != null)
|
||||
identifier = new TaskIdentifier(extras.getLong(
|
||||
LOAD_INSTANCE_TOKEN));
|
||||
|
||||
model = getModel(identifier);
|
||||
}
|
||||
|
||||
abstract protected MODEL_TYPE getModel(TaskIdentifier identifier);
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
controller.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putLong(LOAD_INSTANCE_TOKEN, model.getTaskIdentifier().getId());
|
||||
}
|
||||
}
|
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dame
|
||||
*
|
||||
* 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 java.util.Date;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.timsu.astrid.data.task.TaskIdentifier;
|
||||
import com.timsu.astrid.data.task.TaskModelForView;
|
||||
import com.timsu.astrid.utilities.DateUtilities;
|
||||
import com.timsu.astrid.widget.NumberPicker;
|
||||
import com.timsu.astrid.widget.NumberPickerDialog;
|
||||
|
||||
|
||||
/** Task Properties view for the Astrid Application.
|
||||
*
|
||||
* @author Tim Su (timsu@stanfordalumni.org)
|
||||
*
|
||||
*/
|
||||
public class TaskView extends TaskModificationActivity<TaskModelForView> {
|
||||
private static final int ACTIVITY_EDIT = 0;
|
||||
|
||||
private TextView name;
|
||||
private TextView elapsed;
|
||||
private TextView estimated;
|
||||
private TextView definiteDueDate;
|
||||
private TextView preferredDueDate;
|
||||
private TextView notes;
|
||||
private Button timerButton;
|
||||
private Button progress;
|
||||
|
||||
private NumberPickerDialog progressDialog;
|
||||
|
||||
private Handler handler;
|
||||
private Timer updateTimer;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.task_view);
|
||||
handler = new Handler();
|
||||
|
||||
setUpUIComponents();
|
||||
setUpListeners();
|
||||
populateFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TaskModelForView getModel(TaskIdentifier identifier) {
|
||||
if(identifier == null)
|
||||
throw new IllegalArgumentException("Can't view null task!");
|
||||
return controller.fetchTaskForView(identifier);
|
||||
}
|
||||
|
||||
private void setUpUIComponents() {
|
||||
Resources r = getResources();
|
||||
setTitle(r.getString(R.string.taskView_title));
|
||||
|
||||
name = (TextView)findViewById(R.id.name);
|
||||
elapsed = (TextView)findViewById(R.id.cell_elapsed);
|
||||
estimated = (TextView)findViewById(R.id.cell_estimated);
|
||||
definiteDueDate = (TextView)findViewById(R.id.cell_definiteDueDate);
|
||||
preferredDueDate = (TextView)findViewById(R.id.cell_preferredDueDate);
|
||||
notes = (TextView)findViewById(R.id.cell_notes);
|
||||
timerButton = (Button)findViewById(R.id.timerButton);
|
||||
progress = (Button)findViewById(R.id.progress);
|
||||
|
||||
progressDialog = new NumberPickerDialog(this,
|
||||
new NumberPickerDialog.OnNumberPickedListener() {
|
||||
@Override
|
||||
public void onNumberPicked(NumberPicker view, int number) {
|
||||
model.setProgressPercentage(number);
|
||||
controller.saveTask(model);
|
||||
updateProgressComponents();
|
||||
}
|
||||
}, r.getString(R.string.progress_dialog), 0, 10, 0, 100);
|
||||
|
||||
name.setTextSize(36);
|
||||
|
||||
final TimerTask elapsedTimeUpdater = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateElapsedTimeText();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// update the UI
|
||||
updateTimer = new Timer();
|
||||
updateTimer.scheduleAtFixedRate(elapsedTimeUpdater, 0, 1000);
|
||||
}
|
||||
|
||||
private void setUpListeners() {
|
||||
Button edit = (Button)findViewById(R.id.edit);
|
||||
edit.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(TaskView.this, TaskEdit.class);
|
||||
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN,
|
||||
model.getTaskIdentifier().getId());
|
||||
startActivityForResult(intent, ACTIVITY_EDIT);
|
||||
}
|
||||
});
|
||||
|
||||
timerButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if(model.getTimerStart() == null) {
|
||||
model.setTimerStart(new Date());
|
||||
controller.saveTask(model);
|
||||
} else {
|
||||
long start = model.getTimerStart().getTime();
|
||||
model.setTimerStart(null);
|
||||
long secondsElapsed = (System.currentTimeMillis() - start)/1000;
|
||||
model.setElapsedSeconds((int) (model.getElapsedSeconds() +
|
||||
secondsElapsed));
|
||||
controller.saveTask(model);
|
||||
}
|
||||
|
||||
updateTimerButtonText();
|
||||
}
|
||||
});
|
||||
progress.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
progressDialog.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void populateFields() {
|
||||
final Resources r = getResources();
|
||||
name.setText(model.getName());
|
||||
estimated.setText(DateUtilities.getDurationString(r,
|
||||
model.getEstimatedSeconds(), 2));
|
||||
elapsed.setText(DateUtilities.getDurationString(r,
|
||||
model.getElapsedSeconds(), 2));
|
||||
|
||||
formatDeadline(model.getDefiniteDueDate(), definiteDueDate);
|
||||
formatDeadline(model.getPreferredDueDate(), preferredDueDate);
|
||||
|
||||
updateTimerButtonText();
|
||||
updateProgressComponents();
|
||||
|
||||
if(model.getNotes().length() == 0)
|
||||
((View)notes.getParent()).setVisibility(View.GONE);
|
||||
else
|
||||
notes.setText(model.getNotes());
|
||||
}
|
||||
|
||||
private void formatDeadline(Date deadline, TextView view) {
|
||||
Resources r = getResources();
|
||||
if(deadline == null || model.isTaskCompleted()) {
|
||||
((View)view.getParent()).setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
int secondsToDeadline = (int) ((deadline.getTime() -
|
||||
System.currentTimeMillis())/1000);
|
||||
String text = DateUtilities.getDurationString(r,
|
||||
Math.abs(secondsToDeadline), 2);
|
||||
if(secondsToDeadline < 0) {
|
||||
view.setTextColor(r.getColor(R.color.view_table_overdue));
|
||||
view.setText(text + r.getString(R.string.overdue_suffix));
|
||||
} else
|
||||
view.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent intent) {
|
||||
if(resultCode == RESULT_CANCELED)
|
||||
return;
|
||||
|
||||
// if user edits a task, take them straight to the listing page
|
||||
setResult(resultCode);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
populateFields();
|
||||
}
|
||||
|
||||
/** Update components that depend on elapsed time */
|
||||
private void updateElapsedTimeText() {
|
||||
Resources r = getResources();
|
||||
int timeElapsed = model.getElapsedSeconds();
|
||||
if(model.getTimerStart() != null) {
|
||||
timeElapsed += (int) (System.currentTimeMillis() -
|
||||
model.getTimerStart().getTime())/1000;
|
||||
}
|
||||
|
||||
elapsed.setText(DateUtilities.getDurationString(r,
|
||||
timeElapsed, Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
/** Update components that depend on timer status */
|
||||
private void updateTimerButtonText() {
|
||||
Resources r = getResources();
|
||||
if(model.getTimerStart() == null)
|
||||
timerButton.setText(r.getString(R.string.startTimer_label));
|
||||
else
|
||||
timerButton.setText(r.getString(R.string.stopTimer_label));
|
||||
}
|
||||
|
||||
/** Update components that depend on task progress */
|
||||
private void updateProgressComponents() {
|
||||
Resources r = getResources();
|
||||
progress.setText(model.getProgressPercentage() +
|
||||
r.getString(R.string.progress_suffix));
|
||||
|
||||
if(model.isTaskCompleted())
|
||||
name.setBackgroundColor(r.getColor(R.color.view_header_done));
|
||||
else
|
||||
name.setBackgroundColor(r.getColor(model.getImportance().getColorResource()));
|
||||
|
||||
progressDialog.setInitialValue(model.getProgressPercentage());
|
||||
}
|
||||
|
||||
@Override
|
||||
/** Cancel the timer thread */
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
updateTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dame
|
||||
*
|
||||
* 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
|
||||
abstract public class AbstractController {
|
||||
|
||||
protected Context context;
|
||||
protected SQLiteDatabase database;
|
||||
|
||||
// special columns
|
||||
public static final String KEY_ROWID = "_id";
|
||||
|
||||
|
||||
// database names
|
||||
protected static final String TASK_TABLE_NAME = "tasks";
|
||||
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dame
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
public abstract class AbstractModel {
|
||||
|
||||
/* Data Source Ordering:
|
||||
*
|
||||
* In order to return the best data, we want to check first what the user
|
||||
* has explicitly set (setValues), then the values we have read out of
|
||||
* the database (values), the database itself (cursor), then defaults
|
||||
* (getDefaultValues)
|
||||
*/
|
||||
|
||||
/** User set values */
|
||||
protected ContentValues setValues = new ContentValues();
|
||||
|
||||
/** Cached values from database */
|
||||
private ContentValues values = new ContentValues();
|
||||
|
||||
/** Cursor into the database */
|
||||
private Cursor cursor = null;
|
||||
|
||||
// --- constructors
|
||||
|
||||
/** Construct a model from scratch */
|
||||
public AbstractModel() {
|
||||
// ...
|
||||
}
|
||||
|
||||
/** Construct a model from a database object */
|
||||
public AbstractModel(Cursor cursor) {
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
// --- data source getters
|
||||
|
||||
/** Get the user-set values for this object */
|
||||
public ContentValues getSetValues() {
|
||||
return setValues;
|
||||
}
|
||||
|
||||
/** Get the default values for this object */
|
||||
abstract public ContentValues getDefaultValues();
|
||||
|
||||
/** Get a list of all field/value pairs merged across data sources */
|
||||
public ContentValues getMergedValues() {
|
||||
ContentValues mergedValues = new ContentValues();
|
||||
|
||||
mergedValues.putAll(getDefaultValues());
|
||||
mergedValues.putAll(values);
|
||||
mergedValues.putAll(setValues);
|
||||
|
||||
return mergedValues;
|
||||
}
|
||||
|
||||
/** Return the database cursor */
|
||||
public Cursor getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
// --- data retrieval for the different object types
|
||||
|
||||
protected String retrieveString(String field) {
|
||||
if(setValues.containsKey(field))
|
||||
return setValues.getAsString(field);
|
||||
|
||||
if(values.containsKey(field))
|
||||
return values.getAsString(field);
|
||||
|
||||
// if we have a database to hit, do that now
|
||||
if(cursor != null) {
|
||||
String value = cursor.getString(cursor.getColumnIndexOrThrow(field));
|
||||
values.put(field, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// do we have defaults?
|
||||
ContentValues defaults = getDefaultValues();
|
||||
if(defaults != null && defaults.containsKey(field))
|
||||
return defaults.getAsString(field);
|
||||
|
||||
throw new UnsupportedOperationException("Could not read field " + field);
|
||||
}
|
||||
|
||||
protected Integer retrieveInteger(String field) {
|
||||
if(setValues.containsKey(field))
|
||||
return setValues.getAsInteger(field);
|
||||
|
||||
if(values.containsKey(field))
|
||||
return values.getAsInteger(field);
|
||||
|
||||
// if we have a database to hit, do that now
|
||||
if(cursor != null) {
|
||||
Integer value = cursor.getInt(cursor.getColumnIndexOrThrow(field));
|
||||
values.put(field, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// do we have defaults?
|
||||
ContentValues defaults = getDefaultValues();
|
||||
if(defaults != null && defaults.containsKey(field))
|
||||
return defaults.getAsInteger(field);
|
||||
|
||||
throw new UnsupportedOperationException("Could not read field " + field);
|
||||
}
|
||||
|
||||
protected Long retrieveLong(String field) {
|
||||
if(setValues.containsKey(field))
|
||||
return setValues.getAsLong(field);
|
||||
|
||||
if(values.containsKey(field))
|
||||
return values.getAsLong(field);
|
||||
|
||||
// if we have a database to hit, do that now
|
||||
if(cursor != null) {
|
||||
Long value = cursor.getLong(cursor.getColumnIndexOrThrow(field));
|
||||
values.put(field, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// do we have defaults?
|
||||
ContentValues defaults = getDefaultValues();
|
||||
if(defaults != null && defaults.containsKey(field))
|
||||
return defaults.getAsLong(field);
|
||||
|
||||
throw new UnsupportedOperationException("Could not read field " + field);
|
||||
}
|
||||
|
||||
protected Double retrieveDouble(String field) {
|
||||
if(setValues.containsKey(field))
|
||||
return setValues.getAsDouble(field);
|
||||
|
||||
if(values.containsKey(field))
|
||||
return values.getAsDouble(field);
|
||||
|
||||
// if we have a database to hit, do that now
|
||||
if(cursor != null) {
|
||||
Double value = cursor.getDouble(cursor.getColumnIndexOrThrow(field));
|
||||
values.put(field, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// do we have defaults?
|
||||
ContentValues defaults = getDefaultValues();
|
||||
if(defaults != null && defaults.containsKey(field))
|
||||
return defaults.getAsDouble(field);
|
||||
|
||||
throw new UnsupportedOperationException("Could not read field " + field);
|
||||
}
|
||||
|
||||
// --- retrieving composite objects
|
||||
|
||||
protected Date retrieveDate(String field) {
|
||||
Long time = retrieveLong(field);
|
||||
if(time == null || time == 0)
|
||||
return null;
|
||||
|
||||
return new Date(time);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.timsu.astrid.data.enums;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
|
||||
public enum Importance {
|
||||
// MOST IMPORTANT
|
||||
|
||||
LEVEL_1(R.string.importance_1, R.color.importance_1),
|
||||
LEVEL_2(R.string.importance_2, R.color.importance_2),
|
||||
LEVEL_3(R.string.importance_3, R.color.importance_3),
|
||||
LEVEL_4(R.string.importance_4, R.color.importance_4),
|
||||
|
||||
// LEAST IMPORTANT
|
||||
;
|
||||
|
||||
int label;
|
||||
int color;
|
||||
public static final Importance DEFAULT = LEVEL_2;
|
||||
|
||||
private Importance(int label, int color) {
|
||||
this.label = label;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public int getLabelResource() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getColorResource() {
|
||||
return color;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.timsu.astrid.data.location;
|
||||
|
||||
public class GeoPoint {
|
||||
|
||||
private int latitude, longitude;
|
||||
|
||||
public GeoPoint(int latitude, int longitude) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public int getLatitudeE6() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public int getLongitudeE6() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,301 @@
|
||||
package com.timsu.astrid.data.task;
|
||||
|
||||
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.R;
|
||||
import com.timsu.astrid.data.AbstractController;
|
||||
import com.timsu.astrid.data.AbstractModel;
|
||||
import com.timsu.astrid.data.enums.Importance;
|
||||
|
||||
|
||||
/** Abstract model of a task. Subclasses implement the getters and setters
|
||||
* they are interested in.
|
||||
*
|
||||
* @author timsu
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractTaskModel extends AbstractModel {
|
||||
|
||||
/** Version number of this model */
|
||||
static final int VERSION = 1;
|
||||
|
||||
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 BLOCKING_ON = "blockingOn";
|
||||
static final String NOTIFICATIONS = "notifications";
|
||||
static final String CREATION_DATE = "creationDate";
|
||||
static final String COMPLETION_DATE = "completionDate";
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
static {
|
||||
defaultValues.put(NAME, "");
|
||||
defaultValues.put(NOTES, "");
|
||||
defaultValues.put(PROGRESS_PERCENTAGE, 0);
|
||||
defaultValues.put(IMPORTANCE, Importance.DEFAULT.ordinal());
|
||||
defaultValues.put(ESTIMATED_SECONDS, 0);
|
||||
defaultValues.put(ELAPSED_SECONDS, 0);
|
||||
defaultValues.put(TIMER_START, (Long)null);
|
||||
defaultValues.put(DEFINITE_DUE_DATE, (Long)null);
|
||||
defaultValues.put(PREFERRED_DUE_DATE, (Long)null);
|
||||
defaultValues.put(HIDDEN_UNTIL, (Long)null);
|
||||
defaultValues.put(BLOCKING_ON, (Long)null);
|
||||
defaultValues.put(NOTIFICATIONS, 0);
|
||||
defaultValues.put(COMPLETION_DATE, (Long)null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- database helper
|
||||
|
||||
/** Database Helper manages creating new tables and updating old ones */
|
||||
static class TaskModelDatabaseHelper extends SQLiteOpenHelper {
|
||||
String tableName;
|
||||
|
||||
TaskModelDatabaseHelper(Context context, String databaseName) {
|
||||
super(context, databaseName, null, VERSION);
|
||||
|
||||
this.tableName = databaseName;
|
||||
}
|
||||
|
||||
@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(NAME).append(" text not null,").
|
||||
append(NOTES).append(" text not null,").
|
||||
append(PROGRESS_PERCENTAGE).append(" integer not null,").
|
||||
append(IMPORTANCE).append(" integer not null,").
|
||||
append(ESTIMATED_SECONDS).append(" integer,").
|
||||
append(ELAPSED_SECONDS).append(" integer,").
|
||||
append(TIMER_START).append(" integer,").
|
||||
append(DEFINITE_DUE_DATE).append(" integer,").
|
||||
append(PREFERRED_DUE_DATE).append(" integer,").
|
||||
append(HIDDEN_UNTIL).append(" integer,").
|
||||
append(BLOCKING_ON).append(" integer,").
|
||||
append(NOTIFICATIONS).append(" integer,").
|
||||
append(CREATION_DATE).append(" integer,").
|
||||
append(COMPLETION_DATE).append(" integer").
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- utility methods
|
||||
|
||||
/** Gets task color. Requires definiteDueDate and importance */
|
||||
protected int getTaskColorResource() {
|
||||
if(getDefiniteDueDate() != null && getDefiniteDueDate().getTime() <
|
||||
System.currentTimeMillis()) {
|
||||
return R.color.task_list_overdue;
|
||||
} else {
|
||||
return getImportance().getColorResource();
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks whether task is done. Requires progressPercentage */
|
||||
protected boolean isTaskCompleted() {
|
||||
return getProgressPercentage() >= COMPLETE_PERCENTAGE;
|
||||
}
|
||||
|
||||
// --- task identifier
|
||||
|
||||
private TaskIdentifier identifier = null;
|
||||
|
||||
public TaskIdentifier getTaskIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
void setTaskIdentifier(TaskIdentifier identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
// --- constructor pass-through
|
||||
|
||||
AbstractTaskModel() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Read identifier from database */
|
||||
AbstractTaskModel(Cursor cursor) {
|
||||
super(cursor);
|
||||
|
||||
Integer id = retrieveInteger(AbstractController.KEY_ROWID);
|
||||
setTaskIdentifier(new TaskIdentifier(id));
|
||||
}
|
||||
|
||||
/** Get identifier from argument */
|
||||
AbstractTaskModel(TaskIdentifier identifier, Cursor cursor) {
|
||||
super(cursor);
|
||||
|
||||
setTaskIdentifier(identifier);
|
||||
}
|
||||
|
||||
// --- getters and setters: expose them as you see fit
|
||||
|
||||
protected String getName() {
|
||||
return retrieveString(NAME);
|
||||
}
|
||||
|
||||
protected String getNotes() {
|
||||
return retrieveString(NOTES);
|
||||
}
|
||||
|
||||
protected int getProgressPercentage() {
|
||||
return retrieveInteger(PROGRESS_PERCENTAGE);
|
||||
}
|
||||
|
||||
protected Importance getImportance() {
|
||||
Integer value = retrieveInteger(IMPORTANCE);
|
||||
if(value == null)
|
||||
return null;
|
||||
return Importance.values()[value];
|
||||
}
|
||||
|
||||
protected Integer getEstimatedSeconds() {
|
||||
return retrieveInteger(ESTIMATED_SECONDS);
|
||||
}
|
||||
|
||||
protected Integer getElapsedSeconds() {
|
||||
return retrieveInteger(ELAPSED_SECONDS);
|
||||
}
|
||||
|
||||
protected Date getTimerStart() {
|
||||
return retrieveDate(TIMER_START);
|
||||
}
|
||||
|
||||
protected Date getDefiniteDueDate() {
|
||||
return retrieveDate(DEFINITE_DUE_DATE);
|
||||
}
|
||||
|
||||
protected Date getPreferredDueDate() {
|
||||
return retrieveDate(PREFERRED_DUE_DATE);
|
||||
}
|
||||
|
||||
protected Date getHiddenUntil() {
|
||||
return retrieveDate(HIDDEN_UNTIL);
|
||||
}
|
||||
|
||||
protected Date getCreationDate() {
|
||||
return retrieveDate(CREATION_DATE);
|
||||
}
|
||||
|
||||
protected Date getCompletionDate() {
|
||||
return retrieveDate(COMPLETION_DATE);
|
||||
}
|
||||
|
||||
protected TaskIdentifier getBlockingOn() {
|
||||
Long value = retrieveLong(BLOCKING_ON);
|
||||
if(value == null)
|
||||
return null;
|
||||
return new TaskIdentifier(value);
|
||||
}
|
||||
|
||||
// --- setters
|
||||
|
||||
protected void setName(String name) {
|
||||
setValues.put(NAME, name);
|
||||
}
|
||||
|
||||
protected void setNotes(String notes) {
|
||||
setValues.put(NOTES, notes);
|
||||
}
|
||||
|
||||
protected void setProgressPercentage(int progressPercentage) {
|
||||
setValues.put(PROGRESS_PERCENTAGE, progressPercentage);
|
||||
|
||||
if(getProgressPercentage() != progressPercentage &&
|
||||
progressPercentage == COMPLETE_PERCENTAGE)
|
||||
setCompletionDate(new Date());
|
||||
}
|
||||
|
||||
protected void setImportance(Importance importance) {
|
||||
setValues.put(IMPORTANCE, importance.ordinal());
|
||||
}
|
||||
|
||||
protected void setEstimatedSeconds(Integer estimatedSeconds) {
|
||||
setValues.put(ESTIMATED_SECONDS, estimatedSeconds);
|
||||
}
|
||||
|
||||
protected void setElapsedSeconds(int elapsedSeconds) {
|
||||
setValues.put(ELAPSED_SECONDS, elapsedSeconds);
|
||||
}
|
||||
|
||||
protected void setTimerStart(Date timerStart) {
|
||||
putDate(setValues, TIMER_START, timerStart);
|
||||
}
|
||||
|
||||
protected void setDefiniteDueDate(Date definiteDueDate) {
|
||||
putDate(setValues, DEFINITE_DUE_DATE, definiteDueDate);
|
||||
}
|
||||
|
||||
protected void setPreferredDueDate(Date preferredDueDate) {
|
||||
putDate(setValues, PREFERRED_DUE_DATE, preferredDueDate);
|
||||
}
|
||||
|
||||
protected void setHiddenUntil(Date hiddenUntil) {
|
||||
putDate(setValues, HIDDEN_UNTIL, hiddenUntil);
|
||||
}
|
||||
|
||||
protected void setBlockingOn(TaskIdentifier blockingOn) {
|
||||
if(blockingOn == null)
|
||||
setValues.put(BLOCKING_ON, (Integer)null);
|
||||
else
|
||||
setValues.put(BLOCKING_ON, blockingOn.getId());
|
||||
}
|
||||
|
||||
protected void setCreationDate(Date creationDate) {
|
||||
putDate(setValues, CREATION_DATE, creationDate);
|
||||
}
|
||||
|
||||
protected void setCompletionDate(Date completionDate) {
|
||||
putDate(setValues, COMPLETION_DATE, completionDate);
|
||||
}
|
||||
|
||||
// --- utility methods
|
||||
|
||||
static void putDate(ContentValues cv, String fieldName, Date date) {
|
||||
if(date == null)
|
||||
cv.put(fieldName, (Long)null);
|
||||
else
|
||||
cv.put(fieldName, date.getTime());
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
package com.timsu.astrid.data.task;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import com.timsu.astrid.data.AbstractController;
|
||||
import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
|
||||
|
||||
public class TaskController extends AbstractController {
|
||||
|
||||
// --- task list operations
|
||||
|
||||
/** Return a list of all of the tasks with progress < COMPLETE_PERCENTAGE */
|
||||
public Cursor getActiveTaskListCursor() {
|
||||
return database.query(TASK_TABLE_NAME, TaskModelForList.FIELD_LIST,
|
||||
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
|
||||
AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null,
|
||||
null, null);
|
||||
}
|
||||
|
||||
/** Return a list of all tasks */
|
||||
public Cursor getAllTaskListCursor() {
|
||||
return database.query(TASK_TABLE_NAME, TaskModelForList.FIELD_LIST,
|
||||
null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
/** Create a weighted list of tasks from the db cursor given */
|
||||
public List<TaskModelForList> createTaskListFromCursor(Cursor cursor,
|
||||
boolean hideHidden) {
|
||||
return TaskModelForList.createTaskModelList(cursor, hideHidden);
|
||||
}
|
||||
|
||||
// --- single task operations
|
||||
|
||||
/** Delete the given task */
|
||||
public boolean deleteTask(TaskIdentifier taskId) {
|
||||
if(taskId == null)
|
||||
throw new UnsupportedOperationException("Cannot delete uncreated task!");
|
||||
long id = taskId.getId();
|
||||
return database.delete(TASK_TABLE_NAME, KEY_ROWID + "=" + id, null) > 0;
|
||||
}
|
||||
|
||||
/** Sets the timer start time to the given value. Passing in "null"
|
||||
* signifies that the timer is not running. */
|
||||
public boolean startTimer(TaskModelForView task, Date startDate) throws
|
||||
SQLException {
|
||||
task.setTimerStart(startDate);
|
||||
|
||||
long id = task.getTaskIdentifier().getId();
|
||||
ContentValues values = new ContentValues();
|
||||
AbstractTaskModel.putDate(values, AbstractTaskModel.TIMER_START,
|
||||
startDate);
|
||||
return database.update(TASK_TABLE_NAME, values, KEY_ROWID + "=" + id,
|
||||
null) > 0;
|
||||
}
|
||||
|
||||
/** Saves the given task to the database. Returns true on success. */
|
||||
public boolean saveTask(AbstractTaskModel task) {
|
||||
boolean saveSucessful;
|
||||
|
||||
if(task.getTaskIdentifier() == null) {
|
||||
saveSucessful = database.insert(TASK_TABLE_NAME, AbstractTaskModel.NAME,
|
||||
task.getMergedValues()) >= 0;
|
||||
} else {
|
||||
long id = task.getTaskIdentifier().getId();
|
||||
saveSucessful = database.update(TASK_TABLE_NAME, task.getSetValues(),
|
||||
KEY_ROWID + "=" + id, null) > 0;
|
||||
}
|
||||
|
||||
return saveSucessful;
|
||||
}
|
||||
|
||||
// --- fetching different models
|
||||
|
||||
/** Creates a new task and returns the task identifier */
|
||||
public TaskModelForEdit createNewTaskForEdit() {
|
||||
TaskModelForEdit task = new TaskModelForEdit();
|
||||
task.setTaskIdentifier(null);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/** Returns a TaskModelForEdit corresponding to the given TaskIdentifier */
|
||||
public TaskModelForEdit fetchTaskForEdit(TaskIdentifier taskId) throws SQLException {
|
||||
long id = taskId.getId();
|
||||
Cursor cursor = database.query(true, TASK_TABLE_NAME,
|
||||
TaskModelForEdit.FIELD_LIST,
|
||||
KEY_ROWID + "=" + id, null, null, null, null, null);
|
||||
|
||||
if (cursor != null) {
|
||||
cursor.moveToFirst();
|
||||
TaskModelForEdit model = new TaskModelForEdit(taskId, cursor);
|
||||
return model;
|
||||
}
|
||||
|
||||
throw new SQLException("Returned empty set!");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Returns a TaskModelForView corresponding to the given TaskIdentifier */
|
||||
public TaskModelForView fetchTaskForView(TaskIdentifier taskId) throws SQLException {
|
||||
long id = taskId.getId();
|
||||
Cursor cursor = database.query(true, TASK_TABLE_NAME,
|
||||
TaskModelForView.FIELD_LIST,
|
||||
KEY_ROWID + "=" + id, null, null, null, null, null);
|
||||
|
||||
if (cursor != null) {
|
||||
cursor.moveToFirst();
|
||||
TaskModelForView model = new TaskModelForView(taskId, cursor);
|
||||
return model;
|
||||
}
|
||||
|
||||
throw new SQLException("Returned empty set!");
|
||||
|
||||
}
|
||||
|
||||
// --- boilerplate
|
||||
|
||||
/**
|
||||
* Constructor - takes the context to allow the database to be
|
||||
* opened/created
|
||||
*/
|
||||
public TaskController(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 TaskController open() throws SQLException {
|
||||
SQLiteOpenHelper databaseHelper = new TaskModelDatabaseHelper(
|
||||
context, TASK_TABLE_NAME);
|
||||
database = databaseHelper.getWritableDatabase();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Closes database resource */
|
||||
public void close() {
|
||||
database.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.timsu.astrid.data.task;
|
||||
|
||||
|
||||
/** A little class that identifies a task. For saving state and passing around */
|
||||
public class TaskIdentifier {
|
||||
private long id;
|
||||
|
||||
public TaskIdentifier(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package com.timsu.astrid.data.task;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.timsu.astrid.data.enums.Importance;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
|
||||
|
||||
/** Fields that you would want to edit in the TaskModel */
|
||||
public class TaskModelForEdit extends AbstractTaskModel {
|
||||
|
||||
static String[] FIELD_LIST = new String[] {
|
||||
NAME,
|
||||
IMPORTANCE,
|
||||
ESTIMATED_SECONDS,
|
||||
ELAPSED_SECONDS,
|
||||
DEFINITE_DUE_DATE,
|
||||
PREFERRED_DUE_DATE,
|
||||
HIDDEN_UNTIL,
|
||||
BLOCKING_ON,
|
||||
NOTES,
|
||||
};
|
||||
|
||||
// --- constructors
|
||||
|
||||
public TaskModelForEdit() {
|
||||
super();
|
||||
setCreationDate(new Date());
|
||||
}
|
||||
|
||||
public TaskModelForEdit(TaskIdentifier identifier, Cursor cursor) {
|
||||
super(identifier, cursor);
|
||||
}
|
||||
|
||||
// --- getters and setters
|
||||
|
||||
@Override
|
||||
public Date getDefiniteDueDate() {
|
||||
return super.getDefiniteDueDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getEstimatedSeconds() {
|
||||
return super.getEstimatedSeconds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getElapsedSeconds() {
|
||||
return super.getElapsedSeconds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getHiddenUntil() {
|
||||
return super.getHiddenUntil();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Importance getImportance() {
|
||||
return super.getImportance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNotes() {
|
||||
return super.getNotes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getPreferredDueDate() {
|
||||
return super.getPreferredDueDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskIdentifier getBlockingOn() {
|
||||
return super.getBlockingOn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefiniteDueDate(Date definiteDueDate) {
|
||||
super.setDefiniteDueDate(definiteDueDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEstimatedSeconds(Integer estimatedSeconds) {
|
||||
super.setEstimatedSeconds(estimatedSeconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setElapsedSeconds(int elapsedSeconds) {
|
||||
super.setElapsedSeconds(elapsedSeconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHiddenUntil(Date hiddenUntil) {
|
||||
super.setHiddenUntil(hiddenUntil);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImportance(Importance importance) {
|
||||
super.setImportance(importance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
super.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotes(String notes) {
|
||||
super.setNotes(notes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferredDueDate(Date preferredDueDate) {
|
||||
super.setPreferredDueDate(preferredDueDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockingOn(TaskIdentifier blockingOn) {
|
||||
super.setBlockingOn(blockingOn);
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package com.timsu.astrid.data.task;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.timsu.astrid.data.AbstractController;
|
||||
import com.timsu.astrid.data.enums.Importance;
|
||||
|
||||
|
||||
|
||||
/** Fields that you would want to edit in the TaskModel */
|
||||
public class TaskModelForList extends AbstractTaskModel {
|
||||
|
||||
static String[] FIELD_LIST = new String[] {
|
||||
AbstractController.KEY_ROWID,
|
||||
NAME,
|
||||
IMPORTANCE,
|
||||
ELAPSED_SECONDS,
|
||||
ESTIMATED_SECONDS,
|
||||
TIMER_START,
|
||||
DEFINITE_DUE_DATE,
|
||||
PREFERRED_DUE_DATE,
|
||||
PROGRESS_PERCENTAGE,
|
||||
HIDDEN_UNTIL,
|
||||
};
|
||||
|
||||
static List<TaskModelForList> createTaskModelList(Cursor cursor,
|
||||
boolean hideHidden) {
|
||||
ArrayList<TaskModelForList> list = new ArrayList<TaskModelForList>();
|
||||
final HashMap<TaskModelForList, Integer> weights = new
|
||||
HashMap<TaskModelForList, Integer>();
|
||||
|
||||
// first, load everything
|
||||
for(int i = 0; i < cursor.getCount(); i++) {
|
||||
cursor.moveToNext();
|
||||
TaskModelForList task = new TaskModelForList(cursor);
|
||||
|
||||
// hide tasks
|
||||
if(hideHidden) {
|
||||
if(task.getHiddenUntil() != null &&
|
||||
task.getHiddenUntil().getTime() > System.currentTimeMillis())
|
||||
continue;
|
||||
}
|
||||
|
||||
list.add(task);
|
||||
weights.put(task, task.getWeight());
|
||||
}
|
||||
|
||||
// now sort
|
||||
Collections.sort(list, new Comparator<TaskModelForList>() {
|
||||
@Override
|
||||
public int compare(TaskModelForList a, TaskModelForList b) {
|
||||
return weights.get(a) - weights.get(b);
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/** Get the weighted score for this task. Smaller is more important */
|
||||
private int getWeight() {
|
||||
int weight = 0;
|
||||
|
||||
// importance
|
||||
weight += getImportance().ordinal() * 60;
|
||||
|
||||
// estimated time left
|
||||
int secondsLeft = getEstimatedSeconds() - getElapsedSeconds();
|
||||
if(secondsLeft > 0)
|
||||
weight += secondsLeft / 120;
|
||||
|
||||
// looming absolute deadline
|
||||
if(getDefiniteDueDate() != null) {
|
||||
int hoursLeft = (int) (getDefiniteDueDate().getTime() -
|
||||
System.currentTimeMillis())/1000/3600;
|
||||
if(hoursLeft < 5*24)
|
||||
weight += (hoursLeft - 5*24);
|
||||
}
|
||||
|
||||
// looming preferred deadline
|
||||
if(getPreferredDueDate() != null) {
|
||||
int hoursLeft = (int) (getPreferredDueDate().getTime() -
|
||||
System.currentTimeMillis())/1000/3600;
|
||||
if(hoursLeft < 5*24)
|
||||
weight += (hoursLeft - 5*24)/2;
|
||||
}
|
||||
|
||||
// bubble completed tasks to the bottom
|
||||
if(isTaskCompleted())
|
||||
weight += 1000;
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
// --- constructors
|
||||
|
||||
public TaskModelForList(Cursor cursor) {
|
||||
super(cursor);
|
||||
|
||||
// prefetch every field - we can't lazy load with more than 1
|
||||
getElapsedSeconds();
|
||||
getDefiniteDueDate();
|
||||
getEstimatedSeconds();
|
||||
getHiddenUntil();
|
||||
getImportance();
|
||||
getName();
|
||||
getPreferredDueDate();
|
||||
getProgressPercentage();
|
||||
getTimerStart();
|
||||
}
|
||||
|
||||
// --- getters and setters
|
||||
|
||||
@Override
|
||||
public boolean isTaskCompleted() {
|
||||
return super.isTaskCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTaskColorResource() {
|
||||
return super.getTaskColorResource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getElapsedSeconds() {
|
||||
return super.getElapsedSeconds();
|
||||
}
|
||||
|
||||
public static int getCompletedPercentage() {
|
||||
return COMPLETE_PERCENTAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDefiniteDueDate() {
|
||||
return super.getDefiniteDueDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getEstimatedSeconds() {
|
||||
return super.getEstimatedSeconds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getHiddenUntil() {
|
||||
return super.getHiddenUntil();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Importance getImportance() {
|
||||
return super.getImportance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getPreferredDueDate() {
|
||||
return super.getPreferredDueDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgressPercentage() {
|
||||
return super.getProgressPercentage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getTimerStart() {
|
||||
return super.getTimerStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressPercentage(int progressPercentage) {
|
||||
super.setProgressPercentage(progressPercentage);
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package com.timsu.astrid.data.task;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.timsu.astrid.data.AbstractController;
|
||||
import com.timsu.astrid.data.enums.Importance;
|
||||
|
||||
|
||||
|
||||
/** Fields that you would want to see in the TaskView activity */
|
||||
public class TaskModelForView extends AbstractTaskModel {
|
||||
|
||||
static String[] FIELD_LIST = new String[] {
|
||||
AbstractController.KEY_ROWID,
|
||||
NAME,
|
||||
IMPORTANCE,
|
||||
PROGRESS_PERCENTAGE,
|
||||
ESTIMATED_SECONDS,
|
||||
ELAPSED_SECONDS,
|
||||
TIMER_START,
|
||||
DEFINITE_DUE_DATE,
|
||||
PREFERRED_DUE_DATE,
|
||||
NOTES,
|
||||
};
|
||||
|
||||
// --- constructors
|
||||
|
||||
public TaskModelForView(TaskIdentifier identifier, Cursor cursor) {
|
||||
super(identifier, cursor);
|
||||
}
|
||||
|
||||
// --- getters and setters
|
||||
|
||||
@Override
|
||||
public boolean isTaskCompleted() {
|
||||
return super.isTaskCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTaskColorResource() {
|
||||
return super.getTaskColorResource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgressPercentage() {
|
||||
return super.getProgressPercentage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDefiniteDueDate() {
|
||||
return super.getDefiniteDueDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getEstimatedSeconds() {
|
||||
return super.getEstimatedSeconds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getElapsedSeconds() {
|
||||
return super.getElapsedSeconds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Importance getImportance() {
|
||||
return super.getImportance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNotes() {
|
||||
return super.getNotes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getPreferredDueDate() {
|
||||
return super.getPreferredDueDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getTimerStart() {
|
||||
return super.getTimerStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimerStart(Date timerStart) {
|
||||
super.setTimerStart(timerStart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressPercentage(int progressPercentage) {
|
||||
super.setProgressPercentage(progressPercentage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setElapsedSeconds(int elapsedSeconds) {
|
||||
super.setElapsedSeconds(elapsedSeconds);
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.timsu.astrid.utilities;
|
||||
|
||||
import android.content.res.Resources;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
|
||||
public class DateUtilities {
|
||||
|
||||
/**
|
||||
* Format a time into the format: 5 days, 3 hours, 2 minutes
|
||||
*
|
||||
* @param r Resources to get strings from
|
||||
* @param timeInSeconds
|
||||
* @param unitsToShow number of units to show (i.e. if 2, then 5 hours
|
||||
* 3 minutes 2 seconds is truncated to 5 hours 3 minutes)
|
||||
* @return
|
||||
*/
|
||||
public static String getDurationString(Resources r, int timeInSeconds,
|
||||
int unitsToShow) {
|
||||
short days, hours, minutes, seconds;
|
||||
short unitsDisplayed = 0;
|
||||
|
||||
if(timeInSeconds == 0)
|
||||
return r.getQuantityString(R.plurals.Nseconds, 0, 0);
|
||||
|
||||
days = (short)(timeInSeconds / 24 / 3600);
|
||||
timeInSeconds -= days*24*3600;
|
||||
hours = (short)(timeInSeconds / 3600);
|
||||
timeInSeconds -= hours * 3600;
|
||||
minutes = (short)(timeInSeconds / 60);
|
||||
timeInSeconds -= minutes * 60;
|
||||
seconds = (short)timeInSeconds;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
if(days > 0) {
|
||||
result.append(r.getQuantityString(R.plurals.Ndays, days, days)).
|
||||
append(" ");
|
||||
unitsDisplayed++;
|
||||
}
|
||||
if(unitsDisplayed < unitsToShow && hours > 0) {
|
||||
result.append(r.getQuantityString(R.plurals.Nhours, hours,
|
||||
hours)).
|
||||
append(" ");
|
||||
unitsDisplayed++;
|
||||
}
|
||||
if(unitsDisplayed < unitsToShow && minutes > 0) {
|
||||
result.append(r.getQuantityString(R.plurals.Nminutes, minutes,
|
||||
minutes)).append(" ");
|
||||
unitsDisplayed++;
|
||||
}
|
||||
if(unitsDisplayed < unitsToShow && seconds > 0) {
|
||||
result.append(r.getQuantityString(R.plurals.Nseconds, seconds,
|
||||
seconds)).append(" ");
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a time into the format: 5 d, 3 h, 2 m
|
||||
*
|
||||
* @param r Resources to get strings from
|
||||
* @param timeInSeconds
|
||||
* @param unitsToShow number of units to show
|
||||
* @return
|
||||
*/
|
||||
public static String getShortDurationString(Resources r, int timeInSeconds,
|
||||
int unitsToShow) {
|
||||
short days, hours, minutes, seconds;
|
||||
short unitsDisplayed = 0;
|
||||
|
||||
if(timeInSeconds == 0)
|
||||
return "0 s";
|
||||
|
||||
days = (short)(timeInSeconds / 24 / 3600);
|
||||
timeInSeconds -= days*24*3600;
|
||||
hours = (short)(timeInSeconds / 3600);
|
||||
timeInSeconds -= hours * 3600;
|
||||
minutes = (short)(timeInSeconds / 60);
|
||||
timeInSeconds -= minutes * 60;
|
||||
seconds = (short)timeInSeconds;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
if(days > 0) {
|
||||
result.append(days).append(" d ");
|
||||
unitsDisplayed++;
|
||||
}
|
||||
if(unitsDisplayed < unitsToShow && hours > 0) {
|
||||
result.append(hours).append(" h ");
|
||||
unitsDisplayed++;
|
||||
}
|
||||
if(unitsDisplayed < unitsToShow && minutes > 0) {
|
||||
result.append(minutes).append(" m ");
|
||||
unitsDisplayed++;
|
||||
}
|
||||
if(unitsDisplayed < unitsToShow && seconds < 0) {
|
||||
result.append(hours).append(" s ");
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,422 @@
|
||||
package com.timsu.astrid.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.text.InputFilter;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.NumberKeyListener;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnFocusChangeListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
|
||||
public class NumberPicker extends LinearLayout implements OnClickListener,
|
||||
OnFocusChangeListener, OnLongClickListener {
|
||||
|
||||
public interface OnChangedListener {
|
||||
void onChanged(NumberPicker picker, int oldVal, int newVal);
|
||||
}
|
||||
|
||||
public interface Formatter {
|
||||
String toString(int value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a custom NumberPicker formatting callback to use two-digit minutes
|
||||
* strings like "01". Keeping a static formatter etc. is the most efficient
|
||||
* way to do this; it avoids creating temporary objects on every call to
|
||||
* format().
|
||||
*/
|
||||
public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() {
|
||||
final StringBuilder mBuilder = new StringBuilder();
|
||||
final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
|
||||
final Object[] mArgs = new Object[1];
|
||||
|
||||
public String toString(int value) {
|
||||
mArgs[0] = value;
|
||||
mBuilder.delete(0, mBuilder.length());
|
||||
mFmt.format("%02d", mArgs);
|
||||
return mFmt.toString();
|
||||
}
|
||||
};
|
||||
|
||||
private int incrementBy;
|
||||
public void setIncrementBy(int incrementBy) {
|
||||
this.incrementBy = incrementBy;
|
||||
}
|
||||
|
||||
private final Handler mHandler;
|
||||
private final Runnable mRunnable = new Runnable() {
|
||||
public void run() {
|
||||
if (mIncrement) {
|
||||
changeCurrent(mCurrent + incrementBy, mSlideUpInAnimation, mSlideUpOutAnimation);
|
||||
mHandler.postDelayed(this, mSpeed);
|
||||
} else if (mDecrement) {
|
||||
changeCurrent(mCurrent - incrementBy, mSlideDownInAnimation, mSlideDownOutAnimation);
|
||||
mHandler.postDelayed(this, mSpeed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final TextView mText;
|
||||
private final InputFilter mInputFilter;
|
||||
private final InputFilter mNumberInputFilter;
|
||||
|
||||
private final Animation mSlideUpOutAnimation;
|
||||
private final Animation mSlideUpInAnimation;
|
||||
private final Animation mSlideDownOutAnimation;
|
||||
private final Animation mSlideDownInAnimation;
|
||||
|
||||
private String[] mDisplayedValues;
|
||||
private int mStart;
|
||||
private int mEnd;
|
||||
private int mCurrent;
|
||||
private int mPrevious;
|
||||
private OnChangedListener mListener;
|
||||
private Formatter mFormatter;
|
||||
private long mSpeed = 300;
|
||||
|
||||
private boolean mIncrement;
|
||||
private boolean mDecrement;
|
||||
|
||||
public NumberPicker(Context context, int incrementBy) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public NumberPicker(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs);
|
||||
setOrientation(VERTICAL);
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mInflater.inflate(R.layout.number_picker, this, true);
|
||||
mHandler = new Handler();
|
||||
mInputFilter = new NumberPickerInputFilter();
|
||||
mNumberInputFilter = new NumberRangeKeyListener();
|
||||
mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
|
||||
mIncrementButton.setOnClickListener(this);
|
||||
mIncrementButton.setOnLongClickListener(this);
|
||||
mIncrementButton.setNumberPicker(this);
|
||||
mDecrementButton = (NumberPickerButton) findViewById(R.id.decrement);
|
||||
mDecrementButton.setOnClickListener(this);
|
||||
mDecrementButton.setOnLongClickListener(this);
|
||||
mDecrementButton.setNumberPicker(this);
|
||||
|
||||
mText = (TextView) findViewById(R.id.timepicker_input);
|
||||
mText.setOnFocusChangeListener(this);
|
||||
mText.setFilters(new InputFilter[] { mInputFilter });
|
||||
|
||||
mSlideUpOutAnimation = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
|
||||
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, -100);
|
||||
mSlideUpOutAnimation.setDuration(200);
|
||||
mSlideUpInAnimation = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
|
||||
Animation.RELATIVE_TO_SELF, 100, Animation.RELATIVE_TO_SELF, 0);
|
||||
mSlideUpInAnimation.setDuration(200);
|
||||
mSlideDownOutAnimation = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
|
||||
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 100);
|
||||
mSlideDownOutAnimation.setDuration(200);
|
||||
mSlideDownInAnimation = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
|
||||
Animation.RELATIVE_TO_SELF, -100, Animation.RELATIVE_TO_SELF, 0);
|
||||
mSlideDownInAnimation.setDuration(200);
|
||||
|
||||
if (!isEnabled()) {
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
mIncrementButton.setEnabled(enabled);
|
||||
mDecrementButton.setEnabled(enabled);
|
||||
mText.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void setOnChangeListener(OnChangedListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void setFormatter(Formatter formatter) {
|
||||
mFormatter = formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the range of numbers allowed for the number picker. The current value
|
||||
* will be automatically set to the start.
|
||||
*
|
||||
* @param start
|
||||
* the start of the range (inclusive)
|
||||
* @param end
|
||||
* the end of the range (inclusive)
|
||||
*/
|
||||
public void setRange(int start, int end) {
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
mCurrent = start;
|
||||
updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the range of numbers allowed for the number picker. The current value
|
||||
* will be automatically set to the start. Also provide a mapping for values
|
||||
* used to display to the user.
|
||||
*
|
||||
* @param start
|
||||
* the start of the range (inclusive)
|
||||
* @param end
|
||||
* the end of the range (inclusive)
|
||||
* @param displayedValues
|
||||
* the values displayed to the user.
|
||||
*/
|
||||
public void setRange(int start, int end, String[] displayedValues) {
|
||||
mDisplayedValues = displayedValues;
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
mCurrent = start;
|
||||
updateView();
|
||||
}
|
||||
|
||||
public void setCurrent(int current) {
|
||||
mCurrent = current;
|
||||
updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* The speed (in milliseconds) at which the numbers will scroll when the the
|
||||
* +/- buttons are longpressed. Default is 300ms.
|
||||
*/
|
||||
public void setSpeed(long speed) {
|
||||
mSpeed = speed;
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
|
||||
/*
|
||||
* The text view may still have focus so clear it's focus which will
|
||||
* trigger the on focus changed and any typed values to be pulled.
|
||||
*/
|
||||
mText.clearFocus();
|
||||
|
||||
// now perform the increment/decrement
|
||||
if (R.id.increment == v.getId()) {
|
||||
changeCurrent(mCurrent + incrementBy, mSlideUpInAnimation,
|
||||
mSlideUpOutAnimation);
|
||||
} else if (R.id.decrement == v.getId()) {
|
||||
changeCurrent(mCurrent - incrementBy, mSlideDownInAnimation,
|
||||
mSlideDownOutAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
private String formatNumber(int value) {
|
||||
return (mFormatter != null) ? mFormatter.toString(value) : String
|
||||
.valueOf(value);
|
||||
}
|
||||
|
||||
private void changeCurrent(int current, Animation in, Animation out) {
|
||||
|
||||
// Wrap around the values if we go past the start or end
|
||||
if (current > mEnd) {
|
||||
current = mStart;
|
||||
} else if (current < mStart) {
|
||||
current = mEnd;
|
||||
}
|
||||
mPrevious = mCurrent;
|
||||
mCurrent = current;
|
||||
notifyChange();
|
||||
updateView();
|
||||
}
|
||||
|
||||
private void notifyChange() {
|
||||
if (mListener != null) {
|
||||
mListener.onChanged(this, mPrevious, mCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateView() {
|
||||
|
||||
/*
|
||||
* If we don't have displayed values then use the current number else
|
||||
* find the correct value in the displayed values for the current
|
||||
* number.
|
||||
*/
|
||||
if (mDisplayedValues == null) {
|
||||
mText.setText(formatNumber(mCurrent));
|
||||
} else {
|
||||
mText.setText(mDisplayedValues[mCurrent - mStart]);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCurrentView(CharSequence str) {
|
||||
int val = getSelectedPos(str.toString());
|
||||
if ((val >= mStart) && (val <= mEnd)) {
|
||||
mPrevious = mCurrent;
|
||||
mCurrent = val;
|
||||
notifyChange();
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
|
||||
/*
|
||||
* When focus is lost check that the text field has valid values.
|
||||
*/
|
||||
if (!hasFocus) {
|
||||
String str = String.valueOf(((TextView) v).getText());
|
||||
if ("".equals(str)) {
|
||||
|
||||
// Restore to the old value as we don't allow empty values
|
||||
updateView();
|
||||
} else {
|
||||
|
||||
// Check the new value and ensure it's in range
|
||||
validateCurrentView(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We start the long click here but rely on the {@link NumberPickerButton}
|
||||
* to inform us when the long click has ended.
|
||||
*/
|
||||
public boolean onLongClick(View v) {
|
||||
|
||||
/*
|
||||
* The text view may still have focus so clear it's focus which will
|
||||
* trigger the on focus changed and any typed values to be pulled.
|
||||
*/
|
||||
mText.clearFocus();
|
||||
|
||||
if (R.id.increment == v.getId()) {
|
||||
mIncrement = true;
|
||||
mHandler.post(mRunnable);
|
||||
} else if (R.id.decrement == v.getId()) {
|
||||
mDecrement = true;
|
||||
mHandler.post(mRunnable);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void cancelIncrement() {
|
||||
mIncrement = false;
|
||||
}
|
||||
|
||||
public void cancelDecrement() {
|
||||
mDecrement = false;
|
||||
}
|
||||
|
||||
private static final char[] DIGIT_CHARACTERS = new char[] { '0', '1', '2',
|
||||
'3', '4', '5', '6', '7', '8', '9' };
|
||||
|
||||
private NumberPickerButton mIncrementButton;
|
||||
private NumberPickerButton mDecrementButton;
|
||||
|
||||
private class NumberPickerInputFilter implements InputFilter {
|
||||
public CharSequence filter(CharSequence source, int start, int end,
|
||||
Spanned dest, int dstart, int dend) {
|
||||
if (mDisplayedValues == null) {
|
||||
return mNumberInputFilter.filter(source, start, end, dest,
|
||||
dstart, dend);
|
||||
}
|
||||
CharSequence filtered = String.valueOf(source.subSequence(start,
|
||||
end));
|
||||
String result = String.valueOf(dest.subSequence(0, dstart))
|
||||
+ filtered + dest.subSequence(dend, dest.length());
|
||||
String str = String.valueOf(result).toLowerCase();
|
||||
for (String val : mDisplayedValues) {
|
||||
val = val.toLowerCase();
|
||||
if (val.startsWith(str)) {
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private class NumberRangeKeyListener extends NumberKeyListener {
|
||||
|
||||
@Override
|
||||
protected char[] getAcceptedChars() {
|
||||
return DIGIT_CHARACTERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence filter(CharSequence source, int start, int end,
|
||||
Spanned dest, int dstart, int dend) {
|
||||
|
||||
CharSequence filtered = super.filter(source, start, end, dest,
|
||||
dstart, dend);
|
||||
if (filtered == null) {
|
||||
filtered = source.subSequence(start, end);
|
||||
}
|
||||
|
||||
String result = String.valueOf(dest.subSequence(0, dstart))
|
||||
+ filtered + dest.subSequence(dend, dest.length());
|
||||
|
||||
if ("".equals(result)) {
|
||||
return result;
|
||||
}
|
||||
int val = getSelectedPos(result);
|
||||
|
||||
/*
|
||||
* Ensure the user can't type in a value greater than the max
|
||||
* allowed. We have to allow less than min as the user might want to
|
||||
* delete some numbers and then type a new number.
|
||||
*/
|
||||
if (val > mEnd) {
|
||||
return "";
|
||||
} else {
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getSelectedPos(String str) {
|
||||
if (mDisplayedValues == null) {
|
||||
return Integer.parseInt(str);
|
||||
} else {
|
||||
for (int i = 0; i < mDisplayedValues.length; i++) {
|
||||
|
||||
/* Don't force the user to type in jan when ja will do */
|
||||
str = str.toLowerCase();
|
||||
if (mDisplayedValues[i].toLowerCase().startsWith(str)) {
|
||||
return mStart + i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The user might have typed in a number into the month field i.e.
|
||||
* 10 instead of OCT so support that too.
|
||||
*/
|
||||
try {
|
||||
return Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
/* Ignore as if it's not a number we don't care */
|
||||
}
|
||||
}
|
||||
return mStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current value.
|
||||
*/
|
||||
public int getCurrent() {
|
||||
return mCurrent;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.timsu.astrid.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
|
||||
/**
|
||||
* This class exists purely to cancel long click events.
|
||||
*/
|
||||
public class NumberPickerButton extends ImageButton {
|
||||
|
||||
private NumberPicker mNumberPicker;
|
||||
|
||||
public NumberPickerButton(Context context, AttributeSet attrs,
|
||||
int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public NumberPickerButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public NumberPickerButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void setNumberPicker(NumberPicker picker) {
|
||||
mNumberPicker = picker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
cancelLongpressIfRequired(event);
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTrackballEvent(MotionEvent event) {
|
||||
cancelLongpressIfRequired(event);
|
||||
return super.onTrackballEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
|
||||
|| (keyCode == KeyEvent.KEYCODE_ENTER)) {
|
||||
cancelLongpress();
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
private void cancelLongpressIfRequired(MotionEvent event) {
|
||||
if ((event.getAction() == MotionEvent.ACTION_CANCEL)
|
||||
|| (event.getAction() == MotionEvent.ACTION_UP)) {
|
||||
cancelLongpress();
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelLongpress() {
|
||||
if (R.id.increment == getId()) {
|
||||
mNumberPicker.cancelIncrement();
|
||||
} else if (R.id.decrement == getId()) {
|
||||
mNumberPicker.cancelDecrement();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.timsu.astrid.widget;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
|
||||
public class NumberPickerDialog extends AlertDialog implements OnClickListener {
|
||||
|
||||
public interface OnNumberPickedListener {
|
||||
void onNumberPicked(NumberPicker view, int number);
|
||||
}
|
||||
|
||||
private final NumberPicker mPicker;
|
||||
private final OnNumberPickedListener mCallback;
|
||||
|
||||
public NumberPickerDialog(Context context, OnNumberPickedListener callBack,
|
||||
String title, int initialValue, int incrementBy, int start, int end) {
|
||||
super(context);
|
||||
mCallback = callBack;
|
||||
|
||||
setButton(context.getText(android.R.string.ok), this);
|
||||
setButton2(context.getText(android.R.string.cancel), (OnClickListener) null);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.number_picker_dialog, null);
|
||||
setView(view);
|
||||
|
||||
setTitle(title);
|
||||
mPicker = (NumberPicker) view.findViewById(R.id.numberPicker);
|
||||
mPicker.setCurrent(initialValue);
|
||||
mPicker.setIncrementBy(incrementBy);
|
||||
mPicker.setRange(start, end);
|
||||
}
|
||||
|
||||
public void setInitialValue(int initialValue) {
|
||||
mPicker.setCurrent(initialValue);
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (mCallback != null) {
|
||||
mPicker.clearFocus();
|
||||
mCallback.onNumberPicked(mPicker, mPicker.getCurrent());
|
||||
}
|
||||
}
|
||||
}
|