@ -0,0 +1,32 @@
|
|||||||
|
#built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
|
||||||
|
# files for the dex VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Windows thumbnail db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# OSX files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Eclipse project files
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
.idea
|
||||||
|
#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
|
||||||
|
.gradle
|
||||||
|
build/
|
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.isoron.uhabits"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0" >
|
||||||
|
|
||||||
|
<uses-sdk
|
||||||
|
android:minSdkVersion="14"
|
||||||
|
android:targetSdkVersion="20" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:name="com.activeandroid.app.Application"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@android:style/Theme.Holo.Light" >
|
||||||
|
<meta-data
|
||||||
|
android:name="AA_DB_NAME"
|
||||||
|
android:value="uhabits.db" />
|
||||||
|
<meta-data
|
||||||
|
android:name="AA_DB_VERSION"
|
||||||
|
android:value="2" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="org.isoron.uhabits.MainActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
After Width: | Height: | Size: 195 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 48 KiB |
@ -0,0 +1,20 @@
|
|||||||
|
# To enable ProGuard in your project, edit project.properties
|
||||||
|
# to define the proguard.config property as described in that file.
|
||||||
|
#
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the ProGuard
|
||||||
|
# include property in project.properties.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
@ -0,0 +1,14 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system edit
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
#
|
||||||
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
|
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-18
|
After Width: | Height: | Size: 196 B |
After Width: | Height: | Size: 187 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 290 B |
After Width: | Height: | Size: 181 B |
After Width: | Height: | Size: 552 B |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 164 B |
After Width: | Height: | Size: 151 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 256 B |
After Width: | Height: | Size: 134 B |
After Width: | Height: | Size: 394 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 231 B |
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 426 B |
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 716 B |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 331 B |
After Width: | Height: | Size: 325 B |
After Width: | Height: | Size: 464 B |
After Width: | Height: | Size: 315 B |
After Width: | Height: | Size: 504 B |
After Width: | Height: | Size: 268 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 9.2 KiB |
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2010 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_window_focused="false" android:state_enabled="true" android:drawable="@drawable/apptheme_textfield_default_holo_light" />
|
||||||
|
<item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/apptheme_textfield_disabled_holo_light" />
|
||||||
|
<item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/apptheme_textfield_activated_holo_light" />
|
||||||
|
<item android:state_enabled="true" android:state_activated="true" android:drawable="@drawable/apptheme_textfield_focused_holo_light" />
|
||||||
|
<item android:state_enabled="true" android:drawable="@drawable/apptheme_textfield_default_holo_light" />
|
||||||
|
<item android:state_focused="true" android:drawable="@drawable/apptheme_textfield_disabled_focused_holo_light" />
|
||||||
|
<item android:drawable="@drawable/apptheme_textfield_disabled_holo_light" />
|
||||||
|
</selector>
|
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2013 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.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" />
|
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item android:top="40dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<gradient
|
||||||
|
android:startColor="#30000000"
|
||||||
|
android:endColor="#00000000"
|
||||||
|
android:angle="270"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:top="21dp" android:bottom="2dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<gradient
|
||||||
|
android:angle="270"
|
||||||
|
android:endColor="#ccffffff"
|
||||||
|
android:startColor="#ffffff" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:bottom="21dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<solid android:color="#ffffff" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
|
||||||
|
</layer-list>
|
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item android:bottom="28dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<gradient
|
||||||
|
android:angle="270"
|
||||||
|
android:endColor="#00000000"
|
||||||
|
android:height="1px"
|
||||||
|
android:startColor="#08000000" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
@ -0,0 +1,7 @@
|
|||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:drawable="@drawable/habits_item_check_pressed" android:state_pressed="true"></item>
|
||||||
|
<item android:drawable="@drawable/habits_item_check_pressed" android:state_focused="true"></item>
|
||||||
|
<item android:drawable="@drawable/habits_item_check_normal"></item>
|
||||||
|
|
||||||
|
</selector>
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<item>
|
||||||
|
<shape android:shape="oval" >
|
||||||
|
<gradient
|
||||||
|
android:endColor="#00000000"
|
||||||
|
android:gradientRadius="@dimen/radius"
|
||||||
|
android:startColor="#50000000"
|
||||||
|
android:type="radial" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:bottom="6dp"
|
||||||
|
android:left="4dp"
|
||||||
|
android:right="4dp"
|
||||||
|
android:top="2dp">
|
||||||
|
<shape android:shape="oval" >
|
||||||
|
<solid android:color="#ffffff" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<item>
|
||||||
|
<shape android:shape="oval" >
|
||||||
|
<gradient
|
||||||
|
android:endColor="#00000000"
|
||||||
|
android:gradientRadius="@dimen/radius"
|
||||||
|
android:startColor="#50000000"
|
||||||
|
android:type="radial" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:bottom="6dp"
|
||||||
|
android:left="4dp"
|
||||||
|
android:right="4dp"
|
||||||
|
android:top="2dp">
|
||||||
|
<shape android:shape="oval" >
|
||||||
|
<solid android:color="#20000000" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2013 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.
|
||||||
|
-->
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center" >
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="28dp" >
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@android:id/progress"
|
||||||
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center" />
|
||||||
|
|
||||||
|
<com.android.colorpicker.ColorPickerPalette
|
||||||
|
android:id="@+id/color_picker"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</FrameLayout>
|
||||||
|
</ScrollView>
|
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2013 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">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/color_picker_swatch"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/color_picker_checkmark"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:src="@drawable/ic_colorpicker_swatch_selected"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</merge>
|
@ -0,0 +1,135 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:context="org.isoron.uhabits.dialogs.EditHabitFragment"
|
||||||
|
tools:ignore="MergeRootFrame" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/formPanel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/namePanel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/input_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="10"
|
||||||
|
android:background="@drawable/apptheme_edit_text_holo_light"
|
||||||
|
android:ems="10"
|
||||||
|
android:hint="Name"
|
||||||
|
android:textColor="#cc2222" >
|
||||||
|
|
||||||
|
<requestFocus />
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_pick_color"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:src="@drawable/ic_action_pick_color" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/input_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="10"
|
||||||
|
android:hint="Description"
|
||||||
|
android:inputType="textMultiLine" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Repeat " />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/input_freq_num"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="7"
|
||||||
|
android:maxLength="2"
|
||||||
|
android:inputType="number"
|
||||||
|
android:gravity="center"
|
||||||
|
android:ems="2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView3"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=" times every " />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/input_freq_den"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="7"
|
||||||
|
android:maxLength="2"
|
||||||
|
android:inputType="number"
|
||||||
|
android:gravity="center"
|
||||||
|
android:ems="2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView5"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=" days" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/buttonPanel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:divider="?android:attr/dividerHorizontal"
|
||||||
|
android:dividerPadding="0dip"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:showDividers="beginning" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="?android:attr/buttonBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:onClick="onClick"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_discard"
|
||||||
|
style="?android:attr/buttonBarButtonStyle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Discard" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_save"
|
||||||
|
style="?android:attr/buttonBarButtonStyle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Save" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -0,0 +1,15 @@
|
|||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context="org.isoron.uhabits.MainActivity"
|
||||||
|
tools:ignore="MergeRootFrame" >
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/fragment1"
|
||||||
|
android:name="org.isoron.uhabits.dialogs.ShowHabitsFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:dslv="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#ffffff" >
|
||||||
|
|
||||||
|
<!-- <ListView -->
|
||||||
|
<!-- android:id="@+id/listView" -->
|
||||||
|
<!-- android:layout_width="match_parent" -->
|
||||||
|
<!-- android:layout_height="match_parent" -->
|
||||||
|
<!-- android:divider="#00000000" -->
|
||||||
|
<!-- android:dividerHeight="0dp"> -->
|
||||||
|
<!-- </ListView> -->
|
||||||
|
|
||||||
|
<com.mobeta.android.dslv.DragSortListView
|
||||||
|
android:id="@+id/listView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:divider="#00000000"
|
||||||
|
android:dividerHeight="0dp"
|
||||||
|
dslv:drag_enabled="true"
|
||||||
|
dslv:drag_handle_id="@drawable/habits_header_check"
|
||||||
|
dslv:drag_start_mode="onMove"
|
||||||
|
dslv:float_alpha="0.5"
|
||||||
|
dslv:sort_enabled="true"
|
||||||
|
dslv:track_drag_sort="false"
|
||||||
|
dslv:use_default_controller="true" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:background="@drawable/habits_header" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStarHeader"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="1dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvNameHeader"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingLeft="0dp"
|
||||||
|
android:paddingRight="6dp"
|
||||||
|
android:paddingTop="6dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llButtonsHeader"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Button xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/tvCheck"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/habits_header_check"
|
||||||
|
android:focusable="false"
|
||||||
|
android:minHeight="42dp"
|
||||||
|
android:minWidth="42dp"
|
||||||
|
android:textSize="10sp" />
|
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/habits_item"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStar"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="1dp"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvName"
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingLeft="0dp"
|
||||||
|
android:paddingRight="6dp"
|
||||||
|
android:paddingTop="6dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llButtons"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:orientation="horizontal" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Button xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/tvCheck"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginRight="18dp"
|
||||||
|
android:minHeight="42dp"
|
||||||
|
android:minWidth="42dp"
|
||||||
|
android:focusable="false"
|
||||||
|
android:background="@drawable/habits_item_check" />
|
@ -0,0 +1,11 @@
|
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:context="org.isoron.uhabits.MainActivity" >
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_settings"
|
||||||
|
android:orderInCategory="100"
|
||||||
|
android:showAsAction="never"
|
||||||
|
android:title="@string/action_settings"/>
|
||||||
|
|
||||||
|
</menu>
|
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_edit_habit"
|
||||||
|
android:title="@string/edit">
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_delete_habit"
|
||||||
|
android:title="@string/delete">
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</menu>
|
@ -0,0 +1,9 @@
|
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:context="org.isoron.uhabits.MainActivity" >
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_add"
|
||||||
|
android:title="@string/add_habit" android:showAsAction="always" android:icon="@drawable/ic_action_add"/>
|
||||||
|
|
||||||
|
</menu>
|
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<item name="radius" format="float" type="dimen">30</item>
|
||||||
|
</resources>
|
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<item name="radius" format="float" type="dimen">15</item>
|
||||||
|
</resources>
|
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<item name="radius" format="float" type="dimen">20</item>
|
||||||
|
</resources>
|
@ -0,0 +1,11 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Base application theme for API 11+. This theme completely replaces
|
||||||
|
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
||||||
|
-->
|
||||||
|
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
||||||
|
<!-- API 11 theme customizations can go here. -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,12 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Base application theme for API 14+. This theme completely replaces
|
||||||
|
AppBaseTheme from BOTH res/values/styles.xml and
|
||||||
|
res/values-v11/styles.xml on API 14+ devices.
|
||||||
|
-->
|
||||||
|
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||||
|
<!-- API 14 theme customizations can go here. -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,10 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Example customization of dimensions originally defined in res/values/dimens.xml
|
||||||
|
(such as screen margins) for screens with more than 820dp of available width. This
|
||||||
|
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
|
||||||
|
-->
|
||||||
|
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<item name="radius" format="float" type="dimen">40</item>
|
||||||
|
</resources>
|
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<item name="radius" format="float" type="dimen">60</item>
|
||||||
|
</resources>
|
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<item name="radius" format="float" type="dimen">80</item>
|
||||||
|
</resources>
|
@ -0,0 +1,13 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
|
||||||
|
<!-- Color picker -->
|
||||||
|
<dimen name="color_swatch_large">64dip</dimen>
|
||||||
|
<dimen name="color_swatch_small">48dip</dimen>
|
||||||
|
<dimen name="color_swatch_margins_large">8dip</dimen>
|
||||||
|
<dimen name="color_swatch_margins_small">4dip</dimen>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="DragSortListView">
|
||||||
|
<attr name="collapsed_height" format="dimension" />
|
||||||
|
<attr name="drag_scroll_start" format="float" />
|
||||||
|
<attr name="max_drag_scroll_speed" format="float" />
|
||||||
|
<attr name="float_background_color" format="color" />
|
||||||
|
<attr name="remove_mode">
|
||||||
|
<enum name="clickRemove" value="0" />
|
||||||
|
<enum name="flingRemove" value="1" />
|
||||||
|
</attr>
|
||||||
|
<attr name="track_drag_sort" format="boolean"/>
|
||||||
|
<attr name="float_alpha" format="float"/>
|
||||||
|
<attr name="slide_shuffle_speed" format="float"/>
|
||||||
|
<attr name="remove_animation_duration" format="integer"/>
|
||||||
|
<attr name="drop_animation_duration" format="integer"/>
|
||||||
|
<attr name="drag_enabled" format="boolean" />
|
||||||
|
<attr name="sort_enabled" format="boolean" />
|
||||||
|
<attr name="remove_enabled" format="boolean" />
|
||||||
|
<attr name="drag_start_mode">
|
||||||
|
<enum name="onDown" value="0" />
|
||||||
|
<enum name="onMove" value="1" />
|
||||||
|
<enum name="onLongPress" value="2"/>
|
||||||
|
</attr>
|
||||||
|
<attr name="drag_handle_id" format="integer" />
|
||||||
|
<attr name="fling_handle_id" format="integer" />
|
||||||
|
<attr name="click_remove_id" format="integer" />
|
||||||
|
<attr name="use_default_controller" format="boolean" />
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
@ -0,0 +1,372 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="fa_glass"></string>
|
||||||
|
<string name="fa_music"></string>
|
||||||
|
<string name="fa_search"></string>
|
||||||
|
<string name="fa_envelope_o"></string>
|
||||||
|
<string name="fa_heart"></string>
|
||||||
|
<string name="fa_star"></string>
|
||||||
|
<string name="fa_star_o"></string>
|
||||||
|
<string name="fa_user"></string>
|
||||||
|
<string name="fa_film"></string>
|
||||||
|
<string name="fa_th_large"></string>
|
||||||
|
<string name="fa_th"></string>
|
||||||
|
<string name="fa_th_list"></string>
|
||||||
|
<string name="fa_check"></string>
|
||||||
|
<string name="fa_times"></string>
|
||||||
|
<string name="fa_search_plus"></string>
|
||||||
|
<string name="fa_search_minus"></string>
|
||||||
|
<string name="fa_power_off"></string>
|
||||||
|
<string name="fa_signal"></string>
|
||||||
|
<string name="fa_cog"></string>
|
||||||
|
<string name="fa_trash_o"></string>
|
||||||
|
<string name="fa_home"></string>
|
||||||
|
<string name="fa_file_o"></string>
|
||||||
|
<string name="fa_clock_o"></string>
|
||||||
|
<string name="fa_road"></string>
|
||||||
|
<string name="fa_download"></string>
|
||||||
|
<string name="fa_arrow_circle_o_down"></string>
|
||||||
|
<string name="fa_arrow_circle_o_up"></string>
|
||||||
|
<string name="fa_inbox"></string>
|
||||||
|
<string name="fa_play_circle_o"></string>
|
||||||
|
<string name="fa_repeat"></string>
|
||||||
|
<string name="fa_refresh"></string>
|
||||||
|
<string name="fa_list_alt"></string>
|
||||||
|
<string name="fa_lock"></string>
|
||||||
|
<string name="fa_flag"></string>
|
||||||
|
<string name="fa_headphones"></string>
|
||||||
|
<string name="fa_volume_off"></string>
|
||||||
|
<string name="fa_volume_down"></string>
|
||||||
|
<string name="fa_volume_up"></string>
|
||||||
|
<string name="fa_qrcode"></string>
|
||||||
|
<string name="fa_barcode"></string>
|
||||||
|
<string name="fa_tag"></string>
|
||||||
|
<string name="fa_tags"></string>
|
||||||
|
<string name="fa_book"></string>
|
||||||
|
<string name="fa_bookmark"></string>
|
||||||
|
<string name="fa_print"></string>
|
||||||
|
<string name="fa_camera"></string>
|
||||||
|
<string name="fa_font"></string>
|
||||||
|
<string name="fa_bold"></string>
|
||||||
|
<string name="fa_italic"></string>
|
||||||
|
<string name="fa_text_height"></string>
|
||||||
|
<string name="fa_text_width"></string>
|
||||||
|
<string name="fa_align_left"></string>
|
||||||
|
<string name="fa_align_center"></string>
|
||||||
|
<string name="fa_align_right"></string>
|
||||||
|
<string name="fa_align_justify"></string>
|
||||||
|
<string name="fa_list"></string>
|
||||||
|
<string name="fa_outdent"></string>
|
||||||
|
<string name="fa_indent"></string>
|
||||||
|
<string name="fa_video_camera"></string>
|
||||||
|
<string name="fa_picture_o"></string>
|
||||||
|
<string name="fa_pencil"></string>
|
||||||
|
<string name="fa_map_marker"></string>
|
||||||
|
<string name="fa_adjust"></string>
|
||||||
|
<string name="fa_tint"></string>
|
||||||
|
<string name="fa_pencil_square_o"></string>
|
||||||
|
<string name="fa_share_square_o"></string>
|
||||||
|
<string name="fa_check_square_o"></string>
|
||||||
|
<string name="fa_arrows"></string>
|
||||||
|
<string name="fa_step_backward"></string>
|
||||||
|
<string name="fa_fast_backward"></string>
|
||||||
|
<string name="fa_backward"></string>
|
||||||
|
<string name="fa_play"></string>
|
||||||
|
<string name="fa_pause"></string>
|
||||||
|
<string name="fa_stop"></string>
|
||||||
|
<string name="fa_forward"></string>
|
||||||
|
<string name="fa_fast_forward"></string>
|
||||||
|
<string name="fa_step_forward"></string>
|
||||||
|
<string name="fa_eject"></string>
|
||||||
|
<string name="fa_chevron_left"></string>
|
||||||
|
<string name="fa_chevron_right"></string>
|
||||||
|
<string name="fa_plus_circle"></string>
|
||||||
|
<string name="fa_minus_circle"></string>
|
||||||
|
<string name="fa_times_circle"></string>
|
||||||
|
<string name="fa_check_circle"></string>
|
||||||
|
<string name="fa_question_circle"></string>
|
||||||
|
<string name="fa_info_circle"></string>
|
||||||
|
<string name="fa_crosshairs"></string>
|
||||||
|
<string name="fa_times_circle_o"></string>
|
||||||
|
<string name="fa_check_circle_o"></string>
|
||||||
|
<string name="fa_ban"></string>
|
||||||
|
<string name="fa_arrow_left"></string>
|
||||||
|
<string name="fa_arrow_right"></string>
|
||||||
|
<string name="fa_arrow_up"></string>
|
||||||
|
<string name="fa_arrow_down"></string>
|
||||||
|
<string name="fa_share"></string>
|
||||||
|
<string name="fa_expand"></string>
|
||||||
|
<string name="fa_compress"></string>
|
||||||
|
<string name="fa_plus"></string>
|
||||||
|
<string name="fa_minus"></string>
|
||||||
|
<string name="fa_asterisk"></string>
|
||||||
|
<string name="fa_exclamation_circle"></string>
|
||||||
|
<string name="fa_gift"></string>
|
||||||
|
<string name="fa_leaf"></string>
|
||||||
|
<string name="fa_fire"></string>
|
||||||
|
<string name="fa_eye"></string>
|
||||||
|
<string name="fa_eye_slash"></string>
|
||||||
|
<string name="fa_exclamation_triangle"></string>
|
||||||
|
<string name="fa_plane"></string>
|
||||||
|
<string name="fa_calendar"></string>
|
||||||
|
<string name="fa_random"></string>
|
||||||
|
<string name="fa_comment"></string>
|
||||||
|
<string name="fa_magnet"></string>
|
||||||
|
<string name="fa_chevron_up"></string>
|
||||||
|
<string name="fa_chevron_down"></string>
|
||||||
|
<string name="fa_retweet"></string>
|
||||||
|
<string name="fa_shopping_cart"></string>
|
||||||
|
<string name="fa_folder"></string>
|
||||||
|
<string name="fa_folder_open"></string>
|
||||||
|
<string name="fa_arrows_v"></string>
|
||||||
|
<string name="fa_arrows_h"></string>
|
||||||
|
<string name="fa_bar_chart_o"></string>
|
||||||
|
<string name="fa_twitter_square"></string>
|
||||||
|
<string name="fa_facebook_square"></string>
|
||||||
|
<string name="fa_camera_retro"></string>
|
||||||
|
<string name="fa_key"></string>
|
||||||
|
<string name="fa_cogs"></string>
|
||||||
|
<string name="fa_comments"></string>
|
||||||
|
<string name="fa_thumbs_o_up"></string>
|
||||||
|
<string name="fa_thumbs_o_down"></string>
|
||||||
|
<string name="fa_star_half"></string>
|
||||||
|
<string name="fa_heart_o"></string>
|
||||||
|
<string name="fa_sign_out"></string>
|
||||||
|
<string name="fa_linkedin_square"></string>
|
||||||
|
<string name="fa_thumb_tack"></string>
|
||||||
|
<string name="fa_external_link"></string>
|
||||||
|
<string name="fa_sign_in"></string>
|
||||||
|
<string name="fa_trophy"></string>
|
||||||
|
<string name="fa_github_square"></string>
|
||||||
|
<string name="fa_upload"></string>
|
||||||
|
<string name="fa_lemon_o"></string>
|
||||||
|
<string name="fa_phone"></string>
|
||||||
|
<string name="fa_square_o"></string>
|
||||||
|
<string name="fa_bookmark_o"></string>
|
||||||
|
<string name="fa_phone_square"></string>
|
||||||
|
<string name="fa_twitter"></string>
|
||||||
|
<string name="fa_facebook"></string>
|
||||||
|
<string name="fa_github"></string>
|
||||||
|
<string name="fa_unlock"></string>
|
||||||
|
<string name="fa_credit_card"></string>
|
||||||
|
<string name="fa_rss"></string>
|
||||||
|
<string name="fa_hdd_o"></string>
|
||||||
|
<string name="fa_bullhorn"></string>
|
||||||
|
<string name="fa_bell"></string>
|
||||||
|
<string name="fa_certificate"></string>
|
||||||
|
<string name="fa_hand_o_right"></string>
|
||||||
|
<string name="fa_hand_o_left"></string>
|
||||||
|
<string name="fa_hand_o_up"></string>
|
||||||
|
<string name="fa_hand_o_down"></string>
|
||||||
|
<string name="fa_arrow_circle_left"></string>
|
||||||
|
<string name="fa_arrow_circle_right"></string>
|
||||||
|
<string name="fa_arrow_circle_up"></string>
|
||||||
|
<string name="fa_arrow_circle_down"></string>
|
||||||
|
<string name="fa_globe"></string>
|
||||||
|
<string name="fa_wrench"></string>
|
||||||
|
<string name="fa_tasks"></string>
|
||||||
|
<string name="fa_filter"></string>
|
||||||
|
<string name="fa_briefcase"></string>
|
||||||
|
<string name="fa_arrows_alt"></string>
|
||||||
|
<string name="fa_users"></string>
|
||||||
|
<string name="fa_link"></string>
|
||||||
|
<string name="fa_cloud"></string>
|
||||||
|
<string name="fa_flask"></string>
|
||||||
|
<string name="fa_scissors"></string>
|
||||||
|
<string name="fa_files_o"></string>
|
||||||
|
<string name="fa_paperclip"></string>
|
||||||
|
<string name="fa_floppy_o"></string>
|
||||||
|
<string name="fa_square"></string>
|
||||||
|
<string name="fa_bars"></string>
|
||||||
|
<string name="fa_list_ul"></string>
|
||||||
|
<string name="fa_list_ol"></string>
|
||||||
|
<string name="fa_strikethrough"></string>
|
||||||
|
<string name="fa_underline"></string>
|
||||||
|
<string name="fa_table"></string>
|
||||||
|
<string name="fa_magic"></string>
|
||||||
|
<string name="fa_truck"></string>
|
||||||
|
<string name="fa_pinterest"></string>
|
||||||
|
<string name="fa_pinterest_square"></string>
|
||||||
|
<string name="fa_google_plus_square"></string>
|
||||||
|
<string name="fa_google_plus"></string>
|
||||||
|
<string name="fa_money"></string>
|
||||||
|
<string name="fa_caret_down"></string>
|
||||||
|
<string name="fa_caret_up"></string>
|
||||||
|
<string name="fa_caret_left"></string>
|
||||||
|
<string name="fa_caret_right"></string>
|
||||||
|
<string name="fa_columns"></string>
|
||||||
|
<string name="fa_sort"></string>
|
||||||
|
<string name="fa_sort_asc"></string>
|
||||||
|
<string name="fa_sort_desc"></string>
|
||||||
|
<string name="fa_envelope"></string>
|
||||||
|
<string name="fa_linkedin"></string>
|
||||||
|
<string name="fa_undo"></string>
|
||||||
|
<string name="fa_gavel"></string>
|
||||||
|
<string name="fa_tachometer"></string>
|
||||||
|
<string name="fa_comment_o"></string>
|
||||||
|
<string name="fa_comments_o"></string>
|
||||||
|
<string name="fa_bolt"></string>
|
||||||
|
<string name="fa_sitemap"></string>
|
||||||
|
<string name="fa_umbrella"></string>
|
||||||
|
<string name="fa_clipboard"></string>
|
||||||
|
<string name="fa_lightbulb_o"></string>
|
||||||
|
<string name="fa_exchange"></string>
|
||||||
|
<string name="fa_cloud_download"></string>
|
||||||
|
<string name="fa_cloud_upload"></string>
|
||||||
|
<string name="fa_user_md"></string>
|
||||||
|
<string name="fa_stethoscope"></string>
|
||||||
|
<string name="fa_suitcase"></string>
|
||||||
|
<string name="fa_bell_o"></string>
|
||||||
|
<string name="fa_coffee"></string>
|
||||||
|
<string name="fa_cutlery"></string>
|
||||||
|
<string name="fa_file_text_o"></string>
|
||||||
|
<string name="fa_building_o"></string>
|
||||||
|
<string name="fa_hospital_o"></string>
|
||||||
|
<string name="fa_ambulance"></string>
|
||||||
|
<string name="fa_medkit"></string>
|
||||||
|
<string name="fa_fighter_jet"></string>
|
||||||
|
<string name="fa_beer"></string>
|
||||||
|
<string name="fa_h_square"></string>
|
||||||
|
<string name="fa_plus_square"></string>
|
||||||
|
<string name="fa_angle_double_left"></string>
|
||||||
|
<string name="fa_angle_double_right"></string>
|
||||||
|
<string name="fa_angle_double_up"></string>
|
||||||
|
<string name="fa_angle_double_down"></string>
|
||||||
|
<string name="fa_angle_left"></string>
|
||||||
|
<string name="fa_angle_right"></string>
|
||||||
|
<string name="fa_angle_up"></string>
|
||||||
|
<string name="fa_angle_down"></string>
|
||||||
|
<string name="fa_desktop"></string>
|
||||||
|
<string name="fa_laptop"></string>
|
||||||
|
<string name="fa_tablet"></string>
|
||||||
|
<string name="fa_mobile"></string>
|
||||||
|
<string name="fa_circle_o"></string>
|
||||||
|
<string name="fa_quote_left"></string>
|
||||||
|
<string name="fa_quote_right"></string>
|
||||||
|
<string name="fa_spinner"></string>
|
||||||
|
<string name="fa_circle"></string>
|
||||||
|
<string name="fa_reply"></string>
|
||||||
|
<string name="fa_github_alt"></string>
|
||||||
|
<string name="fa_folder_o"></string>
|
||||||
|
<string name="fa_folder_open_o"></string>
|
||||||
|
<string name="fa_smile_o"></string>
|
||||||
|
<string name="fa_frown_o"></string>
|
||||||
|
<string name="fa_meh_o"></string>
|
||||||
|
<string name="fa_gamepad"></string>
|
||||||
|
<string name="fa_keyboard_o"></string>
|
||||||
|
<string name="fa_flag_o"></string>
|
||||||
|
<string name="fa_flag_checkered"></string>
|
||||||
|
<string name="fa_terminal"></string>
|
||||||
|
<string name="fa_code"></string>
|
||||||
|
<string name="fa_reply_all"></string>
|
||||||
|
<string name="fa_mail_reply_all"></string>
|
||||||
|
<string name="fa_star_half_o"></string>
|
||||||
|
<string name="fa_location_arrow"></string>
|
||||||
|
<string name="fa_crop"></string>
|
||||||
|
<string name="fa_code_fork"></string>
|
||||||
|
<string name="fa_chain_broken"></string>
|
||||||
|
<string name="fa_question"></string>
|
||||||
|
<string name="fa_info"></string>
|
||||||
|
<string name="fa_exclamation"></string>
|
||||||
|
<string name="fa_superscript"></string>
|
||||||
|
<string name="fa_subscript"></string>
|
||||||
|
<string name="fa_eraser"></string>
|
||||||
|
<string name="fa_puzzle_piece"></string>
|
||||||
|
<string name="fa_microphone"></string>
|
||||||
|
<string name="fa_microphone_slash"></string>
|
||||||
|
<string name="fa_shield"></string>
|
||||||
|
<string name="fa_calendar_o"></string>
|
||||||
|
<string name="fa_fire_extinguisher"></string>
|
||||||
|
<string name="fa_rocket"></string>
|
||||||
|
<string name="fa_maxcdn"></string>
|
||||||
|
<string name="fa_chevron_circle_left"></string>
|
||||||
|
<string name="fa_chevron_circle_right"></string>
|
||||||
|
<string name="fa_chevron_circle_up"></string>
|
||||||
|
<string name="fa_chevron_circle_down"></string>
|
||||||
|
<string name="fa_html5"></string>
|
||||||
|
<string name="fa_css3"></string>
|
||||||
|
<string name="fa_anchor"></string>
|
||||||
|
<string name="fa_unlock_alt"></string>
|
||||||
|
<string name="fa_bullseye"></string>
|
||||||
|
<string name="fa_ellipsis_h"></string>
|
||||||
|
<string name="fa_ellipsis_v"></string>
|
||||||
|
<string name="fa_rss_square"></string>
|
||||||
|
<string name="fa_play_circle"></string>
|
||||||
|
<string name="fa_ticket"></string>
|
||||||
|
<string name="fa_minus_square"></string>
|
||||||
|
<string name="fa_minus_square_o"></string>
|
||||||
|
<string name="fa_level_up"></string>
|
||||||
|
<string name="fa_level_down"></string>
|
||||||
|
<string name="fa_check_square"></string>
|
||||||
|
<string name="fa_pencil_square"></string>
|
||||||
|
<string name="fa_external_link_square"></string>
|
||||||
|
<string name="fa_share_square"></string>
|
||||||
|
<string name="fa_compass"></string>
|
||||||
|
<string name="fa_caret_square_o_down"></string>
|
||||||
|
<string name="fa_caret_square_o_up"></string>
|
||||||
|
<string name="fa_caret_square_o_right"></string>
|
||||||
|
<string name="fa_eur"></string>
|
||||||
|
<string name="fa_gbp"></string>
|
||||||
|
<string name="fa_usd"></string>
|
||||||
|
<string name="fa_inr"></string>
|
||||||
|
<string name="fa_jpy"></string>
|
||||||
|
<string name="fa_rub"></string>
|
||||||
|
<string name="fa_krw"></string>
|
||||||
|
<string name="fa_btc"></string>
|
||||||
|
<string name="fa_file"></string>
|
||||||
|
<string name="fa_file_text"></string>
|
||||||
|
<string name="fa_sort_alpha_asc"></string>
|
||||||
|
<string name="fa_sort_alpha_desc"></string>
|
||||||
|
<string name="fa_sort_amount_asc"></string>
|
||||||
|
<string name="fa_sort_amount_desc"></string>
|
||||||
|
<string name="fa_sort_numeric_asc"></string>
|
||||||
|
<string name="fa_sort_numeric_desc"></string>
|
||||||
|
<string name="fa_thumbs_up"></string>
|
||||||
|
<string name="fa_thumbs_down"></string>
|
||||||
|
<string name="fa_youtube_square"></string>
|
||||||
|
<string name="fa_youtube"></string>
|
||||||
|
<string name="fa_xing"></string>
|
||||||
|
<string name="fa_xing_square"></string>
|
||||||
|
<string name="fa_youtube_play"></string>
|
||||||
|
<string name="fa_dropbox"></string>
|
||||||
|
<string name="fa_stack_overflow"></string>
|
||||||
|
<string name="fa_instagram"></string>
|
||||||
|
<string name="fa_flickr"></string>
|
||||||
|
<string name="fa_adn"></string>
|
||||||
|
<string name="fa_bitbucket"></string>
|
||||||
|
<string name="fa_bitbucket_square"></string>
|
||||||
|
<string name="fa_tumblr"></string>
|
||||||
|
<string name="fa_tumblr_square"></string>
|
||||||
|
<string name="fa_long_arrow_down"></string>
|
||||||
|
<string name="fa_long_arrow_up"></string>
|
||||||
|
<string name="fa_long_arrow_left"></string>
|
||||||
|
<string name="fa_long_arrow_right"></string>
|
||||||
|
<string name="fa_apple"></string>
|
||||||
|
<string name="fa_windows"></string>
|
||||||
|
<string name="fa_android"></string>
|
||||||
|
<string name="fa_linux"></string>
|
||||||
|
<string name="fa_dribbble"></string>
|
||||||
|
<string name="fa_skype"></string>
|
||||||
|
<string name="fa_foursquare"></string>
|
||||||
|
<string name="fa_trello"></string>
|
||||||
|
<string name="fa_female"></string>
|
||||||
|
<string name="fa_male"></string>
|
||||||
|
<string name="fa_gittip"></string>
|
||||||
|
<string name="fa_sun_o"></string>
|
||||||
|
<string name="fa_moon_o"></string>
|
||||||
|
<string name="fa_archive"></string>
|
||||||
|
<string name="fa_bug"></string>
|
||||||
|
<string name="fa_vk"></string>
|
||||||
|
<string name="fa_weibo"></string>
|
||||||
|
<string name="fa_renren"></string>
|
||||||
|
<string name="fa_pagelines"></string>
|
||||||
|
<string name="fa_stack_exchange"></string>
|
||||||
|
<string name="fa_arrow_circle_o_right"></string>
|
||||||
|
<string name="fa_arrow_circle_o_left"></string>
|
||||||
|
<string name="fa_caret_square_o_left"></string>
|
||||||
|
<string name="fa_dot_circle_o"></string>
|
||||||
|
<string name="fa_wheelchair"></string>
|
||||||
|
<string name="fa_vimeo_square"></string>
|
||||||
|
<string name="fa_try"></string>
|
||||||
|
<string name="fa_plus_square_o"></string>
|
||||||
|
</resources>
|
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
|
||||||
|
<string name="app_name">μHabits</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
|
||||||
|
<string name="edit">Edit</string>
|
||||||
|
<string name="delete">Delete</string>
|
||||||
|
|
||||||
|
<string name="add_habit">Add habit</string>
|
||||||
|
<string name="color_picker_default_title">Select a Color</string>
|
||||||
|
<string name="color_swatch_description">Color <xliff:g id="color_index" example="14">%1$d</xliff:g></string>
|
||||||
|
<string name="color_swatch_description_selected">Color <xliff:g id="color_index" example="14">%1$d</xliff:g> selected</string>
|
||||||
|
|
||||||
|
<string name="toast_habit_created">Habit created.</string>
|
||||||
|
<string name="toast_habit_deleted">Habit deleted.</string>
|
||||||
|
<string name="toast_nothing_to_undo">Nothing to undo.</string>
|
||||||
|
<string name="toast_nothing_to_redo">Nothing to redo.</string>
|
||||||
|
<string name="toast_habit_changed">Habit changed.</string>
|
||||||
|
<string name="toast_habit_changed_back">Habit changed back.</string>
|
||||||
|
<string name="toast_repetition_toggled">Repetition toggled.</string>
|
||||||
|
|
||||||
|
<string name="habit_key"></string>
|
||||||
|
<string name="offset_key"></string>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,20 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Base application theme, dependent on API level. This theme is replaced
|
||||||
|
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||||
|
-->
|
||||||
|
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
||||||
|
<!--
|
||||||
|
Theme customizations available in newer API levels can go in
|
||||||
|
res/values-vXX/styles.xml, while customizations related to
|
||||||
|
backward-compatibility can go here.
|
||||||
|
-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Application theme. -->
|
||||||
|
<style name="AppTheme" parent="AppBaseTheme">
|
||||||
|
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.colorpicker;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
|
import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dialog which takes in as input an array of colors and creates a palette allowing the user to
|
||||||
|
* select a specific color swatch, which invokes a listener.
|
||||||
|
*/
|
||||||
|
public class ColorPickerDialog extends DialogFragment implements OnColorSelectedListener {
|
||||||
|
|
||||||
|
public static final int SIZE_LARGE = 1;
|
||||||
|
public static final int SIZE_SMALL = 2;
|
||||||
|
|
||||||
|
protected AlertDialog mAlertDialog;
|
||||||
|
|
||||||
|
protected static final String KEY_TITLE_ID = "title_id";
|
||||||
|
protected static final String KEY_COLORS = "colors";
|
||||||
|
protected static final String KEY_SELECTED_COLOR = "selected_color";
|
||||||
|
protected static final String KEY_COLUMNS = "columns";
|
||||||
|
protected static final String KEY_SIZE = "size";
|
||||||
|
|
||||||
|
protected int mTitleResId = R.string.color_picker_default_title;
|
||||||
|
protected int[] mColors = null;
|
||||||
|
protected int mSelectedColor;
|
||||||
|
protected int mColumns;
|
||||||
|
protected int mSize;
|
||||||
|
|
||||||
|
private ColorPickerPalette mPalette;
|
||||||
|
private ProgressBar mProgress;
|
||||||
|
|
||||||
|
protected OnColorSelectedListener mListener;
|
||||||
|
|
||||||
|
public ColorPickerDialog() {
|
||||||
|
// Empty constructor required for dialog fragments.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ColorPickerDialog newInstance(int titleResId, int[] colors, int selectedColor,
|
||||||
|
int columns, int size) {
|
||||||
|
ColorPickerDialog ret = new ColorPickerDialog();
|
||||||
|
ret.initialize(titleResId, colors, selectedColor, columns, size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(int titleResId, int[] colors, int selectedColor, int columns, int size) {
|
||||||
|
setArguments(titleResId, columns, size);
|
||||||
|
setColors(colors, selectedColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArguments(int titleResId, int columns, int size) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt(KEY_TITLE_ID, titleResId);
|
||||||
|
bundle.putInt(KEY_COLUMNS, columns);
|
||||||
|
bundle.putInt(KEY_SIZE, size);
|
||||||
|
setArguments(bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnColorSelectedListener(OnColorSelectedListener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
if (getArguments() != null) {
|
||||||
|
mTitleResId = getArguments().getInt(KEY_TITLE_ID);
|
||||||
|
mColumns = getArguments().getInt(KEY_COLUMNS);
|
||||||
|
mSize = getArguments().getInt(KEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
mColors = savedInstanceState.getIntArray(KEY_COLORS);
|
||||||
|
mSelectedColor = (Integer) savedInstanceState.getSerializable(KEY_SELECTED_COLOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
|
||||||
|
View view = LayoutInflater.from(getActivity()).inflate(R.layout.color_picker_dialog, null);
|
||||||
|
mProgress = (ProgressBar) view.findViewById(android.R.id.progress);
|
||||||
|
mPalette = (ColorPickerPalette) view.findViewById(R.id.color_picker);
|
||||||
|
mPalette.init(mSize, mColumns, this);
|
||||||
|
|
||||||
|
if (mColors != null) {
|
||||||
|
showPaletteView();
|
||||||
|
}
|
||||||
|
|
||||||
|
mAlertDialog = new AlertDialog.Builder(activity)
|
||||||
|
.setTitle(mTitleResId)
|
||||||
|
.setView(view)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
return mAlertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onColorSelected(int color) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onColorSelected(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getTargetFragment() instanceof OnColorSelectedListener) {
|
||||||
|
final OnColorSelectedListener listener =
|
||||||
|
(OnColorSelectedListener) getTargetFragment();
|
||||||
|
listener.onColorSelected(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color != mSelectedColor) {
|
||||||
|
mSelectedColor = color;
|
||||||
|
// Redraw palette to show checkmark on newly selected color before dismissing.
|
||||||
|
mPalette.drawPalette(mColors, mSelectedColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showPaletteView() {
|
||||||
|
if (mProgress != null && mPalette != null) {
|
||||||
|
mProgress.setVisibility(View.GONE);
|
||||||
|
refreshPalette();
|
||||||
|
mPalette.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showProgressBarView() {
|
||||||
|
if (mProgress != null && mPalette != null) {
|
||||||
|
mProgress.setVisibility(View.VISIBLE);
|
||||||
|
mPalette.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColors(int[] colors, int selectedColor) {
|
||||||
|
if (mColors != colors || mSelectedColor != selectedColor) {
|
||||||
|
mColors = colors;
|
||||||
|
mSelectedColor = selectedColor;
|
||||||
|
refreshPalette();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColors(int[] colors) {
|
||||||
|
if (mColors != colors) {
|
||||||
|
mColors = colors;
|
||||||
|
refreshPalette();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedColor(int color) {
|
||||||
|
if (mSelectedColor != color) {
|
||||||
|
mSelectedColor = color;
|
||||||
|
refreshPalette();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshPalette() {
|
||||||
|
if (mPalette != null && mColors != null) {
|
||||||
|
mPalette.drawPalette(mColors, mSelectedColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getColors() {
|
||||||
|
return mColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectedColor() {
|
||||||
|
return mSelectedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putIntArray(KEY_COLORS, mColors);
|
||||||
|
outState.putSerializable(KEY_SELECTED_COLOR, mSelectedColor);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.colorpicker;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TableLayout;
|
||||||
|
import android.widget.TableRow;
|
||||||
|
|
||||||
|
import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A color picker custom view which creates an grid of color squares. The number of squares per
|
||||||
|
* row (and the padding between the squares) is determined by the user.
|
||||||
|
*/
|
||||||
|
public class ColorPickerPalette extends TableLayout {
|
||||||
|
|
||||||
|
public OnColorSelectedListener mOnColorSelectedListener;
|
||||||
|
|
||||||
|
private String mDescription;
|
||||||
|
private String mDescriptionSelected;
|
||||||
|
|
||||||
|
private int mSwatchLength;
|
||||||
|
private int mMarginSize;
|
||||||
|
private int mNumColumns;
|
||||||
|
|
||||||
|
public ColorPickerPalette(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorPickerPalette(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the size, columns, and listener. Size should be a pre-defined size (SIZE_LARGE
|
||||||
|
* or SIZE_SMALL) from ColorPickerDialogFragment.
|
||||||
|
*/
|
||||||
|
public void init(int size, int columns, OnColorSelectedListener listener) {
|
||||||
|
mNumColumns = columns;
|
||||||
|
Resources res = getResources();
|
||||||
|
if (size == ColorPickerDialog.SIZE_LARGE) {
|
||||||
|
mSwatchLength = res.getDimensionPixelSize(R.dimen.color_swatch_large);
|
||||||
|
mMarginSize = res.getDimensionPixelSize(R.dimen.color_swatch_margins_large);
|
||||||
|
} else {
|
||||||
|
mSwatchLength = res.getDimensionPixelSize(R.dimen.color_swatch_small);
|
||||||
|
mMarginSize = res.getDimensionPixelSize(R.dimen.color_swatch_margins_small);
|
||||||
|
}
|
||||||
|
mOnColorSelectedListener = listener;
|
||||||
|
|
||||||
|
mDescription = res.getString(R.string.color_swatch_description);
|
||||||
|
mDescriptionSelected = res.getString(R.string.color_swatch_description_selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableRow createTableRow() {
|
||||||
|
TableRow row = new TableRow(getContext());
|
||||||
|
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||||
|
LayoutParams.WRAP_CONTENT);
|
||||||
|
row.setLayoutParams(params);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds swatches to table in a serpentine format.
|
||||||
|
*/
|
||||||
|
public void drawPalette(int[] colors, int selectedColor) {
|
||||||
|
if (colors == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeAllViews();
|
||||||
|
int tableElements = 0;
|
||||||
|
int rowElements = 0;
|
||||||
|
int rowNumber = 0;
|
||||||
|
|
||||||
|
// Fills the table with swatches based on the array of colors.
|
||||||
|
TableRow row = createTableRow();
|
||||||
|
for (int color : colors) {
|
||||||
|
tableElements++;
|
||||||
|
|
||||||
|
View colorSwatch = createColorSwatch(color, selectedColor);
|
||||||
|
setSwatchDescription(rowNumber, tableElements, rowElements, color == selectedColor,
|
||||||
|
colorSwatch);
|
||||||
|
addSwatchToRow(row, colorSwatch, rowNumber);
|
||||||
|
|
||||||
|
rowElements++;
|
||||||
|
if (rowElements == mNumColumns) {
|
||||||
|
addView(row);
|
||||||
|
row = createTableRow();
|
||||||
|
rowElements = 0;
|
||||||
|
rowNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create blank views to fill the row if the last row has not been filled.
|
||||||
|
if (rowElements > 0) {
|
||||||
|
while (rowElements != mNumColumns) {
|
||||||
|
addSwatchToRow(row, createBlankSpace(), rowNumber);
|
||||||
|
rowElements++;
|
||||||
|
}
|
||||||
|
addView(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a swatch to the end of the row for even-numbered rows (starting with row 0),
|
||||||
|
* to the beginning of a row for odd-numbered rows.
|
||||||
|
*/
|
||||||
|
private static void addSwatchToRow(TableRow row, View swatch, int rowNumber) {
|
||||||
|
if (rowNumber % 2 == 0) {
|
||||||
|
row.addView(swatch);
|
||||||
|
} else {
|
||||||
|
row.addView(swatch, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a content description to the specified swatch view. Because the colors get added in a
|
||||||
|
* snaking form, every other row will need to compensate for the fact that the colors are added
|
||||||
|
* in an opposite direction from their left->right/top->bottom order, which is how the system
|
||||||
|
* will arrange them for accessibility purposes.
|
||||||
|
*/
|
||||||
|
private void setSwatchDescription(int rowNumber, int index, int rowElements, boolean selected,
|
||||||
|
View swatch) {
|
||||||
|
int accessibilityIndex;
|
||||||
|
if (rowNumber % 2 == 0) {
|
||||||
|
// We're in a regular-ordered row
|
||||||
|
accessibilityIndex = index;
|
||||||
|
} else {
|
||||||
|
// We're in a backwards-ordered row.
|
||||||
|
int rowMax = ((rowNumber + 1) * mNumColumns);
|
||||||
|
accessibilityIndex = rowMax - rowElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
String description;
|
||||||
|
if (selected) {
|
||||||
|
description = String.format(mDescriptionSelected, accessibilityIndex);
|
||||||
|
} else {
|
||||||
|
description = String.format(mDescription, accessibilityIndex);
|
||||||
|
}
|
||||||
|
swatch.setContentDescription(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a blank space to fill the row.
|
||||||
|
*/
|
||||||
|
private ImageView createBlankSpace() {
|
||||||
|
ImageView view = new ImageView(getContext());
|
||||||
|
TableRow.LayoutParams params = new TableRow.LayoutParams(mSwatchLength, mSwatchLength);
|
||||||
|
params.setMargins(mMarginSize, mMarginSize, mMarginSize, mMarginSize);
|
||||||
|
view.setLayoutParams(params);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a color swatch.
|
||||||
|
*/
|
||||||
|
private ColorPickerSwatch createColorSwatch(int color, int selectedColor) {
|
||||||
|
ColorPickerSwatch view = new ColorPickerSwatch(getContext(), color,
|
||||||
|
color == selectedColor, mOnColorSelectedListener);
|
||||||
|
TableRow.LayoutParams params = new TableRow.LayoutParams(mSwatchLength, mSwatchLength);
|
||||||
|
params.setMargins(mMarginSize, mMarginSize, mMarginSize, mMarginSize);
|
||||||
|
view.setLayoutParams(params);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.colorpicker;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a circular swatch of a specified color. Adds a checkmark if marked as checked.
|
||||||
|
*/
|
||||||
|
public class ColorPickerSwatch extends FrameLayout implements View.OnClickListener {
|
||||||
|
private int mColor;
|
||||||
|
private ImageView mSwatchImage;
|
||||||
|
private ImageView mCheckmarkImage;
|
||||||
|
private OnColorSelectedListener mOnColorSelectedListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a callback when a color square is selected.
|
||||||
|
*/
|
||||||
|
public interface OnColorSelectedListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a specific color square has been selected.
|
||||||
|
*/
|
||||||
|
public void onColorSelected(int color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorPickerSwatch(Context context, int color, boolean checked,
|
||||||
|
OnColorSelectedListener listener) {
|
||||||
|
super(context);
|
||||||
|
mColor = color;
|
||||||
|
mOnColorSelectedListener = listener;
|
||||||
|
|
||||||
|
LayoutInflater.from(context).inflate(R.layout.color_picker_swatch, this);
|
||||||
|
mSwatchImage = (ImageView) findViewById(R.id.color_picker_swatch);
|
||||||
|
mCheckmarkImage = (ImageView) findViewById(R.id.color_picker_checkmark);
|
||||||
|
setColor(color);
|
||||||
|
setChecked(checked);
|
||||||
|
setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setColor(int color) {
|
||||||
|
Drawable[] colorDrawable = new Drawable[]
|
||||||
|
{getContext().getResources().getDrawable(R.drawable.color_picker_swatch)};
|
||||||
|
mSwatchImage.setImageDrawable(new ColorStateDrawable(colorDrawable, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChecked(boolean checked) {
|
||||||
|
if (checked) {
|
||||||
|
mCheckmarkImage.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
mCheckmarkImage.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (mOnColorSelectedListener != null) {
|
||||||
|
mOnColorSelectedListener.onColorSelected(mColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.colorpicker;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.LayerDrawable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A drawable which sets its color filter to a color specified by the user, and changes to a
|
||||||
|
* slightly darker color when pressed or focused.
|
||||||
|
*/
|
||||||
|
public class ColorStateDrawable extends LayerDrawable {
|
||||||
|
|
||||||
|
private static final float PRESSED_STATE_MULTIPLIER = 0.70f;
|
||||||
|
|
||||||
|
private int mColor;
|
||||||
|
|
||||||
|
public ColorStateDrawable(Drawable[] layers, int color) {
|
||||||
|
super(layers);
|
||||||
|
mColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onStateChange(int[] states) {
|
||||||
|
boolean pressedOrFocused = false;
|
||||||
|
for (int state : states) {
|
||||||
|
if (state == android.R.attr.state_pressed || state == android.R.attr.state_focused) {
|
||||||
|
pressedOrFocused = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pressedOrFocused) {
|
||||||
|
super.setColorFilter(getPressedColor(mColor), PorterDuff.Mode.SRC_ATOP);
|
||||||
|
} else {
|
||||||
|
super.setColorFilter(mColor, PorterDuff.Mode.SRC_ATOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onStateChange(states);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a particular color, adjusts its value by a multiplier.
|
||||||
|
*/
|
||||||
|
private static int getPressedColor(int color) {
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
Color.colorToHSV(color, hsv);
|
||||||
|
hsv[2] = hsv[2] * PRESSED_STATE_MULTIPLIER;
|
||||||
|
return Color.HSVToColor(hsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStateful() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.colorpicker;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A color comparator which compares based on hue, saturation, and value.
|
||||||
|
*/
|
||||||
|
public class HsvColorComparator implements Comparator<Integer> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Integer lhs, Integer rhs) {
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
Color.colorToHSV(lhs, hsv);
|
||||||
|
float hue1 = hsv[0];
|
||||||
|
float sat1 = hsv[1];
|
||||||
|
float val1 = hsv[2];
|
||||||
|
|
||||||
|
float[] hsv2 = new float[3];
|
||||||
|
Color.colorToHSV(rhs, hsv2);
|
||||||
|
float hue2 = hsv2[0];
|
||||||
|
float sat2 = hsv2[1];
|
||||||
|
float val2 = hsv2[2];
|
||||||
|
|
||||||
|
if (hue1 < hue2) {
|
||||||
|
return 1;
|
||||||
|
} else if (hue1 > hue2) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
if (sat1 < sat2) {
|
||||||
|
return 1;
|
||||||
|
} else if (sat1 > sat2) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
if (val1 < val2) {
|
||||||
|
return 1;
|
||||||
|
} else if (val1 > val2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,471 @@
|
|||||||
|
package com.mobeta.android.dslv;
|
||||||
|
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.HapticFeedbackConstants;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that starts and stops item drags on a {@link DragSortListView}
|
||||||
|
* based on touch gestures. This class also inherits from
|
||||||
|
* {@link SimpleFloatViewManager}, which provides basic float View
|
||||||
|
* creation.
|
||||||
|
*
|
||||||
|
* An instance of this class is meant to be passed to the methods
|
||||||
|
* {@link DragSortListView#setTouchListener()} and
|
||||||
|
* {@link DragSortListView#setFloatViewManager()} of your
|
||||||
|
* {@link DragSortListView} instance.
|
||||||
|
*/
|
||||||
|
public class DragSortController extends SimpleFloatViewManager implements View.OnTouchListener, GestureDetector.OnGestureListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drag init mode enum.
|
||||||
|
*/
|
||||||
|
public static final int ON_DOWN = 0;
|
||||||
|
public static final int ON_DRAG = 1;
|
||||||
|
public static final int ON_LONG_PRESS = 2;
|
||||||
|
|
||||||
|
private int mDragInitMode = ON_DOWN;
|
||||||
|
|
||||||
|
private boolean mSortEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove mode enum.
|
||||||
|
*/
|
||||||
|
public static final int CLICK_REMOVE = 0;
|
||||||
|
public static final int FLING_REMOVE = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current remove mode.
|
||||||
|
*/
|
||||||
|
private int mRemoveMode;
|
||||||
|
|
||||||
|
private boolean mRemoveEnabled = false;
|
||||||
|
private boolean mIsRemoving = false;
|
||||||
|
|
||||||
|
private GestureDetector mDetector;
|
||||||
|
|
||||||
|
private GestureDetector mFlingRemoveDetector;
|
||||||
|
|
||||||
|
private int mTouchSlop;
|
||||||
|
|
||||||
|
public static final int MISS = -1;
|
||||||
|
|
||||||
|
private int mHitPos = MISS;
|
||||||
|
private int mFlingHitPos = MISS;
|
||||||
|
|
||||||
|
private int mClickRemoveHitPos = MISS;
|
||||||
|
|
||||||
|
private int[] mTempLoc = new int[2];
|
||||||
|
|
||||||
|
private int mItemX;
|
||||||
|
private int mItemY;
|
||||||
|
|
||||||
|
private int mCurrX;
|
||||||
|
private int mCurrY;
|
||||||
|
|
||||||
|
private boolean mDragging = false;
|
||||||
|
|
||||||
|
private float mFlingSpeed = 500f;
|
||||||
|
|
||||||
|
private int mDragHandleId;
|
||||||
|
|
||||||
|
private int mClickRemoveId;
|
||||||
|
|
||||||
|
private int mFlingHandleId;
|
||||||
|
private boolean mCanDrag;
|
||||||
|
|
||||||
|
private DragSortListView mDslv;
|
||||||
|
private int mPositionX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls {@link #DragSortController(DragSortListView, int)} with a
|
||||||
|
* 0 drag handle id, FLING_RIGHT_REMOVE remove mode,
|
||||||
|
* and ON_DOWN drag init. By default, sorting is enabled, and
|
||||||
|
* removal is disabled.
|
||||||
|
*
|
||||||
|
* @param dslv The DSLV instance
|
||||||
|
*/
|
||||||
|
public DragSortController(DragSortListView dslv) {
|
||||||
|
this(dslv, 0, ON_DOWN, FLING_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, int removeMode) {
|
||||||
|
this(dslv, dragHandleId, dragInitMode, removeMode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, int removeMode, int clickRemoveId) {
|
||||||
|
this(dslv, dragHandleId, dragInitMode, removeMode, clickRemoveId, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, sorting is enabled, and removal is disabled.
|
||||||
|
*
|
||||||
|
* @param dslv The DSLV instance
|
||||||
|
* @param dragHandleId The resource id of the View that represents
|
||||||
|
* the drag handle in a list item.
|
||||||
|
*/
|
||||||
|
public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode,
|
||||||
|
int removeMode, int clickRemoveId, int flingHandleId) {
|
||||||
|
super(dslv);
|
||||||
|
mDslv = dslv;
|
||||||
|
mDetector = new GestureDetector(dslv.getContext(), this);
|
||||||
|
mFlingRemoveDetector = new GestureDetector(dslv.getContext(), mFlingRemoveListener);
|
||||||
|
mFlingRemoveDetector.setIsLongpressEnabled(false);
|
||||||
|
mTouchSlop = ViewConfiguration.get(dslv.getContext()).getScaledTouchSlop();
|
||||||
|
mDragHandleId = dragHandleId;
|
||||||
|
mClickRemoveId = clickRemoveId;
|
||||||
|
mFlingHandleId = flingHandleId;
|
||||||
|
setRemoveMode(removeMode);
|
||||||
|
setDragInitMode(dragInitMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getDragInitMode() {
|
||||||
|
return mDragInitMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set how a drag is initiated. Needs to be one of
|
||||||
|
* {@link ON_DOWN}, {@link ON_DRAG}, or {@link ON_LONG_PRESS}.
|
||||||
|
*
|
||||||
|
* @param mode The drag init mode.
|
||||||
|
*/
|
||||||
|
public void setDragInitMode(int mode) {
|
||||||
|
mDragInitMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable list item sorting. Disabling is useful if only item
|
||||||
|
* removal is desired. Prevents drags in the vertical direction.
|
||||||
|
*
|
||||||
|
* @param enabled Set <code>true</code> to enable list
|
||||||
|
* item sorting.
|
||||||
|
*/
|
||||||
|
public void setSortEnabled(boolean enabled) {
|
||||||
|
mSortEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSortEnabled() {
|
||||||
|
return mSortEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One of {@link CLICK_REMOVE}, {@link FLING_RIGHT_REMOVE},
|
||||||
|
* {@link FLING_LEFT_REMOVE},
|
||||||
|
* {@link SLIDE_RIGHT_REMOVE}, or {@link SLIDE_LEFT_REMOVE}.
|
||||||
|
*/
|
||||||
|
public void setRemoveMode(int mode) {
|
||||||
|
mRemoveMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRemoveMode() {
|
||||||
|
return mRemoveMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable item removal without affecting remove mode.
|
||||||
|
*/
|
||||||
|
public void setRemoveEnabled(boolean enabled) {
|
||||||
|
mRemoveEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRemoveEnabled() {
|
||||||
|
return mRemoveEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the resource id for the View that represents the drag
|
||||||
|
* handle in a list item.
|
||||||
|
*
|
||||||
|
* @param id An android resource id.
|
||||||
|
*/
|
||||||
|
public void setDragHandleId(int id) {
|
||||||
|
mDragHandleId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the resource id for the View that represents the fling
|
||||||
|
* handle in a list item.
|
||||||
|
*
|
||||||
|
* @param id An android resource id.
|
||||||
|
*/
|
||||||
|
public void setFlingHandleId(int id) {
|
||||||
|
mFlingHandleId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the resource id for the View that represents click
|
||||||
|
* removal button.
|
||||||
|
*
|
||||||
|
* @param id An android resource id.
|
||||||
|
*/
|
||||||
|
public void setClickRemoveId(int id) {
|
||||||
|
mClickRemoveId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets flags to restrict certain motions of the floating View
|
||||||
|
* based on DragSortController settings (such as remove mode).
|
||||||
|
* Starts the drag on the DragSortListView.
|
||||||
|
*
|
||||||
|
* @param position The list item position (includes headers).
|
||||||
|
* @param deltaX Touch x-coord minus left edge of floating View.
|
||||||
|
* @param deltaY Touch y-coord minus top edge of floating View.
|
||||||
|
*
|
||||||
|
* @return True if drag started, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean startDrag(int position, int deltaX, int deltaY) {
|
||||||
|
|
||||||
|
int dragFlags = 0;
|
||||||
|
if (mSortEnabled && !mIsRemoving) {
|
||||||
|
dragFlags |= DragSortListView.DRAG_POS_Y | DragSortListView.DRAG_NEG_Y;
|
||||||
|
}
|
||||||
|
if (mRemoveEnabled && mIsRemoving) {
|
||||||
|
dragFlags |= DragSortListView.DRAG_POS_X;
|
||||||
|
dragFlags |= DragSortListView.DRAG_NEG_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDragging = mDslv.startDrag(position - mDslv.getHeaderViewsCount(), dragFlags, deltaX,
|
||||||
|
deltaY);
|
||||||
|
return mDragging;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent ev) {
|
||||||
|
if (!mDslv.isDragEnabled() || mDslv.listViewIntercepted()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDetector.onTouchEvent(ev);
|
||||||
|
if (mRemoveEnabled && mDragging && mRemoveMode == FLING_REMOVE) {
|
||||||
|
mFlingRemoveDetector.onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
||||||
|
switch (action) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
mCurrX = (int) ev.getX();
|
||||||
|
mCurrY = (int) ev.getY();
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
if (mRemoveEnabled && mIsRemoving) {
|
||||||
|
int x = mPositionX >= 0 ? mPositionX : -mPositionX;
|
||||||
|
int removePoint = mDslv.getWidth() / 2;
|
||||||
|
if (x > removePoint) {
|
||||||
|
mDslv.stopDragWithVelocity(true, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
mIsRemoving = false;
|
||||||
|
mDragging = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides to provide fading when slide removal is enabled.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onDragFloatView(View floatView, Point position, Point touch) {
|
||||||
|
|
||||||
|
if (mRemoveEnabled && mIsRemoving) {
|
||||||
|
mPositionX = position.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position to start dragging based on the ACTION_DOWN
|
||||||
|
* MotionEvent. This function simply calls
|
||||||
|
* {@link #dragHandleHitPosition(MotionEvent)}. Override
|
||||||
|
* to change drag handle behavior;
|
||||||
|
* this function is called internally when an ACTION_DOWN
|
||||||
|
* event is detected.
|
||||||
|
*
|
||||||
|
* @param ev The ACTION_DOWN MotionEvent.
|
||||||
|
*
|
||||||
|
* @return The list position to drag if a drag-init gesture is
|
||||||
|
* detected; MISS if unsuccessful.
|
||||||
|
*/
|
||||||
|
public int startDragPosition(MotionEvent ev) {
|
||||||
|
return dragHandleHitPosition(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int startFlingPosition(MotionEvent ev) {
|
||||||
|
return mRemoveMode == FLING_REMOVE ? flingHandleHitPosition(ev) : MISS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for the touch of an item's drag handle (specified by
|
||||||
|
* {@link #setDragHandleId(int)}), and returns that item's position
|
||||||
|
* if a drag handle touch was detected.
|
||||||
|
*
|
||||||
|
* @param ev The ACTION_DOWN MotionEvent.
|
||||||
|
|
||||||
|
* @return The list position of the item whose drag handle was
|
||||||
|
* touched; MISS if unsuccessful.
|
||||||
|
*/
|
||||||
|
public int dragHandleHitPosition(MotionEvent ev) {
|
||||||
|
return viewIdHitPosition(ev, mDragHandleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int flingHandleHitPosition(MotionEvent ev) {
|
||||||
|
return viewIdHitPosition(ev, mFlingHandleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int viewIdHitPosition(MotionEvent ev, int id) {
|
||||||
|
final int x = (int) ev.getX();
|
||||||
|
final int y = (int) ev.getY();
|
||||||
|
|
||||||
|
int touchPos = mDslv.pointToPosition(x, y); // includes headers/footers
|
||||||
|
|
||||||
|
final int numHeaders = mDslv.getHeaderViewsCount();
|
||||||
|
final int numFooters = mDslv.getFooterViewsCount();
|
||||||
|
final int count = mDslv.getCount();
|
||||||
|
|
||||||
|
// Log.d("mobeta", "touch down on position " + itemnum);
|
||||||
|
// We're only interested if the touch was on an
|
||||||
|
// item that's not a header or footer.
|
||||||
|
if (touchPos != AdapterView.INVALID_POSITION && touchPos >= numHeaders
|
||||||
|
&& touchPos < (count - numFooters)) {
|
||||||
|
final View item = mDslv.getChildAt(touchPos - mDslv.getFirstVisiblePosition());
|
||||||
|
final int rawX = (int) ev.getRawX();
|
||||||
|
final int rawY = (int) ev.getRawY();
|
||||||
|
|
||||||
|
View dragBox = id == 0 ? item : (View) item.findViewById(id);
|
||||||
|
if (dragBox != null) {
|
||||||
|
dragBox.getLocationOnScreen(mTempLoc);
|
||||||
|
|
||||||
|
if (rawX > mTempLoc[0] && rawY > mTempLoc[1] &&
|
||||||
|
rawX < mTempLoc[0] + dragBox.getWidth() &&
|
||||||
|
rawY < mTempLoc[1] + dragBox.getHeight()) {
|
||||||
|
|
||||||
|
mItemX = item.getLeft();
|
||||||
|
mItemY = item.getTop();
|
||||||
|
|
||||||
|
return touchPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MISS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDown(MotionEvent ev) {
|
||||||
|
if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) {
|
||||||
|
mClickRemoveHitPos = viewIdHitPosition(ev, mClickRemoveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
mHitPos = startDragPosition(ev);
|
||||||
|
if (mHitPos != MISS && mDragInitMode == ON_DOWN) {
|
||||||
|
startDrag(mHitPos, (int) ev.getX() - mItemX, (int) ev.getY() - mItemY);
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsRemoving = false;
|
||||||
|
mCanDrag = true;
|
||||||
|
mPositionX = 0;
|
||||||
|
mFlingHitPos = startFlingPosition(ev);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||||
|
|
||||||
|
if(e1 == null) return false;
|
||||||
|
if(e2 == null) return false;
|
||||||
|
|
||||||
|
final int x1 = (int) e1.getX();
|
||||||
|
final int y1 = (int) e1.getY();
|
||||||
|
final int x2 = (int) e2.getX();
|
||||||
|
final int y2 = (int) e2.getY();
|
||||||
|
final int deltaX = x2 - mItemX;
|
||||||
|
final int deltaY = y2 - mItemY;
|
||||||
|
|
||||||
|
if (mCanDrag && !mDragging && (mHitPos != MISS || mFlingHitPos != MISS)) {
|
||||||
|
if (mHitPos != MISS) {
|
||||||
|
if (mDragInitMode == ON_DRAG && Math.abs(y2 - y1) > mTouchSlop && mSortEnabled) {
|
||||||
|
startDrag(mHitPos, deltaX, deltaY);
|
||||||
|
}
|
||||||
|
else if (mDragInitMode != ON_DOWN && Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled)
|
||||||
|
{
|
||||||
|
mIsRemoving = true;
|
||||||
|
startDrag(mFlingHitPos, deltaX, deltaY);
|
||||||
|
}
|
||||||
|
} else if (mFlingHitPos != MISS) {
|
||||||
|
if (Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) {
|
||||||
|
mIsRemoving = true;
|
||||||
|
startDrag(mFlingHitPos, deltaX, deltaY);
|
||||||
|
} else if (Math.abs(y2 - y1) > mTouchSlop) {
|
||||||
|
mCanDrag = false; // if started to scroll the list then
|
||||||
|
// don't allow sorting nor fling-removing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return whatever
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLongPress(MotionEvent e) {
|
||||||
|
// Log.d("mobeta", "lift listener long pressed");
|
||||||
|
if (mHitPos != MISS && mDragInitMode == ON_LONG_PRESS) {
|
||||||
|
mDslv.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||||
|
startDrag(mHitPos, mCurrX - mItemX, mCurrY - mItemY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete the OnGestureListener interface
|
||||||
|
@Override
|
||||||
|
public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete the OnGestureListener interface
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapUp(MotionEvent ev) {
|
||||||
|
if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) {
|
||||||
|
if (mClickRemoveHitPos != MISS) {
|
||||||
|
mDslv.removeItem(mClickRemoveHitPos - mDslv.getHeaderViewsCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete the OnGestureListener interface
|
||||||
|
@Override
|
||||||
|
public void onShowPress(MotionEvent ev) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
private GestureDetector.OnGestureListener mFlingRemoveListener =
|
||||||
|
new GestureDetector.SimpleOnGestureListener() {
|
||||||
|
@Override
|
||||||
|
public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
|
||||||
|
float velocityY) {
|
||||||
|
// Log.d("mobeta", "on fling remove called");
|
||||||
|
if (mRemoveEnabled && mIsRemoving) {
|
||||||
|
int w = mDslv.getWidth();
|
||||||
|
int minPos = w / 5;
|
||||||
|
if (velocityX > mFlingSpeed) {
|
||||||
|
if (mPositionX > -minPos) {
|
||||||
|
mDslv.stopDragWithVelocity(true, velocityX);
|
||||||
|
}
|
||||||
|
} else if (velocityX < -mFlingSpeed) {
|
||||||
|
if (mPositionX < minPos) {
|
||||||
|
mDslv.stopDragWithVelocity(true, velocityX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIsRemoving = false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
package com.mobeta.android.dslv;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.util.SparseIntArray;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.support.v4.widget.CursorAdapter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subclass of {@link android.widget.CursorAdapter} that provides
|
||||||
|
* reordering of the elements in the Cursor based on completed
|
||||||
|
* drag-sort operations. The reordering is a simple mapping of
|
||||||
|
* list positions into Cursor positions (the Cursor is unchanged).
|
||||||
|
* To persist changes made by drag-sorts, one can retrieve the
|
||||||
|
* mapping with the {@link #getCursorPositions()} method, which
|
||||||
|
* returns the reordered list of Cursor positions.
|
||||||
|
*
|
||||||
|
* An instance of this class is passed
|
||||||
|
* to {@link DragSortListView#setAdapter(ListAdapter)} and, since
|
||||||
|
* this class implements the {@link DragSortListView.DragSortListener}
|
||||||
|
* interface, it is automatically set as the DragSortListener for
|
||||||
|
* the DragSortListView instance.
|
||||||
|
*/
|
||||||
|
public abstract class DragSortCursorAdapter extends CursorAdapter implements DragSortListView.DragSortListener {
|
||||||
|
|
||||||
|
public static final int REMOVED = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key is ListView position, value is Cursor position
|
||||||
|
*/
|
||||||
|
private SparseIntArray mListMapping = new SparseIntArray();
|
||||||
|
|
||||||
|
private ArrayList<Integer> mRemovedCursorPositions = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
public DragSortCursorAdapter(Context context, Cursor c) {
|
||||||
|
super(context, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DragSortCursorAdapter(Context context, Cursor c, boolean autoRequery) {
|
||||||
|
super(context, c, autoRequery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DragSortCursorAdapter(Context context, Cursor c, int flags) {
|
||||||
|
super(context, c, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps Cursor and clears list-Cursor mapping.
|
||||||
|
*
|
||||||
|
* @see android.widget.CursorAdapter#swapCursor(android.database.Cursor)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Cursor swapCursor(Cursor newCursor) {
|
||||||
|
Cursor old = super.swapCursor(newCursor);
|
||||||
|
resetMappings();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes Cursor and clears list-Cursor mapping.
|
||||||
|
*
|
||||||
|
* @see android.widget.CursorAdapter#changeCursor(android.database.Cursor)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void changeCursor(Cursor cursor) {
|
||||||
|
super.changeCursor(cursor);
|
||||||
|
resetMappings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets list-cursor mapping.
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
resetMappings();
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetMappings() {
|
||||||
|
mListMapping.clear();
|
||||||
|
mRemovedCursorPositions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int position) {
|
||||||
|
return super.getItem(mListMapping.get(position, position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return super.getItemId(mListMapping.get(position, position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||||
|
return super.getDropDownView(mListMapping.get(position, position), convertView, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
return super.getView(mListMapping.get(position, position), convertView, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On drop, this updates the mapping between Cursor positions
|
||||||
|
* and ListView positions. The Cursor is unchanged. Retrieve
|
||||||
|
* the current mapping with {@link getCursorPositions()}.
|
||||||
|
*
|
||||||
|
* @see DragSortListView.DropListener#drop(int, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void drop(int from, int to) {
|
||||||
|
if (from != to) {
|
||||||
|
int cursorFrom = mListMapping.get(from, from);
|
||||||
|
|
||||||
|
if (from > to) {
|
||||||
|
for (int i = from; i > to; --i) {
|
||||||
|
mListMapping.put(i, mListMapping.get(i - 1, i - 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = from; i < to; ++i) {
|
||||||
|
mListMapping.put(i, mListMapping.get(i + 1, i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mListMapping.put(to, cursorFrom);
|
||||||
|
|
||||||
|
cleanMapping();
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On remove, this updates the mapping between Cursor positions
|
||||||
|
* and ListView positions. The Cursor is unchanged. Retrieve
|
||||||
|
* the current mapping with {@link getCursorPositions()}.
|
||||||
|
*
|
||||||
|
* @see DragSortListView.RemoveListener#remove(int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void remove(int which) {
|
||||||
|
int cursorPos = mListMapping.get(which, which);
|
||||||
|
if (!mRemovedCursorPositions.contains(cursorPos)) {
|
||||||
|
mRemovedCursorPositions.add(cursorPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int newCount = getCount();
|
||||||
|
for (int i = which; i < newCount; ++i) {
|
||||||
|
mListMapping.put(i, mListMapping.get(i + 1, i + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
mListMapping.delete(newCount);
|
||||||
|
|
||||||
|
cleanMapping();
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing. Just completes DragSortListener interface.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void drag(int from, int to) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove unnecessary mappings from sparse array.
|
||||||
|
*/
|
||||||
|
private void cleanMapping() {
|
||||||
|
ArrayList<Integer> toRemove = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
int size = mListMapping.size();
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
if (mListMapping.keyAt(i) == mListMapping.valueAt(i)) {
|
||||||
|
toRemove.add(mListMapping.keyAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size = toRemove.size();
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
mListMapping.delete(toRemove.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return super.getCount() - mRemovedCursorPositions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Cursor position mapped to by the provided list position
|
||||||
|
* (given all previously handled drag-sort
|
||||||
|
* operations).
|
||||||
|
*
|
||||||
|
* @param position List position
|
||||||
|
*
|
||||||
|
* @return The mapped-to Cursor position
|
||||||
|
*/
|
||||||
|
public int getCursorPosition(int position) {
|
||||||
|
return mListMapping.get(position, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current order of Cursor positions presented by the
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
public ArrayList<Integer> getCursorPositions() {
|
||||||
|
ArrayList<Integer> result = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
for (int i = 0; i < getCount(); ++i) {
|
||||||
|
result.add(mListMapping.get(i, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list position mapped to by the provided Cursor position.
|
||||||
|
* If the provided Cursor position has been removed by a drag-sort,
|
||||||
|
* this returns {@link #REMOVED}.
|
||||||
|
*
|
||||||
|
* @param cursorPosition A Cursor position
|
||||||
|
* @return The mapped-to list position or REMOVED
|
||||||
|
*/
|
||||||
|
public int getListPosition(int cursorPosition) {
|
||||||
|
if (mRemovedCursorPositions.contains(cursorPosition)) {
|
||||||
|
return REMOVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = mListMapping.indexOfValue(cursorPosition);
|
||||||
|
if (index < 0) {
|
||||||
|
return cursorPosition;
|
||||||
|
} else {
|
||||||
|
return mListMapping.keyAt(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.mobeta.android.dslv;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.MeasureSpec;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.AbsListView;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lightweight ViewGroup that wraps list items obtained from user's
|
||||||
|
* ListAdapter. ItemView expects a single child that has a definite
|
||||||
|
* height (i.e. the child's layout height is not MATCH_PARENT).
|
||||||
|
* The width of
|
||||||
|
* ItemView will always match the width of its child (that is,
|
||||||
|
* the width MeasureSpec given to ItemView is passed directly
|
||||||
|
* to the child, and the ItemView measured width is set to the
|
||||||
|
* child's measured width). The height of ItemView can be anything;
|
||||||
|
* the
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The purpose of this class is to optimize slide
|
||||||
|
* shuffle animations.
|
||||||
|
*/
|
||||||
|
public class DragSortItemView extends ViewGroup {
|
||||||
|
|
||||||
|
private int mGravity = Gravity.TOP;
|
||||||
|
|
||||||
|
public DragSortItemView(Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
// always init with standard ListView layout params
|
||||||
|
setLayoutParams(new AbsListView.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.FILL_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
|
||||||
|
//setClipChildren(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGravity(int gravity) {
|
||||||
|
mGravity = gravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGravity() {
|
||||||
|
return mGravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
|
final View child = getChildAt(0);
|
||||||
|
|
||||||
|
if (child == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mGravity == Gravity.TOP) {
|
||||||
|
child.layout(0, 0, getMeasuredWidth(), child.getMeasuredHeight());
|
||||||
|
} else {
|
||||||
|
child.layout(0, getMeasuredHeight() - child.getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
|
||||||
|
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
|
||||||
|
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||||
|
|
||||||
|
final View child = getChildAt(0);
|
||||||
|
if (child == null) {
|
||||||
|
setMeasuredDimension(0, width);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.isLayoutRequested()) {
|
||||||
|
// Always let child be as tall as it wants.
|
||||||
|
measureChild(child, widthMeasureSpec,
|
||||||
|
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heightMode == MeasureSpec.UNSPECIFIED) {
|
||||||
|
ViewGroup.LayoutParams lp = getLayoutParams();
|
||||||
|
|
||||||
|
if (lp.height > 0) {
|
||||||
|
height = lp.height;
|
||||||
|
} else {
|
||||||
|
height = child.getMeasuredHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.mobeta.android.dslv;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.MeasureSpec;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.AbsListView;
|
||||||
|
import android.widget.Checkable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lightweight ViewGroup that wraps list items obtained from user's
|
||||||
|
* ListAdapter. ItemView expects a single child that has a definite
|
||||||
|
* height (i.e. the child's layout height is not MATCH_PARENT).
|
||||||
|
* The width of
|
||||||
|
* ItemView will always match the width of its child (that is,
|
||||||
|
* the width MeasureSpec given to ItemView is passed directly
|
||||||
|
* to the child, and the ItemView measured width is set to the
|
||||||
|
* child's measured width). The height of ItemView can be anything;
|
||||||
|
* the
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The purpose of this class is to optimize slide
|
||||||
|
* shuffle animations.
|
||||||
|
*/
|
||||||
|
public class DragSortItemViewCheckable extends DragSortItemView implements Checkable {
|
||||||
|
|
||||||
|
public DragSortItemViewCheckable(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChecked() {
|
||||||
|
View child = getChildAt(0);
|
||||||
|
if (child instanceof Checkable)
|
||||||
|
return ((Checkable) child).isChecked();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChecked(boolean checked) {
|
||||||
|
View child = getChildAt(0);
|
||||||
|
if (child instanceof Checkable)
|
||||||
|
((Checkable) child).setChecked(checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toggle() {
|
||||||
|
View child = getChildAt(0);
|
||||||
|
if (child instanceof Checkable)
|
||||||
|
((Checkable) child).toggle();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mobeta.android.dslv;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
|
||||||
|
// taken from v4 rev. 10 ResourceCursorAdapter.java
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static library support version of the framework's {@link android.widget.ResourceCursorAdapter}.
|
||||||
|
* Used to write apps that run on platforms prior to Android 3.0. When running
|
||||||
|
* on Android 3.0 or above, this implementation is still used; it does not try
|
||||||
|
* to switch to the framework's implementation. See the framework SDK
|
||||||
|
* documentation for a class overview.
|
||||||
|
*/
|
||||||
|
public abstract class ResourceDragSortCursorAdapter extends DragSortCursorAdapter {
|
||||||
|
private int mLayout;
|
||||||
|
|
||||||
|
private int mDropDownLayout;
|
||||||
|
|
||||||
|
private LayoutInflater mInflater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor the enables auto-requery.
|
||||||
|
*
|
||||||
|
* @deprecated This option is discouraged, as it results in Cursor queries
|
||||||
|
* being performed on the application's UI thread and thus can cause poor
|
||||||
|
* responsiveness or even Application Not Responding errors. As an alternative,
|
||||||
|
* use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
|
||||||
|
*
|
||||||
|
* @param context The context where the ListView associated with this adapter is running
|
||||||
|
* @param layout resource identifier of a layout file that defines the views
|
||||||
|
* for this list item. Unless you override them later, this will
|
||||||
|
* define both the item views and the drop down views.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c) {
|
||||||
|
super(context, c);
|
||||||
|
mLayout = mDropDownLayout = layout;
|
||||||
|
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor with default behavior as per
|
||||||
|
* {@link CursorAdapter#CursorAdapter(Context, Cursor, boolean)}; it is recommended
|
||||||
|
* you not use this, but instead {@link #ResourceCursorAdapter(Context, int, Cursor, int)}.
|
||||||
|
* When using this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER}
|
||||||
|
* will always be set.
|
||||||
|
*
|
||||||
|
* @param context The context where the ListView associated with this adapter is running
|
||||||
|
* @param layout resource identifier of a layout file that defines the views
|
||||||
|
* for this list item. Unless you override them later, this will
|
||||||
|
* define both the item views and the drop down views.
|
||||||
|
* @param c The cursor from which to get the data.
|
||||||
|
* @param autoRequery If true the adapter will call requery() on the
|
||||||
|
* cursor whenever it changes so the most recent
|
||||||
|
* data is always displayed. Using true here is discouraged.
|
||||||
|
*/
|
||||||
|
public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) {
|
||||||
|
super(context, c, autoRequery);
|
||||||
|
mLayout = mDropDownLayout = layout;
|
||||||
|
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard constructor.
|
||||||
|
*
|
||||||
|
* @param context The context where the ListView associated with this adapter is running
|
||||||
|
* @param layout Resource identifier of a layout file that defines the views
|
||||||
|
* for this list item. Unless you override them later, this will
|
||||||
|
* define both the item views and the drop down views.
|
||||||
|
* @param c The cursor from which to get the data.
|
||||||
|
* @param flags Flags used to determine the behavior of the adapter,
|
||||||
|
* as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}.
|
||||||
|
*/
|
||||||
|
public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c, int flags) {
|
||||||
|
super(context, c, flags);
|
||||||
|
mLayout = mDropDownLayout = layout;
|
||||||
|
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflates view(s) from the specified XML file.
|
||||||
|
*
|
||||||
|
* @see android.widget.CursorAdapter#newView(android.content.Context,
|
||||||
|
* android.database.Cursor, ViewGroup)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||||
|
return mInflater.inflate(mLayout, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
|
||||||
|
return mInflater.inflate(mDropDownLayout, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the layout resource of the item views.</p>
|
||||||
|
*
|
||||||
|
* @param layout the layout resources used to create item views
|
||||||
|
*/
|
||||||
|
public void setViewResource(int layout) {
|
||||||
|
mLayout = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the layout resource of the drop down views.</p>
|
||||||
|
*
|
||||||
|
* @param dropDownLayout the layout resources used to create drop down views
|
||||||
|
*/
|
||||||
|
public void setDropDownViewResource(int dropDownLayout) {
|
||||||
|
mDropDownLayout = dropDownLayout;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,422 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mobeta.android.dslv;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
// taken from sdk/sources/android-16/android/widget/SimpleCursorAdapter.java
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An easy adapter to map columns from a cursor to TextViews or ImageViews
|
||||||
|
* defined in an XML file. You can specify which columns you want, which
|
||||||
|
* views you want to display the columns, and the XML file that defines
|
||||||
|
* the appearance of these views.
|
||||||
|
*
|
||||||
|
* Binding occurs in two phases. First, if a
|
||||||
|
* {@link android.widget.SimpleCursorAdapter.ViewBinder} is available,
|
||||||
|
* {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}
|
||||||
|
* is invoked. If the returned value is true, binding has occured. If the
|
||||||
|
* returned value is false and the view to bind is a TextView,
|
||||||
|
* {@link #setViewText(TextView, String)} is invoked. If the returned value
|
||||||
|
* is false and the view to bind is an ImageView,
|
||||||
|
* {@link #setViewImage(ImageView, String)} is invoked. If no appropriate
|
||||||
|
* binding can be found, an {@link IllegalStateException} is thrown.
|
||||||
|
*
|
||||||
|
* If this adapter is used with filtering, for instance in an
|
||||||
|
* {@link android.widget.AutoCompleteTextView}, you can use the
|
||||||
|
* {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} and the
|
||||||
|
* {@link android.widget.FilterQueryProvider} interfaces
|
||||||
|
* to get control over the filtering process. You can refer to
|
||||||
|
* {@link #convertToString(android.database.Cursor)} and
|
||||||
|
* {@link #runQueryOnBackgroundThread(CharSequence)} for more information.
|
||||||
|
*/
|
||||||
|
public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter {
|
||||||
|
/**
|
||||||
|
* A list of columns containing the data to bind to the UI.
|
||||||
|
* This field should be made private, so it is hidden from the SDK.
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
protected int[] mFrom;
|
||||||
|
/**
|
||||||
|
* A list of View ids representing the views to which the data must be bound.
|
||||||
|
* This field should be made private, so it is hidden from the SDK.
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
protected int[] mTo;
|
||||||
|
|
||||||
|
private int mStringConversionColumn = -1;
|
||||||
|
private CursorToStringConverter mCursorToStringConverter;
|
||||||
|
private ViewBinder mViewBinder;
|
||||||
|
|
||||||
|
String[] mOriginalFrom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor the enables auto-requery.
|
||||||
|
*
|
||||||
|
* @deprecated This option is discouraged, as it results in Cursor queries
|
||||||
|
* being performed on the application's UI thread and thus can cause poor
|
||||||
|
* responsiveness or even Application Not Responding errors. As an alternative,
|
||||||
|
* use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public SimpleDragSortCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
|
||||||
|
super(context, layout, c);
|
||||||
|
mTo = to;
|
||||||
|
mOriginalFrom = from;
|
||||||
|
findColumns(c, from);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard constructor.
|
||||||
|
*
|
||||||
|
* @param context The context where the ListView associated with this
|
||||||
|
* SimpleListItemFactory is running
|
||||||
|
* @param layout resource identifier of a layout file that defines the views
|
||||||
|
* for this list item. The layout file should include at least
|
||||||
|
* those named views defined in "to"
|
||||||
|
* @param c The database cursor. Can be null if the cursor is not available yet.
|
||||||
|
* @param from A list of column names representing the data to bind to the UI. Can be null
|
||||||
|
* if the cursor is not available yet.
|
||||||
|
* @param to The views that should display column in the "from" parameter.
|
||||||
|
* These should all be TextViews. The first N views in this list
|
||||||
|
* are given the values of the first N columns in the from
|
||||||
|
* parameter. Can be null if the cursor is not available yet.
|
||||||
|
* @param flags Flags used to determine the behavior of the adapter,
|
||||||
|
* as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}.
|
||||||
|
*/
|
||||||
|
public SimpleDragSortCursorAdapter(Context context, int layout,
|
||||||
|
Cursor c, String[] from, int[] to, int flags) {
|
||||||
|
super(context, layout, c, flags);
|
||||||
|
mTo = to;
|
||||||
|
mOriginalFrom = from;
|
||||||
|
findColumns(c, from);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds all of the field names passed into the "to" parameter of the
|
||||||
|
* constructor with their corresponding cursor columns as specified in the
|
||||||
|
* "from" parameter.
|
||||||
|
*
|
||||||
|
* Binding occurs in two phases. First, if a
|
||||||
|
* {@link android.widget.SimpleCursorAdapter.ViewBinder} is available,
|
||||||
|
* {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}
|
||||||
|
* is invoked. If the returned value is true, binding has occured. If the
|
||||||
|
* returned value is false and the view to bind is a TextView,
|
||||||
|
* {@link #setViewText(TextView, String)} is invoked. If the returned value is
|
||||||
|
* false and the view to bind is an ImageView,
|
||||||
|
* {@link #setViewImage(ImageView, String)} is invoked. If no appropriate
|
||||||
|
* binding can be found, an {@link IllegalStateException} is thrown.
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if binding cannot occur
|
||||||
|
*
|
||||||
|
* @see android.widget.CursorAdapter#bindView(android.view.View,
|
||||||
|
* android.content.Context, android.database.Cursor)
|
||||||
|
* @see #getViewBinder()
|
||||||
|
* @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder)
|
||||||
|
* @see #setViewImage(ImageView, String)
|
||||||
|
* @see #setViewText(TextView, String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void bindView(View view, Context context, Cursor cursor) {
|
||||||
|
final ViewBinder binder = mViewBinder;
|
||||||
|
final int count = mTo.length;
|
||||||
|
final int[] from = mFrom;
|
||||||
|
final int[] to = mTo;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final View v = view.findViewById(to[i]);
|
||||||
|
if (v != null) {
|
||||||
|
boolean bound = false;
|
||||||
|
if (binder != null) {
|
||||||
|
bound = binder.setViewValue(v, cursor, from[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bound) {
|
||||||
|
String text = cursor.getString(from[i]);
|
||||||
|
if (text == null) {
|
||||||
|
text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v instanceof TextView) {
|
||||||
|
setViewText((TextView) v, text);
|
||||||
|
} else if (v instanceof ImageView) {
|
||||||
|
setViewImage((ImageView) v, text);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(v.getClass().getName() + " is not a " +
|
||||||
|
" view that can be bounds by this SimpleCursorAdapter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ViewBinder} used to bind data to views.
|
||||||
|
*
|
||||||
|
* @return a ViewBinder or null if the binder does not exist
|
||||||
|
*
|
||||||
|
* @see #bindView(android.view.View, android.content.Context, android.database.Cursor)
|
||||||
|
* @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder)
|
||||||
|
*/
|
||||||
|
public ViewBinder getViewBinder() {
|
||||||
|
return mViewBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the binder used to bind data to views.
|
||||||
|
*
|
||||||
|
* @param viewBinder the binder used to bind data to views, can be null to
|
||||||
|
* remove the existing binder
|
||||||
|
*
|
||||||
|
* @see #bindView(android.view.View, android.content.Context, android.database.Cursor)
|
||||||
|
* @see #getViewBinder()
|
||||||
|
*/
|
||||||
|
public void setViewBinder(ViewBinder viewBinder) {
|
||||||
|
mViewBinder = viewBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by bindView() to set the image for an ImageView but only if
|
||||||
|
* there is no existing ViewBinder or if the existing ViewBinder cannot
|
||||||
|
* handle binding to an ImageView.
|
||||||
|
*
|
||||||
|
* By default, the value will be treated as an image resource. If the
|
||||||
|
* value cannot be used as an image resource, the value is used as an
|
||||||
|
* image Uri.
|
||||||
|
*
|
||||||
|
* Intended to be overridden by Adapters that need to filter strings
|
||||||
|
* retrieved from the database.
|
||||||
|
*
|
||||||
|
* @param v ImageView to receive an image
|
||||||
|
* @param value the value retrieved from the cursor
|
||||||
|
*/
|
||||||
|
public void setViewImage(ImageView v, String value) {
|
||||||
|
try {
|
||||||
|
v.setImageResource(Integer.parseInt(value));
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
v.setImageURI(Uri.parse(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by bindView() to set the text for a TextView but only if
|
||||||
|
* there is no existing ViewBinder or if the existing ViewBinder cannot
|
||||||
|
* handle binding to a TextView.
|
||||||
|
*
|
||||||
|
* Intended to be overridden by Adapters that need to filter strings
|
||||||
|
* retrieved from the database.
|
||||||
|
*
|
||||||
|
* @param v TextView to receive text
|
||||||
|
* @param text the text to be set for the TextView
|
||||||
|
*/
|
||||||
|
public void setViewText(TextView v, String text) {
|
||||||
|
v.setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the index of the column used to get a String representation
|
||||||
|
* of the Cursor.
|
||||||
|
*
|
||||||
|
* @return a valid index in the current Cursor or -1
|
||||||
|
*
|
||||||
|
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||||
|
* @see #setStringConversionColumn(int)
|
||||||
|
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||||
|
* @see #getCursorToStringConverter()
|
||||||
|
*/
|
||||||
|
public int getStringConversionColumn() {
|
||||||
|
return mStringConversionColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the index of the column in the Cursor used to get a String
|
||||||
|
* representation of that Cursor. The column is used to convert the
|
||||||
|
* Cursor to a String only when the current CursorToStringConverter
|
||||||
|
* is null.
|
||||||
|
*
|
||||||
|
* @param stringConversionColumn a valid index in the current Cursor or -1 to use the default
|
||||||
|
* conversion mechanism
|
||||||
|
*
|
||||||
|
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||||
|
* @see #getStringConversionColumn()
|
||||||
|
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||||
|
* @see #getCursorToStringConverter()
|
||||||
|
*/
|
||||||
|
public void setStringConversionColumn(int stringConversionColumn) {
|
||||||
|
mStringConversionColumn = stringConversionColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the converter used to convert the filtering Cursor
|
||||||
|
* into a String.
|
||||||
|
*
|
||||||
|
* @return null if the converter does not exist or an instance of
|
||||||
|
* {@link android.widget.SimpleCursorAdapter.CursorToStringConverter}
|
||||||
|
*
|
||||||
|
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||||
|
* @see #getStringConversionColumn()
|
||||||
|
* @see #setStringConversionColumn(int)
|
||||||
|
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||||
|
*/
|
||||||
|
public CursorToStringConverter getCursorToStringConverter() {
|
||||||
|
return mCursorToStringConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the converter used to convert the filtering Cursor
|
||||||
|
* into a String.
|
||||||
|
*
|
||||||
|
* @param cursorToStringConverter the Cursor to String converter, or
|
||||||
|
* null to remove the converter
|
||||||
|
*
|
||||||
|
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||||
|
* @see #getStringConversionColumn()
|
||||||
|
* @see #setStringConversionColumn(int)
|
||||||
|
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||||
|
*/
|
||||||
|
public void setCursorToStringConverter(CursorToStringConverter cursorToStringConverter) {
|
||||||
|
mCursorToStringConverter = cursorToStringConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a CharSequence representation of the specified Cursor as defined
|
||||||
|
* by the current CursorToStringConverter. If no CursorToStringConverter
|
||||||
|
* has been set, the String conversion column is used instead. If the
|
||||||
|
* conversion column is -1, the returned String is empty if the cursor
|
||||||
|
* is null or Cursor.toString().
|
||||||
|
*
|
||||||
|
* @param cursor the Cursor to convert to a CharSequence
|
||||||
|
*
|
||||||
|
* @return a non-null CharSequence representing the cursor
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CharSequence convertToString(Cursor cursor) {
|
||||||
|
if (mCursorToStringConverter != null) {
|
||||||
|
return mCursorToStringConverter.convertToString(cursor);
|
||||||
|
} else if (mStringConversionColumn > -1) {
|
||||||
|
return cursor.getString(mStringConversionColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.convertToString(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a map from an array of strings to an array of column-id integers in cursor c.
|
||||||
|
* If c is null, the array will be discarded.
|
||||||
|
*
|
||||||
|
* @param c the cursor to find the columns from
|
||||||
|
* @param from the Strings naming the columns of interest
|
||||||
|
*/
|
||||||
|
private void findColumns(Cursor c, String[] from) {
|
||||||
|
if (c != null) {
|
||||||
|
int i;
|
||||||
|
int count = from.length;
|
||||||
|
if (mFrom == null || mFrom.length != count) {
|
||||||
|
mFrom = new int[count];
|
||||||
|
}
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
mFrom[i] = c.getColumnIndexOrThrow(from[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mFrom = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor swapCursor(Cursor c) {
|
||||||
|
// super.swapCursor() will notify observers before we have
|
||||||
|
// a valid mapping, make sure we have a mapping before this
|
||||||
|
// happens
|
||||||
|
findColumns(c, mOriginalFrom);
|
||||||
|
return super.swapCursor(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the cursor and change the column-to-view mappings at the same time.
|
||||||
|
*
|
||||||
|
* @param c The database cursor. Can be null if the cursor is not available yet.
|
||||||
|
* @param from A list of column names representing the data to bind to the UI. Can be null
|
||||||
|
* if the cursor is not available yet.
|
||||||
|
* @param to The views that should display column in the "from" parameter.
|
||||||
|
* These should all be TextViews. The first N views in this list
|
||||||
|
* are given the values of the first N columns in the from
|
||||||
|
* parameter. Can be null if the cursor is not available yet.
|
||||||
|
*/
|
||||||
|
public void changeCursorAndColumns(Cursor c, String[] from, int[] to) {
|
||||||
|
mOriginalFrom = from;
|
||||||
|
mTo = to;
|
||||||
|
// super.changeCursor() will notify observers before we have
|
||||||
|
// a valid mapping, make sure we have a mapping before this
|
||||||
|
// happens
|
||||||
|
findColumns(c, mOriginalFrom);
|
||||||
|
super.changeCursor(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be used by external clients of SimpleCursorAdapter
|
||||||
|
* to bind values fom the Cursor to views.
|
||||||
|
*
|
||||||
|
* You should use this class to bind values from the Cursor to views
|
||||||
|
* that are not directly supported by SimpleCursorAdapter or to
|
||||||
|
* change the way binding occurs for views supported by
|
||||||
|
* SimpleCursorAdapter.
|
||||||
|
*
|
||||||
|
* @see SimpleCursorAdapter#bindView(android.view.View, android.content.Context, android.database.Cursor)
|
||||||
|
* @see SimpleCursorAdapter#setViewImage(ImageView, String)
|
||||||
|
* @see SimpleCursorAdapter#setViewText(TextView, String)
|
||||||
|
*/
|
||||||
|
public static interface ViewBinder {
|
||||||
|
/**
|
||||||
|
* Binds the Cursor column defined by the specified index to the specified view.
|
||||||
|
*
|
||||||
|
* When binding is handled by this ViewBinder, this method must return true.
|
||||||
|
* If this method returns false, SimpleCursorAdapter will attempts to handle
|
||||||
|
* the binding on its own.
|
||||||
|
*
|
||||||
|
* @param view the view to bind the data to
|
||||||
|
* @param cursor the cursor to get the data from
|
||||||
|
* @param columnIndex the column at which the data can be found in the cursor
|
||||||
|
*
|
||||||
|
* @return true if the data was bound to the view, false otherwise
|
||||||
|
*/
|
||||||
|
boolean setViewValue(View view, Cursor cursor, int columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be used by external clients of SimpleCursorAdapter
|
||||||
|
* to define how the Cursor should be converted to a String.
|
||||||
|
*
|
||||||
|
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||||
|
*/
|
||||||
|
public static interface CursorToStringConverter {
|
||||||
|
/**
|
||||||
|
* Returns a CharSequence representing the specified Cursor.
|
||||||
|
*
|
||||||
|
* @param cursor the cursor for which a CharSequence representation
|
||||||
|
* is requested
|
||||||
|
*
|
||||||
|
* @return a non-null CharSequence representing the cursor
|
||||||
|
*/
|
||||||
|
CharSequence convertToString(Cursor cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.mobeta.android.dslv;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple implementation of the FloatViewManager class. Uses list
|
||||||
|
* items as they appear in the ListView to create the floating View.
|
||||||
|
*/
|
||||||
|
public class SimpleFloatViewManager implements DragSortListView.FloatViewManager {
|
||||||
|
|
||||||
|
private Bitmap mFloatBitmap;
|
||||||
|
|
||||||
|
private ImageView mImageView;
|
||||||
|
|
||||||
|
private int mFloatBGColor = Color.BLACK;
|
||||||
|
|
||||||
|
private ListView mListView;
|
||||||
|
|
||||||
|
public SimpleFloatViewManager(ListView lv) {
|
||||||
|
mListView = lv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackgroundColor(int color) {
|
||||||
|
mFloatBGColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This simple implementation creates a Bitmap copy of the
|
||||||
|
* list item currently shown at ListView <code>position</code>.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public View onCreateFloatView(int position) {
|
||||||
|
// Guaranteed that this will not be null? I think so. Nope, got
|
||||||
|
// a NullPointerException once...
|
||||||
|
View v = mListView.getChildAt(position + mListView.getHeaderViewsCount() - mListView.getFirstVisiblePosition());
|
||||||
|
|
||||||
|
if (v == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
v.setPressed(false);
|
||||||
|
|
||||||
|
// Create a copy of the drawing cache so that it does not get
|
||||||
|
// recycled by the framework when the list tries to clean up memory
|
||||||
|
//v.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
|
||||||
|
v.setDrawingCacheEnabled(true);
|
||||||
|
mFloatBitmap = Bitmap.createBitmap(v.getDrawingCache());
|
||||||
|
v.setDrawingCacheEnabled(false);
|
||||||
|
|
||||||
|
if (mImageView == null) {
|
||||||
|
mImageView = new ImageView(mListView.getContext());
|
||||||
|
}
|
||||||
|
mImageView.setBackgroundColor(mFloatBGColor);
|
||||||
|
mImageView.setPadding(0, 0, 0, 0);
|
||||||
|
mImageView.setImageBitmap(mFloatBitmap);
|
||||||
|
mImageView.setLayoutParams(new ViewGroup.LayoutParams(v.getWidth(), v.getHeight()));
|
||||||
|
|
||||||
|
return mImageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This does nothing
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onDragFloatView(View floatView, Point position, Point touch) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the Bitmap from the ImageView created in
|
||||||
|
* onCreateFloatView() and tells the system to recycle it.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onDestroyFloatView(View floatView) {
|
||||||
|
((ImageView) floatView).setImageDrawable(null);
|
||||||
|
|
||||||
|
mFloatBitmap.recycle();
|
||||||
|
mFloatBitmap = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.isoron.helpers;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class Command {
|
||||||
|
public abstract void execute();
|
||||||
|
public abstract void undo();
|
||||||
|
|
||||||
|
public Integer getExecuteStringId() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUndoStringId() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package org.isoron.helpers;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
public class DateHelper
|
||||||
|
{
|
||||||
|
public static int millisecondsInOneDay = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
public static long getLocalTime()
|
||||||
|
{
|
||||||
|
TimeZone tz = TimeZone.getDefault();
|
||||||
|
long now = new Date().getTime();
|
||||||
|
return now + tz.getOffset(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getStartOfDay(long timestamp)
|
||||||
|
{
|
||||||
|
return (timestamp / millisecondsInOneDay) * millisecondsInOneDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static Date getStartOfDay(Date date)
|
||||||
|
// {
|
||||||
|
// Calendar calendar = Calendar.getInstance();
|
||||||
|
// calendar.setTime(date);
|
||||||
|
// calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
// calendar.set(Calendar.MINUTE, 0);
|
||||||
|
// calendar.set(Calendar.SECOND, 0);
|
||||||
|
// calendar.set(Calendar.MILLISECOND, 0);
|
||||||
|
// return calendar.getTime();
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static int differenceInDays(Date from, Date to)
|
||||||
|
{
|
||||||
|
long milliseconds = getStartOfDay(to.getTime()) - getStartOfDay(from.getTime());
|
||||||
|
int days = (int) (milliseconds / millisecondsInOneDay);
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String differenceInWords(Date from, Date to)
|
||||||
|
{
|
||||||
|
Integer days = differenceInDays(from, to);
|
||||||
|
boolean negative = (days < 0);
|
||||||
|
days = Math.abs(days);
|
||||||
|
|
||||||
|
Integer weeks = (int) Math.round(days / 7.0);
|
||||||
|
Double months = days / 30.4;
|
||||||
|
Double years = days / 365.0;
|
||||||
|
|
||||||
|
StringBuffer s = new StringBuffer();
|
||||||
|
DecimalFormat df = new DecimalFormat("#.#");
|
||||||
|
|
||||||
|
if(months > 18)
|
||||||
|
{
|
||||||
|
s.append(df.format(years));
|
||||||
|
s.append(" years");
|
||||||
|
}
|
||||||
|
else if(weeks > 6)
|
||||||
|
{
|
||||||
|
s.append(df.format(months));
|
||||||
|
s.append(" months");
|
||||||
|
}
|
||||||
|
else if(days > 13)
|
||||||
|
{
|
||||||
|
s.append(weeks);
|
||||||
|
s.append(" weeks");
|
||||||
|
}
|
||||||
|
else if(days > 6)
|
||||||
|
{
|
||||||
|
s.append(days);
|
||||||
|
s.append(" days");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(days == 0)
|
||||||
|
s.append("Today");
|
||||||
|
else if(days == 1 && negative)
|
||||||
|
s.append("Yesterday");
|
||||||
|
else if(days == 1 && !negative)
|
||||||
|
s.append("Tomorrow");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(negative)
|
||||||
|
s.append("past ");
|
||||||
|
s.append(new SimpleDateFormat("EEEE").format(to));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(negative && days > 6)
|
||||||
|
s.append(" ago");
|
||||||
|
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package org.isoron.helpers;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
|
public abstract class DialogHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
// public static AlertDialog alert(Activity context, String title, String message, OnClickListener positiveClickListener) {
|
||||||
|
// return new AlertDialog.Builder(context)
|
||||||
|
// .setTitle(title)
|
||||||
|
// .setMessage(message)
|
||||||
|
// .setPositiveButton(android.R.string.yes, positiveClickListener)
|
||||||
|
// .setNegativeButton(android.R.string.no, null).show();
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static abstract class SimpleClickListener implements OnClickListener
|
||||||
|
{
|
||||||
|
public abstract void onClick();
|
||||||
|
|
||||||
|
public void onClick(DialogInterface dialog, int whichButton)
|
||||||
|
{
|
||||||
|
onClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface OnSavedListener
|
||||||
|
{
|
||||||
|
public void onSaved(Command command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showSoftKeyboard(View view)
|
||||||
|
{
|
||||||
|
InputMethodManager imm = (InputMethodManager)
|
||||||
|
view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import org.isoron.helpers.Command;
|
||||||
|
import org.isoron.uhabits.dialogs.ShowHabitsFragment;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
public class MainActivity extends Activity
|
||||||
|
{
|
||||||
|
|
||||||
|
private ShowHabitsFragment showHabitsFragment;
|
||||||
|
|
||||||
|
private LinkedList<Command> undoList;
|
||||||
|
private LinkedList<Command> redoList;
|
||||||
|
|
||||||
|
private static int MAX_UNDO_LEVEL = 15;
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Creation *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
// Habit.rebuildOrder();
|
||||||
|
// Habit.roundTimestamps();
|
||||||
|
setContentView(R.layout.main_activity);
|
||||||
|
showHabitsFragment = (ShowHabitsFragment) getFragmentManager().findFragmentById(
|
||||||
|
R.id.fragment1);
|
||||||
|
|
||||||
|
undoList = new LinkedList<Command>();
|
||||||
|
redoList = new LinkedList<Command>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Action Bar Menu *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu)
|
||||||
|
{
|
||||||
|
getMenuInflater().inflate(R.menu.main_activity, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item)
|
||||||
|
{
|
||||||
|
int id = item.getItemId();
|
||||||
|
if(id == R.id.action_settings)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Commands, Undo, Redo *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
public void executeCommand(Command command, boolean datasetChanged)
|
||||||
|
{
|
||||||
|
executeCommand(command, datasetChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void executeCommand(Command command, boolean datasetChanged, boolean clearRedoStack)
|
||||||
|
{
|
||||||
|
undoList.push(command);
|
||||||
|
if(undoList.size() > MAX_UNDO_LEVEL)
|
||||||
|
undoList.removeLast();
|
||||||
|
if(clearRedoStack)
|
||||||
|
redoList.clear();
|
||||||
|
command.execute();
|
||||||
|
|
||||||
|
showToast(command.getExecuteStringId());
|
||||||
|
if(datasetChanged)
|
||||||
|
{
|
||||||
|
showHabitsFragment.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void undo()
|
||||||
|
{
|
||||||
|
if(undoList.isEmpty())
|
||||||
|
{
|
||||||
|
showToast(R.string.toast_nothing_to_undo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command last = undoList.pop();
|
||||||
|
redoList.push(last);
|
||||||
|
last.undo();
|
||||||
|
showToast(last.getUndoStringId());
|
||||||
|
|
||||||
|
showHabitsFragment.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void redo()
|
||||||
|
{
|
||||||
|
if(redoList.isEmpty())
|
||||||
|
{
|
||||||
|
showToast(R.string.toast_nothing_to_redo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Command last = redoList.pop();
|
||||||
|
executeCommand(last, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Toast toast;
|
||||||
|
|
||||||
|
private void showToast(Integer stringId)
|
||||||
|
{
|
||||||
|
if(stringId == null)
|
||||||
|
return;
|
||||||
|
if(toast == null)
|
||||||
|
toast = Toast.makeText(this, stringId, Toast.LENGTH_SHORT);
|
||||||
|
else
|
||||||
|
toast.setText(stringId);
|
||||||
|
toast.show();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,209 @@
|
|||||||
|
package org.isoron.uhabits.dialogs;
|
||||||
|
|
||||||
|
import org.isoron.helpers.Command;
|
||||||
|
import org.isoron.helpers.DialogHelper.OnSavedListener;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.ColorMatrix;
|
||||||
|
import android.graphics.ColorMatrixColorFilter;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.colorpicker.ColorPickerDialog;
|
||||||
|
import com.android.colorpicker.ColorPickerSwatch;
|
||||||
|
|
||||||
|
public class EditHabitFragment extends DialogFragment implements OnClickListener
|
||||||
|
{
|
||||||
|
private int mode;
|
||||||
|
static final int EDIT_MODE = 0;
|
||||||
|
static final int CREATE_MODE = 1;
|
||||||
|
|
||||||
|
private OnSavedListener onSavedListener;
|
||||||
|
|
||||||
|
private Habit originalHabit, modifiedHabit;
|
||||||
|
private TextView tvName, tvDescription, tvFreqNum, tvFreqDen;
|
||||||
|
|
||||||
|
static class SolidColorMatrix extends ColorMatrix
|
||||||
|
{
|
||||||
|
public SolidColorMatrix(int color)
|
||||||
|
{
|
||||||
|
float matrix[] = { 0.0f, 0.0f, 0.0f, 0.0f, Color.red(color), 0.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
Color.green(color), 0.0f, 0.0f, 0.0f, 0.0f, Color.blue(color), 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0 };
|
||||||
|
set(matrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Factory *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
static EditHabitFragment editSingleHabitFragment(long id)
|
||||||
|
{
|
||||||
|
EditHabitFragment frag = new EditHabitFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putLong("habitId", id);
|
||||||
|
args.putInt("editMode", EDIT_MODE);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EditHabitFragment createHabitFragment()
|
||||||
|
{
|
||||||
|
EditHabitFragment frag = new EditHabitFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putInt("editMode", CREATE_MODE);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Creation *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
View view = inflater.inflate(R.layout.edit_habit, container, false);
|
||||||
|
tvName = (TextView) view.findViewById(R.id.input_name);
|
||||||
|
tvDescription = (TextView) view.findViewById(R.id.input_description);
|
||||||
|
tvFreqNum = (TextView) view.findViewById(R.id.input_freq_num);
|
||||||
|
tvFreqDen = (TextView) view.findViewById(R.id.input_freq_den);
|
||||||
|
|
||||||
|
Button buttonSave = (Button) view.findViewById(R.id.button_save);
|
||||||
|
Button buttonDiscard = (Button) view.findViewById(R.id.button_discard);
|
||||||
|
|
||||||
|
buttonSave.setOnClickListener(this);
|
||||||
|
buttonDiscard.setOnClickListener(this);
|
||||||
|
|
||||||
|
ImageButton buttonPickColor = (ImageButton) view.findViewById(R.id.button_pick_color);
|
||||||
|
|
||||||
|
Bundle args = getArguments();
|
||||||
|
mode = (Integer) args.get("editMode");
|
||||||
|
|
||||||
|
if(mode == CREATE_MODE)
|
||||||
|
{
|
||||||
|
getDialog().setTitle("Create habit");
|
||||||
|
modifiedHabit = new Habit();
|
||||||
|
}
|
||||||
|
else if(mode == EDIT_MODE)
|
||||||
|
{
|
||||||
|
originalHabit = Habit.get((Long) args.get("habitId"));
|
||||||
|
modifiedHabit = new Habit(originalHabit);
|
||||||
|
|
||||||
|
getDialog().setTitle("Edit habit");
|
||||||
|
tvName.append(modifiedHabit.name);
|
||||||
|
tvDescription.append(modifiedHabit.description);
|
||||||
|
tvFreqNum.setText(null);
|
||||||
|
tvFreqDen.setText(null);
|
||||||
|
tvFreqNum.append(modifiedHabit.freq_num.toString());
|
||||||
|
tvFreqDen.append(modifiedHabit.freq_den.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
changeColor(modifiedHabit.color);
|
||||||
|
|
||||||
|
buttonPickColor.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(View view)
|
||||||
|
{
|
||||||
|
ColorPickerDialog picker = ColorPickerDialog.newInstance(
|
||||||
|
R.string.color_picker_default_title,
|
||||||
|
Habit.colors, modifiedHabit.color, 4, ColorPickerDialog.SIZE_SMALL);
|
||||||
|
|
||||||
|
picker.setOnColorSelectedListener(new ColorPickerSwatch.OnColorSelectedListener()
|
||||||
|
{
|
||||||
|
public void onColorSelected(int color)
|
||||||
|
{
|
||||||
|
modifiedHabit.color = color;
|
||||||
|
changeColor(color);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
picker.show(getFragmentManager(), "picker");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeColor(Integer color)
|
||||||
|
{
|
||||||
|
SolidColorMatrix matrix = new SolidColorMatrix(color);
|
||||||
|
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
|
||||||
|
Drawable background = getActivity().getResources().getDrawable(
|
||||||
|
R.drawable.apptheme_edit_text_holo_light);
|
||||||
|
background.setColorFilter(filter);
|
||||||
|
tvName.setBackgroundDrawable(background);
|
||||||
|
tvName.setTextColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnSavedListener(OnSavedListener onSavedListener)
|
||||||
|
{
|
||||||
|
this.onSavedListener = onSavedListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Callback *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v)
|
||||||
|
{
|
||||||
|
int id = v.getId();
|
||||||
|
|
||||||
|
/* Save button */
|
||||||
|
if(id == R.id.button_save)
|
||||||
|
{
|
||||||
|
Command command = null;
|
||||||
|
|
||||||
|
modifiedHabit.name = tvName.getText().toString().trim();
|
||||||
|
modifiedHabit.description = tvDescription.getText().toString().trim();
|
||||||
|
modifiedHabit.freq_num = Integer.parseInt(tvFreqNum.getText().toString());
|
||||||
|
modifiedHabit.freq_den = Integer.parseInt(tvFreqDen.getText().toString());
|
||||||
|
|
||||||
|
Boolean valid = true;
|
||||||
|
|
||||||
|
if(modifiedHabit.name.length() == 0)
|
||||||
|
{
|
||||||
|
tvName.setError("Name cannot be blank.");
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modifiedHabit.freq_num <= 0)
|
||||||
|
{
|
||||||
|
tvFreqNum.setError("Frequency has to be positive.");
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(mode == EDIT_MODE)
|
||||||
|
command = originalHabit.new EditCommand(modifiedHabit);
|
||||||
|
|
||||||
|
if(mode == CREATE_MODE)
|
||||||
|
command = new Habit.CreateCommand(modifiedHabit);
|
||||||
|
|
||||||
|
if(onSavedListener != null)
|
||||||
|
onSavedListener.onSaved(command);
|
||||||
|
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Discard button */
|
||||||
|
if(id == R.id.button_discard)
|
||||||
|
{
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,357 @@
|
|||||||
|
package org.isoron.uhabits.dialogs;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import org.isoron.helpers.Command;
|
||||||
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.helpers.DialogHelper.OnSavedListener;
|
||||||
|
import org.isoron.uhabits.MainActivity;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Vibrator;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnLongClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||||
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.LinearLayout.LayoutParams;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.mobeta.android.dslv.DragSortController;
|
||||||
|
import com.mobeta.android.dslv.DragSortListView;
|
||||||
|
import com.mobeta.android.dslv.DragSortListView.DropListener;
|
||||||
|
|
||||||
|
public class ShowHabitsFragment extends Fragment implements OnSavedListener, OnItemClickListener,
|
||||||
|
OnLongClickListener, DropListener
|
||||||
|
{
|
||||||
|
|
||||||
|
private int tvNameWidth;
|
||||||
|
private int button_count;
|
||||||
|
ShowHabitsAdapter adapter;
|
||||||
|
DragSortListView listView;
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Adapter *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
class ShowHabitsAdapter extends BaseAdapter
|
||||||
|
{
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
private LayoutInflater inflater;
|
||||||
|
private Typeface fontawesome;
|
||||||
|
|
||||||
|
String habits[] = { "wake up early", "work out", "meditate", "take vitamins",
|
||||||
|
"go to school",
|
||||||
|
"cook dinner & lunch" };
|
||||||
|
|
||||||
|
public ShowHabitsAdapter(Context context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
|
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
fontawesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount()
|
||||||
|
{
|
||||||
|
return Habit.getCount() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int position)
|
||||||
|
{
|
||||||
|
if(position == 0)
|
||||||
|
return null;
|
||||||
|
return Habit.getByPosition(position - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position)
|
||||||
|
{
|
||||||
|
if(position == 0)
|
||||||
|
return 0;
|
||||||
|
return ((Habit) getItem(position)).getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View view, ViewGroup parent)
|
||||||
|
{
|
||||||
|
final Habit habit = (Habit) getItem(position);
|
||||||
|
|
||||||
|
if(view == null)
|
||||||
|
{
|
||||||
|
view = inflater.inflate(R.layout.show_habits_item, null);
|
||||||
|
((TextView) view.findViewById(R.id.tvStar)).setTypeface(fontawesome);
|
||||||
|
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(tvNameWidth,
|
||||||
|
LayoutParams.WRAP_CONTENT, 1);
|
||||||
|
((TextView) view.findViewById(R.id.tvName)).setLayoutParams(params);
|
||||||
|
|
||||||
|
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
|
||||||
|
.getDefaultDisplay();
|
||||||
|
Point size = new Point();
|
||||||
|
display.getSize(size);
|
||||||
|
|
||||||
|
for (int i = 0; i < button_count; i++)
|
||||||
|
{
|
||||||
|
View check = inflater.inflate(R.layout.show_habits_item_check, null);
|
||||||
|
Button btCheck = (Button) check.findViewById(R.id.tvCheck);
|
||||||
|
btCheck.setTypeface(fontawesome);
|
||||||
|
btCheck.setOnLongClickListener(ShowHabitsFragment.this);
|
||||||
|
((LinearLayout) view.findViewById(R.id.llButtons)).addView(check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView tvStar = (TextView) view.findViewById(R.id.tvStar);
|
||||||
|
TextView tvName = (TextView) view.findViewById(R.id.tvName);
|
||||||
|
|
||||||
|
if(habit == null)
|
||||||
|
{
|
||||||
|
tvName.setText(null);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inactiveColor = Color.rgb(230, 230, 230);
|
||||||
|
int activeColor = habit.color;
|
||||||
|
|
||||||
|
tvName.setText(habit.name);
|
||||||
|
tvName.setTextColor(activeColor);
|
||||||
|
|
||||||
|
int score = habit.getScore();
|
||||||
|
if(score < 5999000)
|
||||||
|
{
|
||||||
|
tvStar.setText(context.getString(R.string.fa_star_o));
|
||||||
|
tvStar.setTextColor(Color.LTGRAY);
|
||||||
|
}
|
||||||
|
else if(score < 12973000)
|
||||||
|
{
|
||||||
|
tvStar.setText(context.getString(R.string.fa_star_half_o));
|
||||||
|
tvStar.setTextColor(Color.LTGRAY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tvStar.setText(context.getString(R.string.fa_star));
|
||||||
|
tvStar.setTextColor(activeColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
|
||||||
|
int m = llButtons.getChildCount();
|
||||||
|
|
||||||
|
long dateTo = DateHelper.getStartOfDay(DateHelper.getLocalTime());
|
||||||
|
long dateFrom = dateTo - m * DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
|
int isChecked[] = habit.getReps(dateFrom, dateTo);
|
||||||
|
|
||||||
|
for (int i = 0; i < m; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
Button tvCheck = (Button) llButtons.getChildAt(i);
|
||||||
|
tvCheck.setTag(R.string.habit_key, habit.getId());
|
||||||
|
tvCheck.setTag(R.string.offset_key, i);
|
||||||
|
|
||||||
|
switch(isChecked[i])
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
tvCheck.setText(R.string.fa_check);
|
||||||
|
tvCheck.setTextColor(activeColor);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
tvCheck.setText(R.string.fa_check);
|
||||||
|
tvCheck.setTextColor(inactiveColor);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
tvCheck.setText(R.string.fa_times);
|
||||||
|
tvCheck.setTextColor(inactiveColor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Creation *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
View view = inflater.inflate(R.layout.show_habits, container, false);
|
||||||
|
|
||||||
|
DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||||
|
int width = (int) (dm.widthPixels / dm.density);
|
||||||
|
button_count = (int) ((width - 160) / 42);
|
||||||
|
tvNameWidth = (int) ((width - 30 - button_count * 42) * dm.density);
|
||||||
|
|
||||||
|
adapter = new ShowHabitsAdapter(getActivity());
|
||||||
|
listView = (DragSortListView) view.findViewById(R.id.listView);
|
||||||
|
listView.setAdapter(adapter);
|
||||||
|
listView.setOnItemClickListener(this);
|
||||||
|
registerForContextMenu(listView);
|
||||||
|
listView.setDropListener(this);
|
||||||
|
|
||||||
|
DragSortController controller = new DragSortController(listView);
|
||||||
|
controller.setDragHandleId(R.id.tvStar);
|
||||||
|
controller.setRemoveEnabled(false);
|
||||||
|
controller.setSortEnabled(true);
|
||||||
|
controller.setDragInitMode(1);
|
||||||
|
|
||||||
|
listView.setFloatViewManager(controller);
|
||||||
|
listView.setOnTouchListener(controller);
|
||||||
|
listView.setDragEnabled(true);
|
||||||
|
|
||||||
|
GregorianCalendar day = new GregorianCalendar();
|
||||||
|
day.setTimeInMillis(DateHelper.getLocalTime());
|
||||||
|
|
||||||
|
for (int i = 0; i < button_count; i++)
|
||||||
|
{
|
||||||
|
View check = inflater.inflate(R.layout.show_habits_header_check, null);
|
||||||
|
Button btCheck = (Button) check.findViewById(R.id.tvCheck);
|
||||||
|
btCheck.setText(day.getDisplayName(GregorianCalendar.DAY_OF_WEEK,
|
||||||
|
GregorianCalendar.SHORT, Locale.US) + "\n"
|
||||||
|
+ Integer.toString(day.get(GregorianCalendar.DAY_OF_MONTH)));
|
||||||
|
((LinearLayout) view.findViewById(R.id.llButtonsHeader)).addView(check);
|
||||||
|
|
||||||
|
day.add(GregorianCalendar.DAY_OF_MONTH, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
|
||||||
|
{
|
||||||
|
inflater.inflate(R.menu.show_habits_options, menu);
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo)
|
||||||
|
{
|
||||||
|
super.onCreateContextMenu(menu, view, menuInfo);
|
||||||
|
getActivity().getMenuInflater().inflate(R.menu.show_habits_context, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Callback *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item)
|
||||||
|
{
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
if(id == R.id.action_add)
|
||||||
|
{
|
||||||
|
EditHabitFragment frag = EditHabitFragment.createHabitFragment();
|
||||||
|
frag.setOnSavedListener(this);
|
||||||
|
frag.show(getFragmentManager(), "dialog");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(MenuItem menuItem)
|
||||||
|
{
|
||||||
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuItem.getMenuInfo();
|
||||||
|
final int id = menuItem.getItemId();
|
||||||
|
final Habit habit = Habit.get(info.id);
|
||||||
|
|
||||||
|
if(id == R.id.action_edit_habit)
|
||||||
|
{
|
||||||
|
EditHabitFragment frag = EditHabitFragment.editSingleHabitFragment(habit.getId());
|
||||||
|
frag.setOnSavedListener(this);
|
||||||
|
frag.show(getFragmentManager(), "dialog");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onContextItemSelected(menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaved(Command command)
|
||||||
|
{
|
||||||
|
executeCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyDataSetChanged()
|
||||||
|
{
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v)
|
||||||
|
{
|
||||||
|
int id = v.getId();
|
||||||
|
|
||||||
|
if(id == R.id.tvCheck)
|
||||||
|
{
|
||||||
|
Habit habit = Habit.get((Long) v.getTag(R.string.habit_key));
|
||||||
|
int offset = (Integer) v.getTag(R.string.offset_key);
|
||||||
|
long timestamp = DateHelper.getStartOfDay(DateHelper.getLocalTime() - offset
|
||||||
|
* DateHelper.millisecondsInOneDay);
|
||||||
|
|
||||||
|
executeCommand(habit.new ToggleRepetitionCommand(timestamp));
|
||||||
|
|
||||||
|
Vibrator vb = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
vb.vibrate(100);
|
||||||
|
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeCommand(Command c)
|
||||||
|
{
|
||||||
|
((MainActivity) getActivity()).executeCommand(c, false);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drop(int from, int to)
|
||||||
|
{
|
||||||
|
Habit.reorder(from - 1, to - 1);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,427 @@
|
|||||||
|
package org.isoron.uhabits.models;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.isoron.helpers.Command;
|
||||||
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.graphics.Color;
|
||||||
|
|
||||||
|
import com.activeandroid.Model;
|
||||||
|
import com.activeandroid.annotation.Column;
|
||||||
|
import com.activeandroid.annotation.Table;
|
||||||
|
import com.activeandroid.query.Delete;
|
||||||
|
import com.activeandroid.query.From;
|
||||||
|
import com.activeandroid.query.Select;
|
||||||
|
import com.activeandroid.query.Update;
|
||||||
|
import com.activeandroid.util.SQLiteUtils;
|
||||||
|
|
||||||
|
@Table(name = "Habits")
|
||||||
|
public class Habit extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Fields *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
public static final int colors[] = { Color.parseColor("#900000"),
|
||||||
|
Color.parseColor("#c54100"), Color.parseColor("#c0ab00"),
|
||||||
|
Color.parseColor("#8db600"), Color.parseColor("#117209"),
|
||||||
|
Color.parseColor("#06965b"), Color.parseColor("#069a95"),
|
||||||
|
Color.parseColor("#114896"), Color.parseColor("#501394"),
|
||||||
|
Color.parseColor("#872086"), Color.parseColor("#c31764"),
|
||||||
|
Color.parseColor("#000000"), Color.parseColor("#aaaaaa") };
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
@Column(name = "description")
|
||||||
|
public String description;
|
||||||
|
|
||||||
|
@Column(name = "freq_num")
|
||||||
|
public Integer freq_num;
|
||||||
|
|
||||||
|
@Column(name = "freq_den")
|
||||||
|
public Integer freq_den;
|
||||||
|
|
||||||
|
@Column(name = "color")
|
||||||
|
public Integer color;
|
||||||
|
|
||||||
|
@Column(name = "position")
|
||||||
|
public Integer position;
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Commands *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
public static class CreateCommand extends Command
|
||||||
|
{
|
||||||
|
private Habit model;
|
||||||
|
private Long savedId;
|
||||||
|
|
||||||
|
public CreateCommand(Habit model)
|
||||||
|
{
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute()
|
||||||
|
{
|
||||||
|
Habit savedHabit = new Habit(model);
|
||||||
|
if(savedId == null)
|
||||||
|
{
|
||||||
|
savedHabit.save();
|
||||||
|
savedId = savedHabit.getId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
savedHabit.save(savedId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undo()
|
||||||
|
{
|
||||||
|
Habit.get(savedId).delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getExecuteStringId()
|
||||||
|
{
|
||||||
|
return R.string.toast_habit_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getUndoStringId()
|
||||||
|
{
|
||||||
|
return R.string.toast_habit_deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditCommand extends Command
|
||||||
|
{
|
||||||
|
private Habit original;
|
||||||
|
private Habit modified;
|
||||||
|
private long savedId;
|
||||||
|
private boolean hasIntervalChanged;
|
||||||
|
|
||||||
|
public EditCommand(Habit modified)
|
||||||
|
{
|
||||||
|
this.savedId = getId();
|
||||||
|
this.modified = new Habit(modified);
|
||||||
|
this.original = new Habit(Habit.this);
|
||||||
|
|
||||||
|
hasIntervalChanged = (this.original.freq_den != this.modified.freq_den
|
||||||
|
|| this.original.freq_num != this.modified.freq_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute()
|
||||||
|
{
|
||||||
|
Habit habit = Habit.get(savedId);
|
||||||
|
habit.copyAttributes(modified);
|
||||||
|
habit.save();
|
||||||
|
if(hasIntervalChanged)
|
||||||
|
habit.deleteScoresNewerThan(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void undo()
|
||||||
|
{
|
||||||
|
Habit habit = Habit.get(savedId);
|
||||||
|
habit.copyAttributes(original);
|
||||||
|
habit.save();
|
||||||
|
if(hasIntervalChanged)
|
||||||
|
habit.deleteScoresNewerThan(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getExecuteStringId()
|
||||||
|
{
|
||||||
|
return R.string.toast_habit_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUndoStringId()
|
||||||
|
{
|
||||||
|
return R.string.toast_habit_changed_back;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ToggleRepetitionCommand extends Command
|
||||||
|
{
|
||||||
|
private Long offset;
|
||||||
|
|
||||||
|
public ToggleRepetitionCommand(long offset)
|
||||||
|
{
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute()
|
||||||
|
{
|
||||||
|
toggleRepetition(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undo()
|
||||||
|
{
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Accessors *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
public Habit(Habit model)
|
||||||
|
{
|
||||||
|
copyAttributes(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyAttributes(Habit model)
|
||||||
|
{
|
||||||
|
this.name = model.name;
|
||||||
|
this.description = model.description;
|
||||||
|
this.freq_num = model.freq_num;
|
||||||
|
this.freq_den = model.freq_den;
|
||||||
|
this.color = model.color;
|
||||||
|
this.position = model.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Habit()
|
||||||
|
{
|
||||||
|
this.color = colors[11];
|
||||||
|
this.position = Habit.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Habit get(Long id)
|
||||||
|
{
|
||||||
|
return Habit.load(Habit.class, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(Long id)
|
||||||
|
{
|
||||||
|
save();
|
||||||
|
Habit.updateId(getId(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
public static void updateId(long oldId, long newId)
|
||||||
|
{
|
||||||
|
SQLiteUtils.execSql(String.format(
|
||||||
|
"update Habits set Id = %d where Id = %d", newId, oldId));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static From select()
|
||||||
|
{
|
||||||
|
return new Select().from(Habit.class).orderBy("position");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCount()
|
||||||
|
{
|
||||||
|
return select().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Habit getByPosition(int position)
|
||||||
|
{
|
||||||
|
return select().offset(position).executeSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Repetitions *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
protected From selectReps()
|
||||||
|
{
|
||||||
|
return new Select().from(Repetition.class).where("habit = ?", getId())
|
||||||
|
.orderBy("timestamp");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected From selectRepsFromTo(long timeFrom, long timeTo)
|
||||||
|
{
|
||||||
|
return selectReps().and("timestamp >= ?", timeFrom).and(
|
||||||
|
"timestamp <= ?", timeTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRep(long timestamp)
|
||||||
|
{
|
||||||
|
int count = selectReps().where("timestamp = ?", timestamp).count();
|
||||||
|
return (count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteReps(long timestamp)
|
||||||
|
{
|
||||||
|
new Delete().from(Repetition.class).where("habit = ?", getId())
|
||||||
|
.and("timestamp = ?", timestamp).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getReps(long timeFrom, long timeTo)
|
||||||
|
{
|
||||||
|
long timeFromExtended = timeFrom - freq_den * DateHelper.millisecondsInOneDay;
|
||||||
|
List<Repetition> reps = selectRepsFromTo(timeFromExtended, timeTo).execute();
|
||||||
|
|
||||||
|
int nDaysExtended = (int) ((timeTo - timeFromExtended) / DateHelper.millisecondsInOneDay);
|
||||||
|
int checkExtended[] = new int[nDaysExtended + 1];
|
||||||
|
|
||||||
|
int nDays = (int) ((timeTo - timeFrom) / DateHelper.millisecondsInOneDay);
|
||||||
|
|
||||||
|
// mark explicit checks
|
||||||
|
for (Repetition rep : reps)
|
||||||
|
{
|
||||||
|
int offset = (int) ((rep.timestamp - timeFrom) / DateHelper.millisecondsInOneDay);
|
||||||
|
checkExtended[nDays - offset] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// marks implicit checks
|
||||||
|
for(int i=0; i<nDays; i++)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
for(int j=0; j<freq_den; j++)
|
||||||
|
if(checkExtended[i+j] == 2) counter++;
|
||||||
|
|
||||||
|
if(counter >= freq_num)
|
||||||
|
checkExtended[i] = Math.max(checkExtended[i], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check[] = new int[nDays + 1];
|
||||||
|
for(int i=0; i<nDays+1; i++)
|
||||||
|
check[i] = checkExtended[i];
|
||||||
|
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Repetition getOldestRep()
|
||||||
|
{
|
||||||
|
return (Repetition) selectReps().limit(1).executeSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleRepetition(long timestamp)
|
||||||
|
{
|
||||||
|
if(hasRep(timestamp))
|
||||||
|
{
|
||||||
|
deleteReps(timestamp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Repetition rep = new Repetition();
|
||||||
|
rep.habit = this;
|
||||||
|
rep.timestamp = timestamp;
|
||||||
|
rep.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteScoresNewerThan(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Scoring *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
public Score getNewestScore()
|
||||||
|
{
|
||||||
|
return new Select().from(Score.class).where("habit = ?", getId())
|
||||||
|
.orderBy("timestamp desc").limit(1).executeSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteScoresNewerThan(long timestamp)
|
||||||
|
{
|
||||||
|
new Delete().from(Score.class).where("habit = ?", getId())
|
||||||
|
.and("timestamp >= ?", timestamp).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getScore()
|
||||||
|
{
|
||||||
|
int beginningScore;
|
||||||
|
long beginningTime;
|
||||||
|
|
||||||
|
long today = DateHelper.getStartOfDay(DateHelper.getLocalTime());
|
||||||
|
long day = DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
|
double freq = ((double) freq_num) / freq_den;
|
||||||
|
double multiplier = Math.pow(0.5, 1.0 / (14.0 / freq - 1));
|
||||||
|
|
||||||
|
Score newestScore = getNewestScore();
|
||||||
|
if(newestScore == null)
|
||||||
|
{
|
||||||
|
Repetition oldestRep = getOldestRep();
|
||||||
|
if(oldestRep == null)
|
||||||
|
return 0;
|
||||||
|
beginningTime = oldestRep.timestamp;
|
||||||
|
beginningScore = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
beginningTime = newestScore.timestamp + day;
|
||||||
|
beginningScore = newestScore.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nDays = (today - beginningTime) / day;
|
||||||
|
if(nDays < 0)
|
||||||
|
return newestScore.score;
|
||||||
|
|
||||||
|
int reps[] = getReps(beginningTime, today);
|
||||||
|
|
||||||
|
int lastScore = beginningScore;
|
||||||
|
for (int i = 0; i < reps.length; i++)
|
||||||
|
{
|
||||||
|
Score s = new Score();
|
||||||
|
s.habit = this;
|
||||||
|
s.timestamp = beginningTime + day * i;
|
||||||
|
s.score = (int) (lastScore * multiplier);
|
||||||
|
if(reps[reps.length-i-1] == 2) {
|
||||||
|
s.score += 1000000;
|
||||||
|
s.score = Math.min(s.score, 19259500);
|
||||||
|
}
|
||||||
|
s.save();
|
||||||
|
|
||||||
|
lastScore = s.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* Ordering *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
public static void reorder(int from, int to)
|
||||||
|
{
|
||||||
|
if(from == to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Habit h = Habit.getByPosition(from);
|
||||||
|
if(to < from)
|
||||||
|
new Update(Habit.class).set("position = position + 1")
|
||||||
|
.where("position >= ? and position < ?", to, from)
|
||||||
|
.execute();
|
||||||
|
else
|
||||||
|
new Update(Habit.class).set("position = position - 1")
|
||||||
|
.where("position > ? and position <= ?", from, to)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
h.position = to;
|
||||||
|
h.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void rebuildOrder()
|
||||||
|
{
|
||||||
|
List<Habit> habits = select().execute();
|
||||||
|
int i = 0;
|
||||||
|
for (Habit h : habits)
|
||||||
|
{
|
||||||
|
h.position = i++;
|
||||||
|
h.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void roundTimestamps()
|
||||||
|
{
|
||||||
|
List<Repetition> reps = new Select().from(Repetition.class).execute();
|
||||||
|
for (Repetition r : reps)
|
||||||
|
{
|
||||||
|
r.timestamp = DateHelper.getStartOfDay(r.timestamp);
|
||||||
|
r.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.isoron.uhabits.models;
|
||||||
|
|
||||||
|
import com.activeandroid.Model;
|
||||||
|
import com.activeandroid.annotation.Column;
|
||||||
|
import com.activeandroid.annotation.Table;
|
||||||
|
|
||||||
|
@Table(name = "Repetitions")
|
||||||
|
public class Repetition extends Model {
|
||||||
|
|
||||||
|
@Column(name = "habit")
|
||||||
|
public Habit habit;
|
||||||
|
|
||||||
|
@Column(name = "timestamp")
|
||||||
|
public Long timestamp;
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.isoron.uhabits.models;
|
||||||
|
|
||||||
|
import com.activeandroid.Model;
|
||||||
|
import com.activeandroid.annotation.Column;
|
||||||
|
import com.activeandroid.annotation.Table;
|
||||||
|
|
||||||
|
@Table(name = "Score")
|
||||||
|
public class Score extends Model
|
||||||
|
{
|
||||||
|
@Column(name = "habit")
|
||||||
|
public Habit habit;
|
||||||
|
|
||||||
|
@Column(name = "timestamp")
|
||||||
|
public Long timestamp;
|
||||||
|
|
||||||
|
@Column(name = "score")
|
||||||
|
public Integer score;
|
||||||
|
}
|