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