diff --git a/source/.classpath b/source/.classpath
new file mode 100644
index 0000000..7bc01d9
--- /dev/null
+++ b/source/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/source/.project b/source/.project
new file mode 100644
index 0000000..d85c35e
--- /dev/null
+++ b/source/.project
@@ -0,0 +1,33 @@
+
+
+ vpHerder
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/source/.settings/org.eclipse.jdt.core.prefs b/source/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..b080d2d
--- /dev/null
+++ b/source/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/source/AndroidManifest.xml b/source/AndroidManifest.xml
new file mode 100644
index 0000000..84404c7
--- /dev/null
+++ b/source/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/bin/AndroidManifest.xml b/source/bin/AndroidManifest.xml
new file mode 100644
index 0000000..84404c7
--- /dev/null
+++ b/source/bin/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/bin/classes/me/caesar2011/vpherder/BuildConfig.class b/source/bin/classes/me/caesar2011/vpherder/BuildConfig.class
new file mode 100644
index 0000000..38b3d87
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/BuildConfig.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/MainActivity$SectionFragment.class b/source/bin/classes/me/caesar2011/vpherder/MainActivity$SectionFragment.class
new file mode 100644
index 0000000..ad98034
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/MainActivity$SectionFragment.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/MainActivity$SectionsPagerAdapter.class b/source/bin/classes/me/caesar2011/vpherder/MainActivity$SectionsPagerAdapter.class
new file mode 100644
index 0000000..d652266
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/MainActivity$SectionsPagerAdapter.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/MainActivity.class b/source/bin/classes/me/caesar2011/vpherder/MainActivity.class
new file mode 100644
index 0000000..a5c058c
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/MainActivity.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$attr.class b/source/bin/classes/me/caesar2011/vpherder/R$attr.class
new file mode 100644
index 0000000..b2adfa9
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$attr.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$color.class b/source/bin/classes/me/caesar2011/vpherder/R$color.class
new file mode 100644
index 0000000..8cf3ee9
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$color.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$dimen.class b/source/bin/classes/me/caesar2011/vpherder/R$dimen.class
new file mode 100644
index 0000000..1522d03
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$dimen.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$drawable.class b/source/bin/classes/me/caesar2011/vpherder/R$drawable.class
new file mode 100644
index 0000000..b380481
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$drawable.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$id.class b/source/bin/classes/me/caesar2011/vpherder/R$id.class
new file mode 100644
index 0000000..9707764
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$id.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$layout.class b/source/bin/classes/me/caesar2011/vpherder/R$layout.class
new file mode 100644
index 0000000..1dbd815
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$layout.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$menu.class b/source/bin/classes/me/caesar2011/vpherder/R$menu.class
new file mode 100644
index 0000000..e99514f
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$menu.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$string.class b/source/bin/classes/me/caesar2011/vpherder/R$string.class
new file mode 100644
index 0000000..455fa8d
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$string.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R$style.class b/source/bin/classes/me/caesar2011/vpherder/R$style.class
new file mode 100644
index 0000000..890bad9
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R$style.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/R.class b/source/bin/classes/me/caesar2011/vpherder/R.class
new file mode 100644
index 0000000..f2e1078
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/R.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$AnnounceType.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$AnnounceType.class
new file mode 100644
index 0000000..c2cc01f
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$AnnounceType.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolder.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolder.class
new file mode 100644
index 0000000..011ece9
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolder.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolderALTERATION.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolderALTERATION.class
new file mode 100644
index 0000000..c55d2a0
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolderALTERATION.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolderREMARK.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolderREMARK.class
new file mode 100644
index 0000000..bac51f9
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter$ViewHolderREMARK.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter.class
new file mode 100644
index 0000000..7f1ccec
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSAdapter.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSCreate$DownloadFilesTask.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSCreate$DownloadFilesTask.class
new file mode 100644
index 0000000..c55a678
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSCreate$DownloadFilesTask.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSCreate.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSCreate.class
new file mode 100644
index 0000000..ba75662
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSCreate.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncement.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncement.class
new file mode 100644
index 0000000..af92f9d
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncement.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementAlteration.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementAlteration.class
new file mode 100644
index 0000000..a98c5e8
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementAlteration.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementRemark.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementRemark.class
new file mode 100644
index 0000000..b22f49d
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementRemark.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonChange.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonChange.class
new file mode 100644
index 0000000..beca991
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonChange.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonObject.class b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonObject.class
new file mode 100644
index 0000000..d2f0698
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/teachersubstitution/TSjsonObject.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView$HeaderViewHolder.class b/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView$HeaderViewHolder.class
new file mode 100644
index 0000000..9b1f94b
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView$HeaderViewHolder.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView$RefreshState.class b/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView$RefreshState.class
new file mode 100644
index 0000000..8ac71e6
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView$RefreshState.class differ
diff --git a/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView.class b/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView.class
new file mode 100644
index 0000000..15c7693
Binary files /dev/null and b/source/bin/classes/me/caesar2011/vpherder/views/PullToRefreshListView.class differ
diff --git a/source/gen/me/caesar2011/vpherder/BuildConfig.java b/source/gen/me/caesar2011/vpherder/BuildConfig.java
new file mode 100644
index 0000000..b223a62
--- /dev/null
+++ b/source/gen/me/caesar2011/vpherder/BuildConfig.java
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package me.caesar2011.vpherder;
+
+public final class BuildConfig {
+ public final static boolean DEBUG = true;
+}
\ No newline at end of file
diff --git a/source/gen/me/caesar2011/vpherder/R.java b/source/gen/me/caesar2011/vpherder/R.java
new file mode 100644
index 0000000..ec89cac
--- /dev/null
+++ b/source/gen/me/caesar2011/vpherder/R.java
@@ -0,0 +1,105 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package me.caesar2011.vpherder;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class color {
+ public static final int block=0x7f040002;
+ public static final int fragment_background=0x7f040003;
+ public static final int subject=0x7f040000;
+ public static final int teacher=0x7f040001;
+ }
+ public static final class dimen {
+ /** Default screen margins, per the Android Design guidelines.
+
+ Customize dimensions originally defined in res/values/dimens.xml (such as
+ screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
+
+ */
+ public static final int activity_horizontal_margin=0x7f050000;
+ public static final int activity_vertical_margin=0x7f050001;
+ }
+ public static final class drawable {
+ public static final int ic_launcher=0x7f020000;
+ }
+ public static final class id {
+ public static final int action_settings=0x7f09000f;
+ public static final int box_subject=0x7f090008;
+ public static final int changes=0x7f090007;
+ public static final int listview=0x7f090003;
+ public static final int main=0x7f090005;
+ public static final int pager=0x7f090000;
+ public static final int pager_title_strip=0x7f090001;
+ public static final int remark=0x7f09000e;
+ public static final int section_label=0x7f090002;
+ public static final int subject=0x7f090009;
+ public static final int subject_subinfo=0x7f09000a;
+ public static final int teacher=0x7f090006;
+ public static final int text=0x7f090004;
+ public static final int textview_from=0x7f09000b;
+ public static final int textview_to=0x7f09000d;
+ public static final int to_arrow=0x7f09000c;
+ }
+ public static final class layout {
+ public static final int activity_main=0x7f030000;
+ public static final int fragment_main_dummy=0x7f030001;
+ public static final int fragment_teacher_substitution=0x7f030002;
+ public static final int pull_to_refresh_header=0x7f030003;
+ public static final int teacher_substitution_change=0x7f030004;
+ public static final int teacher_substitution_row_alteration=0x7f030005;
+ public static final int teacher_substitution_row_remark=0x7f030006;
+ }
+ public static final class menu {
+ public static final int main=0x7f080000;
+ }
+ public static final class string {
+ public static final int action_settings=0x7f060007;
+ public static final int app_name=0x7f060004;
+ public static final int pull_to_refresh_aborting_label=0x7f060003;
+ public static final int pull_to_refresh_pull_label=0x7f060000;
+ public static final int pull_to_refresh_refreshing_label=0x7f060002;
+ public static final int pull_to_refresh_release_label=0x7f060001;
+ public static final int title_section1=0x7f060005;
+ public static final int title_section2=0x7f060006;
+ public static final int to_arrow=0x7f060008;
+ }
+ public static final class style {
+ /**
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+
+
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+
+
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+
+ API 11 theme customizations can go here.
+
+ 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.
+
+ API 14 theme customizations can go here.
+ */
+ public static final int AppBaseTheme=0x7f070000;
+ /** Application theme.
+ All customizations that are NOT specific to a particular API-level can go here.
+ */
+ public static final int AppTheme=0x7f070005;
+ public static final int TextSize_Large=0x7f070002;
+ public static final int TextSize_Medium=0x7f070003;
+ public static final int TextSize_Small=0x7f070004;
+ public static final int TextSize_VeryLarge=0x7f070001;
+ }
+}
diff --git a/source/ic_launcher-web.png b/source/ic_launcher-web.png
new file mode 100644
index 0000000..e8519c6
Binary files /dev/null and b/source/ic_launcher-web.png differ
diff --git a/source/libs/android-support-v4.jar b/source/libs/android-support-v4.jar
new file mode 100644
index 0000000..9056828
Binary files /dev/null and b/source/libs/android-support-v4.jar differ
diff --git a/source/libs/commons-io-2.4.jar b/source/libs/commons-io-2.4.jar
new file mode 100644
index 0000000..90035a4
Binary files /dev/null and b/source/libs/commons-io-2.4.jar differ
diff --git a/source/proguard-project.txt b/source/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/source/proguard-project.txt
@@ -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 *;
+#}
diff --git a/source/project.properties b/source/project.properties
new file mode 100644
index 0000000..4ab1256
--- /dev/null
+++ b/source/project.properties
@@ -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-19
diff --git a/source/raw/images/pull_arrow.xcf b/source/raw/images/pull_arrow.xcf
new file mode 100644
index 0000000..e7345d8
Binary files /dev/null and b/source/raw/images/pull_arrow.xcf differ
diff --git a/source/res/drawable-hdpi/ic_launcher.png b/source/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..bffed76
Binary files /dev/null and b/source/res/drawable-hdpi/ic_launcher.png differ
diff --git a/source/res/drawable-mdpi/ic_launcher.png b/source/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..08eeec7
Binary files /dev/null and b/source/res/drawable-mdpi/ic_launcher.png differ
diff --git a/source/res/drawable-xhdpi/ic_launcher.png b/source/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..b147441
Binary files /dev/null and b/source/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/source/res/drawable-xxhdpi/ic_launcher.png b/source/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..19df53e
Binary files /dev/null and b/source/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/source/res/layout/activity_main.xml b/source/res/layout/activity_main.xml
new file mode 100644
index 0000000..65125b6
--- /dev/null
+++ b/source/res/layout/activity_main.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
diff --git a/source/res/layout/fragment_main_dummy.xml b/source/res/layout/fragment_main_dummy.xml
new file mode 100644
index 0000000..668926b
--- /dev/null
+++ b/source/res/layout/fragment_main_dummy.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/source/res/layout/fragment_teacher_substitution.xml b/source/res/layout/fragment_teacher_substitution.xml
new file mode 100644
index 0000000..2db47be
--- /dev/null
+++ b/source/res/layout/fragment_teacher_substitution.xml
@@ -0,0 +1,7 @@
+
+
diff --git a/source/res/layout/pull_to_refresh_header.xml b/source/res/layout/pull_to_refresh_header.xml
new file mode 100644
index 0000000..e6eee66
--- /dev/null
+++ b/source/res/layout/pull_to_refresh_header.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/res/layout/teacher_substitution_change.xml b/source/res/layout/teacher_substitution_change.xml
new file mode 100644
index 0000000..902a282
--- /dev/null
+++ b/source/res/layout/teacher_substitution_change.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/source/res/layout/teacher_substitution_row_alteration.xml b/source/res/layout/teacher_substitution_row_alteration.xml
new file mode 100644
index 0000000..5191c44
--- /dev/null
+++ b/source/res/layout/teacher_substitution_row_alteration.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/res/layout/teacher_substitution_row_remark.xml b/source/res/layout/teacher_substitution_row_remark.xml
new file mode 100644
index 0000000..36d1263
--- /dev/null
+++ b/source/res/layout/teacher_substitution_row_remark.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/source/res/menu/main.xml b/source/res/menu/main.xml
new file mode 100644
index 0000000..c002028
--- /dev/null
+++ b/source/res/menu/main.xml
@@ -0,0 +1,9 @@
+
diff --git a/source/res/values-sw600dp/dimens.xml b/source/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..44f01db
--- /dev/null
+++ b/source/res/values-sw600dp/dimens.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/source/res/values-sw720dp-land/dimens.xml b/source/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..61e3fa8
--- /dev/null
+++ b/source/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,9 @@
+
+
+
+ 128dp
+
+
diff --git a/source/res/values-v11/styles.xml b/source/res/values-v11/styles.xml
new file mode 100644
index 0000000..3c02242
--- /dev/null
+++ b/source/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/source/res/values-v14/styles.xml b/source/res/values-v14/styles.xml
new file mode 100644
index 0000000..a91fd03
--- /dev/null
+++ b/source/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/source/res/values/colors.xml b/source/res/values/colors.xml
new file mode 100644
index 0000000..2cb856e
--- /dev/null
+++ b/source/res/values/colors.xml
@@ -0,0 +1,7 @@
+
+
+ #d34937
+ #000
+ #888
+ #fff
+
diff --git a/source/res/values/dimens.xml b/source/res/values/dimens.xml
new file mode 100644
index 0000000..55c1e59
--- /dev/null
+++ b/source/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+
+ 16dp
+ 16dp
+
+
diff --git a/source/res/values/pull_to_refresh_strings.xml b/source/res/values/pull_to_refresh_strings.xml
new file mode 100644
index 0000000..783afb9
--- /dev/null
+++ b/source/res/values/pull_to_refresh_strings.xml
@@ -0,0 +1,7 @@
+
+
+ Ziehen zum Aktualisieren…
+ Loslassen zum Aktualisieren…
+ Aktualisieren…
+ Aktualisieren abbrechen…
+
diff --git a/source/res/values/strings.xml b/source/res/values/strings.xml
new file mode 100644
index 0000000..b4a4815
--- /dev/null
+++ b/source/res/values/strings.xml
@@ -0,0 +1,9 @@
+
+
+ vpHerder
+ Heute
+ Einstellungen
+ Menü
+
+ ▶
+
diff --git a/source/res/values/styles.xml b/source/res/values/styles.xml
new file mode 100644
index 0000000..4af71c4
--- /dev/null
+++ b/source/res/values/styles.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/src/me/caesar2011/vpherder/MainActivity.java b/source/src/me/caesar2011/vpherder/MainActivity.java
new file mode 100644
index 0000000..f2fbc6a
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/MainActivity.java
@@ -0,0 +1,125 @@
+package me.caesar2011.vpherder;
+
+import java.util.Locale;
+
+import me.caesar2011.vpherder.teachersubstitution.TSCreate;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class MainActivity extends FragmentActivity {
+
+ /**
+ * The {@link android.support.v4.view.PagerAdapter} that will provide
+ * fragments for each of the sections. We use a
+ * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
+ * will keep every loaded fragment in memory. If this becomes too memory
+ * intensive, it may be best to switch to a
+ * {@link android.support.v4.app.FragmentStatePagerAdapter}.
+ */
+ SectionsPagerAdapter mSectionsPagerAdapter;
+
+ /**
+ * The {@link ViewPager} that will host the section contents.
+ */
+ ViewPager mViewPager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // TSCreate the adapter that will return a fragment for each of the three
+ // primary sections of the app.
+ mSectionsPagerAdapter = new SectionsPagerAdapter(
+ getSupportFragmentManager());
+
+ // Set up the ViewPager with the sections adapter.
+ mViewPager = (ViewPager) findViewById(R.id.pager);
+ mViewPager.setAdapter(mSectionsPagerAdapter);
+
+ }
+
+ /**
+ * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
+ * one of the sections/tabs/pages.
+ */
+ public class SectionsPagerAdapter extends FragmentPagerAdapter {
+
+ public SectionsPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ // getItem is called to instantiate the fragment for the given page.
+ // Return a SectionFragment (defined as a static inner class
+ // below) with the page number as its lone argument.
+ Fragment fragment = new SectionFragment();
+ Bundle args = new Bundle();
+ args.putInt(SectionFragment.ARG_SECTION_NUMBER, position + 1);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public int getCount() {
+ // Show 2 total pages.
+ return 2;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ Locale l = Locale.getDefault();
+ switch (position) {
+ case 0:
+ return getString(R.string.title_section1).toUpperCase(l); // teacher substitution today
+ case 1:
+ return getString(R.string.title_section2).toUpperCase(l); //settings
+ }
+ return null;
+ }
+ }
+
+ /**
+ * A dummy fragment representing a section of the app, but that simply
+ * displays dummy text.
+ */
+ public static class SectionFragment extends Fragment {
+ /**
+ * The fragment argument representing the section number for this
+ * fragment.
+ */
+ public static final String ARG_SECTION_NUMBER = "section_number";
+
+ public SectionFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ int page = getArguments().getInt(ARG_SECTION_NUMBER);
+ if (page == 1) {
+ return (new TSCreate(getActivity(), inflater, container)).Draw();
+ }
+
+ // TODO delete this code
+ View rootView = inflater.inflate(R.layout.fragment_main_dummy,
+ container, false);
+ TextView dummyTextView = (TextView) rootView
+ .findViewById(R.id.section_label);
+ dummyTextView.setText(Integer.toString(getArguments().getInt(
+ ARG_SECTION_NUMBER)));
+ return rootView;
+ }
+ }
+
+}
diff --git a/source/src/me/caesar2011/vpherder/teachersubstitution/TSAdapter.java b/source/src/me/caesar2011/vpherder/teachersubstitution/TSAdapter.java
new file mode 100644
index 0000000..128f258
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/teachersubstitution/TSAdapter.java
@@ -0,0 +1,107 @@
+/**
+ *
+ */
+package me.caesar2011.vpherder.teachersubstitution;
+
+import java.util.ArrayList;
+
+import me.caesar2011.vpherder.R;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+/**
+ * @author BastiLapTop
+ *
+ */
+public class TSAdapter extends ArrayAdapter {
+
+ private ArrayList mData = new ArrayList();
+ private final LayoutInflater mInflater;
+
+ public TSAdapter(Context context, int textViewResourceId,
+ ArrayList objects) {
+ super(context, textViewResourceId, objects);
+ mData = objects;
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public int getCount() {
+ return mData.size();
+ }
+
+ @Override
+ public TSjsonAnnouncement getItem(int position) {
+ return mData.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ // TODO Optimize
+ if (mData.get(position) instanceof TSjsonAnnouncementRemark) {
+ return AnnounceType.REMARK;
+ } else {
+ return AnnounceType.ALTERATION;
+ }
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return AnnounceType.count;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder = null;
+ int type = getItemViewType(position);
+ if (convertView == null) {
+ switch (type) {
+ case AnnounceType.REMARK:
+ convertView = mInflater.inflate(R.layout.teacher_substitution_row_remark, null);
+ break;
+ case AnnounceType.ALTERATION:
+ convertView = mInflater.inflate(R.layout.teacher_substitution_row_alteration, null);
+ break;
+ }
+ holder = mData.get(position).createHolder(convertView);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+ // (Re-)fill view with new data
+ mData.get(position).refillView(holder);
+ return convertView;
+ }
+
+
+ // SUB CLASSES
+
+ static class AnnounceType {
+ public static final int REMARK = 0;
+ public static final int ALTERATION = 1;
+ public static final int count = 2;
+ }
+
+ public static class ViewHolder {}
+
+ public static class ViewHolderREMARK extends ViewHolder {
+ public TextView text;
+ }
+
+ public static class ViewHolderALTERATION extends ViewHolder {
+ public TextView teacher;
+ public TextView subject;
+ public TextView subject_subinfo;
+ public TextView changes_from;
+ public TextView changes_to;
+ public TextView remark;
+ }
+}
diff --git a/source/src/me/caesar2011/vpherder/teachersubstitution/TSCreate.java b/source/src/me/caesar2011/vpherder/teachersubstitution/TSCreate.java
new file mode 100644
index 0000000..d1e9a8f
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/teachersubstitution/TSCreate.java
@@ -0,0 +1,118 @@
+/**
+ *
+ */
+package me.caesar2011.vpherder.teachersubstitution;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.concurrent.ExecutionException;
+
+import me.caesar2011.vpherder.R;
+
+import org.apache.commons.io.IOUtils;
+import org.json.JSONException;
+
+import android.app.Activity;
+import android.os.AsyncTask;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+/**
+ * Class to organize the drawings of the teacher substition.
+ *
+ * @author BastiLapTop
+ *
+ */
+public class TSCreate {
+
+ private final Activity activity;
+ private final LayoutInflater inflater;
+ private final ViewGroup container;
+ private static TSjsonObject JsonObject;
+
+ /**
+ * Constructor
+ */
+ public TSCreate(Activity activity, LayoutInflater inflater, ViewGroup container) {
+ this.activity = activity;
+ this.inflater = inflater;
+ this.container = container;
+
+ if(JsonObject == null){
+ try {
+ URL url = new URL("https://vpherder.canis.uberspace.de/example.json");
+
+ DownloadFilesTask downloadSubstitutions = new DownloadFilesTask();
+ downloadSubstitutions.execute(url);
+ downloadSubstitutions.get();
+ String theString = downloadSubstitutions.getOutput()[0];
+
+ JsonObject = new TSjsonObject(theString);
+ } catch (ExecutionException e) {
+ System.out.println("ERRRRRRRRRRRRRRRRRRRRROR ExecutionException!");
+ } catch (InterruptedException e) {
+ System.out.println("ERRRRRRRRRRRRRRRRRRRRROR InterruptedException!");
+ } catch (JSONException e) {
+ System.out.println("ERRRRRRRRRRRRRRRRRRRRROR JSONException!");
+ } catch (MalformedURLException e) {
+ System.out.println("ERRRRRRRRRRRRRRRRRRRRROR MalformedURLException!");
+ }
+ }
+ }
+
+ public View Draw() {
+ View rootView = inflater.inflate(R.layout.fragment_teacher_substitution,
+ container, false);
+
+ final ListView listview = (ListView) rootView.findViewById(R.id.listview);
+
+ final TSAdapter adapter = new TSAdapter(activity,
+ R.layout.teacher_substitution_row_remark, JsonObject.announcements);
+ listview.setAdapter(adapter);
+
+ return rootView;
+ }
+
+
+
+ private class DownloadFilesTask extends AsyncTask {
+ private String[] outputFiles;
+
+ protected String[] doInBackground(URL... urls) {
+ int count = urls.length;
+ String[] files = new String[count];
+ for (int i = 0; i < count; i++) {
+ URLConnection connection;
+ try {
+ connection = urls[i].openConnection();
+ InputStream inputStream = connection.getInputStream();
+ publishProgress((int) ((i / (float) count) * 100));
+
+ StringWriter writer = new StringWriter();
+ IOUtils.copy(inputStream, writer, "UTF-8");
+ files[i] = writer.toString();
+ } catch (IOException e) {
+ }
+
+ // Escape early if cancel() is called
+ if (isCancelled()) break;
+ }
+ outputFiles = files;
+ return files;
+ }
+
+ protected void onProgressUpdate(Integer... progress) {
+ //setProgressPercent(progress[0]);
+ }
+
+ protected String[] getOutput() {
+ return outputFiles;
+ }
+ }
+}
diff --git a/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncement.java b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncement.java
new file mode 100644
index 0000000..4ab1953
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncement.java
@@ -0,0 +1,31 @@
+package me.caesar2011.vpherder.teachersubstitution;
+
+import me.caesar2011.vpherder.teachersubstitution.TSAdapter.ViewHolder;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.view.View;
+
+public class TSjsonAnnouncement {
+
+ public final String type;
+
+ /**
+ * @param jsonObject
+ * @throws JSONException
+ */
+ public TSjsonAnnouncement(JSONObject jsonObject) throws JSONException {
+ // TODO Auto-generated constructor stub
+ this.type = jsonObject.getString("type");
+ }
+
+ public void refillView(ViewHolder holder) {
+
+ }
+
+ public ViewHolder createHolder(View convertView) {
+ return null;
+ }
+
+}
diff --git a/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementAlteration.java b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementAlteration.java
new file mode 100644
index 0000000..145b538
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementAlteration.java
@@ -0,0 +1,104 @@
+/**
+ *
+ */
+package me.caesar2011.vpherder.teachersubstitution;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import me.caesar2011.vpherder.R;
+import me.caesar2011.vpherder.teachersubstitution.TSAdapter.ViewHolder;
+import me.caesar2011.vpherder.teachersubstitution.TSAdapter.ViewHolderALTERATION;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * @author BastiLapTop
+ *
+ */
+public class TSjsonAnnouncementAlteration extends TSjsonAnnouncement {
+
+ public final int time;
+ public final String form;
+ public final String teacher;
+ public final String subject;
+ public final boolean cancelled;
+ public final ArrayList changes;
+ public final String remark;
+
+ /**
+ * @param jsonObject
+ * @throws JSONException
+ */
+ public TSjsonAnnouncementAlteration(JSONObject jsonObject)
+ throws JSONException {
+ super(jsonObject);
+ this.time = jsonObject.getInt("time");
+ this.form = jsonObject.getString("form");
+ this.teacher = jsonObject.getString("teacher");
+ this.subject = jsonObject.getString("class");
+ this.cancelled = jsonObject.getBoolean("cancelled");
+
+ this.changes = new ArrayList();
+ JSONObject jObject = jsonObject.getJSONObject("changes");
+ Iterator> i = jObject.keys();
+
+ while(i.hasNext()){
+ String key = (String)i.next();
+ if(jObject.get(key) instanceof JSONObject){
+ jObject.getJSONObject(key);
+ TSjsonChange jChanges = new TSjsonChange(key,
+ jObject.getJSONObject(key).getString("old"),
+ jObject.getJSONObject(key).getString("new"));
+ this.changes.add(jChanges);
+ }
+ }
+ this.remark = jsonObject.optString("remark");
+ }
+
+ @Override
+ public void refillView(ViewHolder holder) {
+ ViewHolderALTERATION holdAlteration = (ViewHolderALTERATION) holder;
+ holdAlteration.teacher.setText(teacher);
+ holdAlteration.subject.setText(subject);
+ holdAlteration.subject_subinfo.setText(time + " - " + form);
+
+ String sFrom = "";
+ String sTo = "";
+ Iterator i = changes.iterator();
+ while (i.hasNext()) {
+ TSjsonChange jChange = i.next();
+ if (!sFrom.equals("")) {
+ sFrom += "\n";
+ sTo += "\n";
+ }
+ sFrom += jChange.oldValue;
+ sTo += jChange.newValue;
+ }
+ holdAlteration.changes_from.setText(sFrom);
+ holdAlteration.changes_to.setText(sTo);
+
+ if (remark.equals("false")) {
+ holdAlteration.remark.setVisibility(View.GONE);
+ } else {
+ holdAlteration.remark.setText(remark);
+ }
+ }
+
+ @Override
+ public ViewHolder createHolder(View convertView) {
+ ViewHolderALTERATION holder = new ViewHolderALTERATION();
+ holder.teacher = (TextView)convertView.findViewById(R.id.teacher);
+ holder.subject = (TextView)convertView.findViewById(R.id.subject);
+ holder.subject_subinfo = (TextView)convertView.findViewById(R.id.subject_subinfo);
+ holder.changes_from = (TextView)convertView.findViewById(R.id.textview_from);
+ holder.changes_to = (TextView)convertView.findViewById(R.id.textview_to);
+ holder.remark = (TextView)convertView.findViewById(R.id.remark);
+ return holder;
+ }
+
+}
diff --git a/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementRemark.java b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementRemark.java
new file mode 100644
index 0000000..d4f64fa
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonAnnouncementRemark.java
@@ -0,0 +1,46 @@
+/**
+ *
+ */
+package me.caesar2011.vpherder.teachersubstitution;
+
+import me.caesar2011.vpherder.R;
+import me.caesar2011.vpherder.teachersubstitution.TSAdapter.ViewHolder;
+import me.caesar2011.vpherder.teachersubstitution.TSAdapter.ViewHolderREMARK;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * @author BastiLapTop
+ *
+ */
+public class TSjsonAnnouncementRemark extends TSjsonAnnouncement {
+
+ public final String text;
+
+ /**
+ * @param jsonObject
+ * @throws JSONException
+ */
+ public TSjsonAnnouncementRemark(JSONObject jsonObject) throws JSONException {
+ super(jsonObject);
+ this.text = jsonObject.optString("text");
+ }
+
+ @Override
+ public void refillView(ViewHolder holder) {
+ ViewHolderREMARK holdRemark = (ViewHolderREMARK) holder;
+ holdRemark.text.setText(text);
+ }
+
+ @Override
+ public ViewHolder createHolder(View convertView) {
+ ViewHolderREMARK holder = new ViewHolderREMARK();
+ holder.text = (TextView)convertView.findViewById(R.id.text);
+ return holder;
+ }
+
+}
diff --git a/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonChange.java b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonChange.java
new file mode 100644
index 0000000..859cbbf
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonChange.java
@@ -0,0 +1,27 @@
+/**
+ *
+ */
+package me.caesar2011.vpherder.teachersubstitution;
+
+
+/**
+ * @author BastiLapTop
+ *
+ */
+public class TSjsonChange {
+
+ public final String name;
+ public final String oldValue;
+ public final String newValue;
+
+ /**
+ *
+ */
+ public TSjsonChange(String name, String oldValue, String newValue) {
+ // TODO Auto-generated constructor stub
+ this.name = name;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+}
diff --git a/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonObject.java b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonObject.java
new file mode 100644
index 0000000..e1c0b0d
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/teachersubstitution/TSjsonObject.java
@@ -0,0 +1,77 @@
+/**
+ *
+ */
+package me.caesar2011.vpherder.teachersubstitution;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Locale;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * The hole json object witch handles version, date, creation/modified time, etc. ...
+ * And it holds a list of all announcements.
+ *
+ * @author BastiLapTop
+ *
+ */
+public class TSjsonObject {
+
+ public final String version;
+ public final Date date;
+ public final Date created;
+ public final Date modified;
+ public final ArrayList announcements;
+
+
+ /**
+ * @param jsonObject
+ * @throws JSONException
+ */
+ public TSjsonObject(JSONObject jsonObject) throws JSONException {
+ // TODO Auto-generated constructor stub
+ this.version = jsonObject.getString("version");
+
+ try {
+ this.date = new SimpleDateFormat("yyyy-MM-dd", Locale.GERMANY).parse(jsonObject.getString("date"));
+ } catch (ParseException e) {
+ throw new JSONException("Date could not be converted. ParseExeption.");
+ }
+
+ try {
+ this.created = new Date(Long.parseLong(jsonObject.getString("created")) * 1000);
+ } catch (NumberFormatException e) {
+ throw new JSONException("Created could not be converted. NumberFormatException.");
+ }
+
+ try {
+ this.modified = new Date(Long.parseLong(jsonObject.getString("modified")) * 1000);
+ } catch (NumberFormatException e) {
+ throw new JSONException("Modified could not be converted. NumberFormatException.");
+ }
+
+ JSONArray jArray = jsonObject.getJSONArray("announcements");
+ JSONObject jObject = null;
+ this.announcements = new ArrayList();
+ for (int i = 0; i < jArray.length(); i++) {
+ jObject = jArray.getJSONObject(i);
+ if (jObject.getString("type").equals("alteration")) {
+ this.announcements.add(new TSjsonAnnouncementAlteration(jObject));
+ } else {
+ this.announcements.add(new TSjsonAnnouncementRemark(jObject));
+ }
+ }
+ }
+
+ public TSjsonObject(String jsonString) throws JSONException {
+ this(new JSONObject(jsonString));
+ }
+
+
+
+}
diff --git a/source/src/me/caesar2011/vpherder/views/PullToRefreshListView.java b/source/src/me/caesar2011/vpherder/views/PullToRefreshListView.java
new file mode 100644
index 0000000..28a5298
--- /dev/null
+++ b/source/src/me/caesar2011/vpherder/views/PullToRefreshListView.java
@@ -0,0 +1,165 @@
+package me.caesar2011.vpherder.views;
+
+import me.caesar2011.vpherder.R;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class PullToRefreshListView extends ListView implements OnScrollListener {
+
+ private float mStartX;
+ private float mStartY;
+ private int mRefreshState;
+ private LayoutInflater mInflater;
+ private View mHeaderView;
+ private HeaderViewHolder mHeaderViewHolder;
+ private int mLastTopVisiblePos;
+
+ private static final int PULL_DOWN_LIMIT = (int) Math.round(0.75 * DisplayMetrics.DENSITY_DEFAULT);
+
+ public PullToRefreshListView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public PullToRefreshListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public PullToRefreshListView(Context context, AttributeSet attrs,
+ int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ public void init(Context context) {
+ super.setOnScrollListener(this);
+
+ mInflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mHeaderView = mInflater.inflate(R.layout.pull_to_refresh_header, null);
+ mHeaderViewHolder = new HeaderViewHolder(mHeaderView);
+ addHeaderView(mHeaderView);
+
+ mRefreshState = RefreshState.PULL_TO_REFRESH;
+ }
+
+ @Override
+ public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onScrollStateChanged(AbsListView arg0, int arg1) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean isHandled = false;
+
+ if (event.getAction() == MotionEvent.ACTION_DOWN || mLastTopVisiblePos == 1) {
+ int refreshBoxHeight = (int) ((mRefreshState == RefreshState.REFRESHING)?PULL_DOWN_LIMIT+15:1);
+ mStartX = event.getRawX();
+ mStartY = event.getRawY()-refreshBoxHeight;
+ mHeaderViewHolder.setVisibility(View.VISIBLE);
+ mHeaderView.setLayoutParams(new LayoutParams(mHeaderView.getLayoutParams().width, refreshBoxHeight));
+ }
+ if (event.getRawY()-mStartY > Math.abs(event.getRawX()-mStartX) && getFirstVisiblePosition() == 0) {
+ int stretch = (int) Math.max(0, event.getRawY()-mStartY);
+ System.out.println(event.getRawY()-mStartY);
+ System.out.println(Math.abs(event.getRawX()-mStartX));
+ System.out.println("--");
+ mHeaderView.setLayoutParams(new LayoutParams(mHeaderView.getLayoutParams().width, stretch));
+ if (mRefreshState == RefreshState.PULL_TO_REFRESH && stretch > PULL_DOWN_LIMIT) {
+ mRefreshState = RefreshState.RELEASE_TO_REFRESH;
+ mHeaderViewHolder.setRefreshingState(mRefreshState);
+ } else if (mRefreshState == RefreshState.RELEASE_TO_REFRESH && stretch <= PULL_DOWN_LIMIT) {
+ mRefreshState = RefreshState.PULL_TO_REFRESH;
+ mHeaderViewHolder.setRefreshingState(mRefreshState);
+ } else if (mRefreshState == RefreshState.ABORTING && stretch > PULL_DOWN_LIMIT) {
+ mRefreshState = RefreshState.RELEASE_TO_REFRESH;
+ mHeaderViewHolder.setRefreshingState(mRefreshState);
+ } else if (mRefreshState == RefreshState.REFRESHING && stretch <= PULL_DOWN_LIMIT) {
+ mRefreshState = RefreshState.ABORTING;
+ mHeaderViewHolder.setRefreshingState(mRefreshState);
+ }
+ isHandled = true;
+ }
+
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ isHandled = false;
+ switch (mRefreshState) {
+ case RefreshState.PULL_TO_REFRESH:
+ mHeaderViewHolder.setVisibility(View.GONE);
+ mHeaderView.setLayoutParams(new LayoutParams(mHeaderView.getLayoutParams().width, 0));
+ break;
+ case RefreshState.RELEASE_TO_REFRESH:
+ mHeaderViewHolder.setVisibility(View.VISIBLE);
+ mRefreshState = RefreshState.REFRESHING;
+ mHeaderViewHolder.setRefreshingState(mRefreshState);
+ mHeaderView.setLayoutParams(new LayoutParams(mHeaderView.getLayoutParams().width, PULL_DOWN_LIMIT));
+ break;
+ case RefreshState.REFRESHING:
+ mHeaderView.setLayoutParams(new LayoutParams(mHeaderView.getLayoutParams().width, PULL_DOWN_LIMIT));
+ break;
+ case RefreshState.ABORTING:
+ mHeaderViewHolder.setVisibility(View.GONE);
+ mRefreshState = RefreshState.PULL_TO_REFRESH;
+ mHeaderViewHolder.setRefreshingState(mRefreshState);
+ mHeaderView.setLayoutParams(new LayoutParams(mHeaderView.getLayoutParams().width, 0));
+ break;
+ }
+ }
+ mLastTopVisiblePos = getFirstVisiblePosition();
+ return isHandled?true:super.onTouchEvent(event);
+ }
+
+ private class HeaderViewHolder {
+ public final View mParent;
+ public final TextView mText;
+
+ public HeaderViewHolder(View HeaderView) {
+ mParent = HeaderView;
+ mText = (TextView) HeaderView.findViewById(R.id.text);
+ }
+
+ public void setVisibility(int visibility) {
+ mParent.setVisibility(visibility);
+ mText.setVisibility(visibility);
+ }
+
+ public void setRefreshingState(int refreshState) {
+ switch (refreshState){
+ case RefreshState.PULL_TO_REFRESH:
+ mText.setText(R.string.pull_to_refresh_pull_label);
+ break;
+ case RefreshState.RELEASE_TO_REFRESH:
+ mText.setText(R.string.pull_to_refresh_release_label);
+ break;
+ case RefreshState.REFRESHING:
+ mText.setText(R.string.pull_to_refresh_refreshing_label);
+ break;
+ case RefreshState.ABORTING:
+ mText.setText(R.string.pull_to_refresh_aborting_label);
+ break;
+ }
+ }
+ }
+
+ private static class RefreshState {
+ public static final int PULL_TO_REFRESH = 1;
+ public static final int RELEASE_TO_REFRESH = 2;
+ public static final int REFRESHING = 3;
+ public static final int ABORTING = 4;
+ }
+}