aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorSammysHP <sven@sammyshp.de>2011-11-23 16:03:44 +0100
committerSammysHP <sven@sammyshp.de>2011-11-23 16:03:44 +0100
commitb4eaf66670760969f72b1244f298654484ee5731 (patch)
treeaa345cd6acada40c3af70871f61a07b3542dd610 /main
parentdf4bf84d783744790b1aa2975e8373261eb6ca06 (diff)
downloadcgeo-b4eaf66670760969f72b1244f298654484ee5731.zip
cgeo-b4eaf66670760969f72b1244f298654484ee5731.tar.gz
cgeo-b4eaf66670760969f72b1244f298654484ee5731.tar.bz2
New: Horizontal scrollable pages for cache-details using a ViewPager.
This moves most of the code from "cgeodetail" into a new class "CacheDetailActivity". Some important parts are rewritten and the code is much more structured. This closes #83 "Redesign detail-view". Some minor changes will be added later (e.g. removing old files, improve log-count-display)
Diffstat (limited to 'main')
-rw-r--r--main/.classpath1
-rw-r--r--main/AndroidManifest.xml2
-rw-r--r--main/libs/android-support-v4.jarbin0 -> 140011 bytes
-rw-r--r--main/proguard.cfg4
-rw-r--r--main/res/drawable-hdpi/pagerindicator_background.9.pngbin0 -> 959 bytes
-rw-r--r--main/res/drawable-ldpi/pagerindicator_background.9.pngbin0 -> 367 bytes
-rw-r--r--main/res/drawable/pagerindicator_background.9.pngbin0 -> 579 bytes
-rw-r--r--main/res/layout/cacheview.xml56
-rw-r--r--main/res/layout/cacheview_description.xml160
-rw-r--r--main/res/layout/cacheview_details.xml164
-rw-r--r--main/res/layout/cacheview_inventory.xml5
-rw-r--r--main/res/layout/cacheview_logs.xml28
-rw-r--r--main/res/layout/cacheview_waypoints.xml25
-rw-r--r--main/res/values/attrs.xml1
-rw-r--r--main/res/values/colors.xml54
-rw-r--r--main/res/values/styles.xml597
-rw-r--r--main/res/values/themes.xml2
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java2268
-rw-r--r--main/src/cgeo/geocaching/cgCacheListAdapter.java2
-rw-r--r--main/src/cgeo/geocaching/cgTrackable.java14
-rw-r--r--main/src/cgeo/geocaching/cgeo.java2
-rw-r--r--main/src/cgeo/geocaching/cgeoadvsearch.java4
-rw-r--r--main/src/cgeo/geocaching/cgeocaches.java2
-rw-r--r--main/src/cgeo/geocaching/cgeopopup.java2
-rw-r--r--main/src/cgeo/geocaching/cgeotrackable.java4
-rw-r--r--main/src/cgeo/geocaching/maps/OtherCachersOverlay.java4
-rw-r--r--main/src/cgeo/geocaching/utils/BaseUtils.java10
27 files changed, 3094 insertions, 317 deletions
diff --git a/main/.classpath b/main/.classpath
index db7b7b6..e8b6f86 100644
--- a/main/.classpath
+++ b/main/.classpath
@@ -7,5 +7,6 @@
<classpathentry kind="lib" path="libs/locus-api-4.0.jar"/>
<classpathentry kind="lib" path="libs/mapsforge-map-0.2.4.jar"/>
<classpathentry kind="lib" path="libs/commons-collections-3.2.1.jar"/>
+ <classpathentry kind="lib" path="libs/android-support-v4.jar"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml
index 91626cc..269b90e 100644
--- a/main/AndroidManifest.xml
+++ b/main/AndroidManifest.xml
@@ -213,7 +213,7 @@
</intent-filter>
</activity>
<activity
- android:name=".cgeodetail"
+ android:name=".CacheDetailActivity"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation" >
<intent-filter>
diff --git a/main/libs/android-support-v4.jar b/main/libs/android-support-v4.jar
new file mode 100644
index 0000000..b9a4279
--- /dev/null
+++ b/main/libs/android-support-v4.jar
Binary files differ
diff --git a/main/proguard.cfg b/main/proguard.cfg
index 02ab774..3b5251d 100644
--- a/main/proguard.cfg
+++ b/main/proguard.cfg
@@ -6,6 +6,10 @@
-dontwarn java.beans.*
-dontwarn org.mapsforge.android.maps.Test*
+-dontwarn CompatHoneycomb
+-dontwarn **CompatCreatorHoneycombMR2
+-dontwarn **ActivityCompatHoneycomb
+-dontwarn **MenuCompatHoneycomb
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
diff --git a/main/res/drawable-hdpi/pagerindicator_background.9.png b/main/res/drawable-hdpi/pagerindicator_background.9.png
new file mode 100644
index 0000000..2474e5c
--- /dev/null
+++ b/main/res/drawable-hdpi/pagerindicator_background.9.png
Binary files differ
diff --git a/main/res/drawable-ldpi/pagerindicator_background.9.png b/main/res/drawable-ldpi/pagerindicator_background.9.png
new file mode 100644
index 0000000..d9f91d6
--- /dev/null
+++ b/main/res/drawable-ldpi/pagerindicator_background.9.png
Binary files differ
diff --git a/main/res/drawable/pagerindicator_background.9.png b/main/res/drawable/pagerindicator_background.9.png
new file mode 100644
index 0000000..697675b
--- /dev/null
+++ b/main/res/drawable/pagerindicator_background.9.png
Binary files differ
diff --git a/main/res/layout/cacheview.xml b/main/res/layout/cacheview.xml
new file mode 100644
index 0000000..05df377
--- /dev/null
+++ b/main/res/layout/cacheview.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="?background_color"
+ android:orientation="vertical" >
+
+ <LinearLayout style="@style/action_bar" >
+
+ <ImageView
+ style="@style/action_bar_action"
+ android:onClick="goHome" />
+
+ <View style="@style/action_bar_separator" />
+
+ <TextView style="@style/action_bar_title" />
+
+ <View style="@style/action_bar_separator" />
+
+ <ImageView
+ style="@style/action_bar_action"
+ android:onClick="startCompassNavigation"
+ android:src="@drawable/actionbar_compass" />
+
+ <View style="@style/action_bar_separator" />
+
+ <ImageView
+ style="@style/action_bar_action"
+ android:onClick="goManual"
+ android:src="@drawable/actionbar_manual" />
+ </LinearLayout>
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/viewpager"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+
+ <RelativeLayout style="@style/pager_indicator" >
+
+ <TextView
+ android:id="@+id/indicator_prev"
+ style="@style/pager_indicator.side"
+ android:layout_alignParentLeft="true" />
+
+ <TextView
+ android:id="@+id/indicator_current"
+ style="@style/pager_indicator.title" />
+
+ <TextView
+ android:id="@+id/indicator_next"
+ style="@style/pager_indicator.side"
+ android:layout_alignParentRight="true" />
+ </RelativeLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout/cacheview_description.xml b/main/res/layout/cacheview_description.xml
new file mode 100644
index 0000000..12abe7e
--- /dev/null
+++ b/main/res/layout/cacheview_description.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:padding="4dip" >
+
+ <!-- Short description -->
+
+ <TextView
+ android:id="@+id/shortdesc"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dip"
+ android:linksClickable="true"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14dip"
+ android:visibility="gone" />
+
+ <!-- Long description -->
+
+ <TextView
+ android:id="@+id/longdesc"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dip"
+ android:linksClickable="true"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14dip"
+ android:visibility="gone" />
+
+ <Button
+ android:id="@+id/show_description"
+ style="@style/button"
+ android:text="@string/cache_description_long"
+ android:visibility="gone" />
+
+ <RelativeLayout
+ android:id="@+id/loading"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" >
+
+ <ProgressBar
+ style="@android:style/Widget.ProgressBar.Large.Inverse"
+ android:layout_width="76dip"
+ android:layout_height="76dip"
+ android:layout_centerInParent="true"
+ android:gravity="center"
+ android:indeterminate="true" />
+ </RelativeLayout>
+
+ <!-- Attributes box -->
+
+ <LinearLayout
+ android:id="@+id/attributes_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:visibility="gone" >
+
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+
+ <View style="@style/separator_horizontal" />
+
+ <TextView
+ style="@style/separator_horizontal_headline"
+ android:text="@string/cache_attributes" />
+ </RelativeLayout>
+ <!-- innerbox is only needed to define the paddings easily -->
+
+ <LinearLayout
+ android:id="@+id/attributes_innerbox"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="6dp"
+ android:paddingRight="6dp" />
+ </LinearLayout>
+
+ <!-- Hint and spoiler-images box -->
+
+ <LinearLayout
+ android:id="@+id/hint_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dip"
+ android:orientation="vertical"
+ android:visibility="gone" >
+
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+
+ <View style="@style/separator_horizontal" />
+
+ <TextView
+ style="@style/separator_horizontal_headline"
+ android:text="@string/cache_hint" />
+ </RelativeLayout>
+
+ <TextView
+ android:id="@+id/hint"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:linksClickable="true"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14dip" />
+
+ <TextView
+ android:id="@+id/hint_spoilerlink"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:layout_marginTop="6dip"
+ android:drawableLeft="?log_img_icon"
+ android:drawablePadding="3dip"
+ android:text="@string/cache_menu_spoilers"
+ android:textColor="?text_color"
+ android:textSize="14dip" />
+ </LinearLayout>
+
+ <!-- Personal note box -->
+
+ <LinearLayout
+ android:id="@+id/personalnote_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dip"
+ android:orientation="vertical"
+ android:visibility="gone" >
+
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+
+ <View style="@style/separator_horizontal" />
+
+ <TextView
+ style="@style/separator_horizontal_headline"
+ android:text="@string/cache_personal_note" />
+ </RelativeLayout>
+
+ <TextView
+ android:id="@+id/personalnote"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:linksClickable="true"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14dip"
+ android:visibility="gone" />
+ </LinearLayout>
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/main/res/layout/cacheview_details.xml b/main/res/layout/cacheview_details.xml
new file mode 100644
index 0000000..45d067e
--- /dev/null
+++ b/main/res/layout/cacheview_details.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:scrollbars="none" >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:padding="4dip" >
+
+ <!-- Map preview -->
+
+ <ImageView
+ android:id="@+id/map_preview"
+ android:layout_width="fill_parent"
+ android:layout_height="80dip"
+ android:layout_gravity="center"
+ android:layout_marginBottom="5dip"
+ android:gravity="center"
+ android:scaleType="centerCrop"
+ android:src="@null"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:id="@+id/details_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+
+ <!-- Offline box -->
+
+ <LinearLayout
+ android:id="@+id/offline_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+
+ <View style="@style/separator_horizontal" />
+
+ <TextView
+ style="@style/separator_horizontal_headline"
+ android:text="@string/cache_offline" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/offline_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="130dip"
+ android:paddingRight="3dip"
+ android:textColor="?text_color"
+ android:textSize="14dip" />
+
+ <Button
+ android:id="@+id/offline_refresh"
+ style="@style/button_small"
+ android:layout_width="60dip"
+ android:layout_alignParentRight="true"
+ android:layout_marginRight="71dip"
+ android:text="@string/cache_offline_refresh"
+ android:visibility="gone" />
+
+ <Button
+ android:id="@+id/offline_store"
+ style="@style/button_small"
+ android:layout_width="60dip"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_offline_store" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <!-- Watchlist box -->
+
+ <LinearLayout
+ android:id="@+id/watchlist_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+
+ <View style="@style/separator_horizontal" />
+
+ <TextView
+ style="@style/separator_horizontal_headline"
+ android:text="@string/cache_watchlist" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/watchlist_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="130dip"
+ android:paddingRight="3dip"
+ android:textColor="?text_color"
+ android:textSize="14dip" />
+
+ <Button
+ android:id="@+id/add_to_watchlist"
+ style="@style/button_small"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_watchlist_add"
+ android:visibility="gone" />
+
+ <Button
+ android:id="@+id/remove_from_watchlist"
+ style="@style/button_small"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_watchlist_remove"
+ android:visibility="gone" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <!-- License Box -->
+
+ <LinearLayout
+ android:id="@+id/license_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:visibility="gone" >
+
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+
+ <View style="@style/separator_horizontal" />
+
+ <TextView
+ style="@style/separator_horizontal_headline"
+ android:text="@string/cache_license" />
+ </RelativeLayout>
+
+ <TextView
+ android:id="@+id/license"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:linksClickable="true"
+ android:padding="3dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14dip" />
+ </LinearLayout>
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/main/res/layout/cacheview_inventory.xml b/main/res/layout/cacheview_inventory.xml
new file mode 100644
index 0000000..9effe8c
--- /dev/null
+++ b/main/res/layout/cacheview_inventory.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+ </ListView> \ No newline at end of file
diff --git a/main/res/layout/cacheview_logs.xml b/main/res/layout/cacheview_logs.xml
new file mode 100644
index 0000000..d7babb9
--- /dev/null
+++ b/main/res/layout/cacheview_logs.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:padding="4dip" >
+
+ <TextView
+ android:id="@+id/log_count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dip"
+ android:textColor="?text_color"
+ android:textSize="14dip" />
+
+ <LinearLayout
+ android:id="@+id/log_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/main/res/layout/cacheview_waypoints.xml b/main/res/layout/cacheview_waypoints.xml
new file mode 100644
index 0000000..35e4948
--- /dev/null
+++ b/main/res/layout/cacheview_waypoints.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:padding="4dip" >
+
+ <LinearLayout
+ android:id="@+id/waypoints"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/add_waypoint"
+ style="@style/button"
+ android:text="@string/cache_waypoints_add" />
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/main/res/values/attrs.xml b/main/res/values/attrs.xml
index 187d4cb..e6d7bba 100644
--- a/main/res/values/attrs.xml
+++ b/main/res/values/attrs.xml
@@ -17,6 +17,7 @@
<attr name="background_color_notice" format="color" />
<attr name="background_color_transparent" format="color" />
<attr name="separator_color" format="color" />
+ <attr name="text_color_pagerindicator" format="color" />
<!-- drawables -->
<attr name="button" format="integer" />
diff --git a/main/res/values/colors.xml b/main/res/values/colors.xml
index 169f319..91fb6a5 100644
--- a/main/res/values/colors.xml
+++ b/main/res/values/colors.xml
@@ -1,27 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
- <color name="just_white">#FFFFFFFF</color>
- <color name="just_black">#FF000000</color>
- <color name="background_dark">#FF000000</color>
- <color name="background_light">#FFFFFFFF</color>
- <color name="background_dark_notice">#FF191919</color>
- <color name="background_light_notice">#FFDFDFDF</color>
- <color name="background_dark_transparent">#44000000</color>
- <color name="background_light_transparent">#44FFFFFF</color>
- <color name="owncache_background_dark">#FF222222</color>
- <color name="owncache_background_light">#FFDDDDDD</color>
- <color name="separator_dark">#44FFFFFF</color>
- <color name="separator_light">#44000000</color>
- <color name="text_icon">#FFFFFFFF</color>
- <color name="text_dark">#FFFFFFFF</color>
- <color name="text_light">#FF000000</color>
- <color name="text_headline_dark">#88FFFFFF</color>
- <color name="text_headline_light">#88000000</color>
- <color name="text_grey_dark">#AAFFFFFF</color>
- <color name="text_grey_light">#AA000000</color>
- <color name="text_hint_dark">#44FFFFFF</color>
- <color name="text_hint_light">#44000000</color>
- <color name="link">#FF00C0FF</color>
- <color name="button_enabled">#FF000000</color>
- <color name="button_disabled">#66000000</color>
-</resources>
+
+ <color name="just_white">#FFFFFFFF</color>
+ <color name="just_black">#FF000000</color>
+ <color name="background_dark">#FF000000</color>
+ <color name="background_light">#FFFFFFFF</color>
+ <color name="background_dark_notice">#FF191919</color>
+ <color name="background_light_notice">#FFDFDFDF</color>
+ <color name="background_dark_transparent">#44000000</color>
+ <color name="background_light_transparent">#44FFFFFF</color>
+ <color name="owncache_background_dark">#FF222222</color>
+ <color name="owncache_background_light">#FFDDDDDD</color>
+ <color name="separator_dark">#44FFFFFF</color>
+ <color name="separator_light">#44000000</color>
+ <color name="text_icon">#FFFFFFFF</color>
+ <color name="text_dark">#FFFFFFFF</color>
+ <color name="text_light">#FF000000</color>
+ <color name="text_headline_dark">#88FFFFFF</color>
+ <color name="text_headline_light">#88000000</color>
+ <color name="text_grey_dark">#AAFFFFFF</color>
+ <color name="text_grey_light">#AA000000</color>
+ <color name="text_hint_dark">#44FFFFFF</color>
+ <color name="text_hint_light">#44000000</color>
+ <color name="link">#FF00C0FF</color>
+ <color name="button_enabled">#FF000000</color>
+ <color name="button_disabled">#66000000</color>
+ <color name="text_pagerindicator">#FFFFFFFF</color>
+ <color name="text_pagerindicator_sides">#88FFFFFF</color>
+
+</resources> \ No newline at end of file
diff --git a/main/res/values/styles.xml b/main/res/values/styles.xml
index 06c5c43..58b404f 100644
--- a/main/res/values/styles.xml
+++ b/main/res/values/styles.xml
@@ -1,305 +1,340 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
-<!-- system definitions -->
- <style name="cgeo" parent="android:Theme.NoTitleBar">
- </style>
- <style name="button" parent="@android:style/Widget.Button">
- <item name="android:padding">6dip</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">22dip</item>
- <item name="android:textColor">?text_color</item>
- <item name="android:background">?button</item>
- <item name="android:focusable">true</item>
- <item name="android:clickable">true</item>
- <item name="android:gravity">center</item>
- </style>
+ <!-- system definitions -->
+ <style name="cgeo" parent="android:Theme.NoTitleBar"></style>
- <style name="edittext" parent="@android:style/Widget.EditText">
- <item name="android:padding">6dip</item>
- <item name="android:singleLine">true</item>
- <item name="android:autoText">true</item>
- <item name="android:textSize">22dip</item>
- <item name="android:textColor">?text_color</item>
- <item name="android:textColorHint">?text_color_hint</item>
- <item name="android:background">?input</item>
- <item name="android:focusable">true</item>
- <item name="android:gravity">top|left</item>
- <item name="android:capitalize">none</item>
- </style>
+ <style name="button" parent="@android:style/Widget.Button">
+ <item name="android:padding">6dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">22dip</item>
+ <item name="android:textColor">?text_color</item>
+ <item name="android:background">?button</item>
+ <item name="android:focusable">true</item>
+ <item name="android:clickable">true</item>
+ <item name="android:gravity">center</item>
+ </style>
-<!-- own definitions -->
-<!-- actionbar -->
- <style name="action_bar">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">@dimen/actionbar_height</item>
- <item name="android:orientation">horizontal</item>
- <item name="android:background">@drawable/actionbar_background</item>
- <item name="android:gravity">center</item>
- </style>
+ <style name="edittext" parent="@android:style/Widget.EditText">
+ <item name="android:padding">6dip</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:autoText">true</item>
+ <item name="android:textSize">22dip</item>
+ <item name="android:textColor">?text_color</item>
+ <item name="android:textColorHint">?text_color_hint</item>
+ <item name="android:background">?input</item>
+ <item name="android:focusable">true</item>
+ <item name="android:gravity">top|left</item>
+ <item name="android:capitalize">none</item>
+ </style>
- <style name="action_bar_icon_cgeo">
- <item name="android:layout_width">@dimen/actionbar_height</item>
- <item name="android:layout_height">@dimen/actionbar_height</item>
- <item name="android:padding">4dip</item>
- <item name="android:scaleType">center</item>
- <item name="android:focusable">true</item>
- <item name="android:src">@drawable/actionbar_cgeo</item>
- <item name="android:background">@drawable/actionbar_button</item>
- </style>
+ <!-- own definitions -->
+ <!-- actionbar -->
+ <style name="action_bar">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">@dimen/actionbar_height</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:background">@drawable/actionbar_background</item>
+ <item name="android:gravity">center</item>
+ </style>
- <style name="action_bar_action">
- <item name="android:layout_width">@dimen/actionbar_height</item>
- <item name="android:layout_height">@dimen/actionbar_height</item>
- <item name="android:padding">2dip</item>
- <item name="android:scaleType">center</item>
- <item name="android:focusable">true</item>
- <item name="android:src">@drawable/actionbar_home</item>
- <item name="android:background">@drawable/actionbar_button</item>
- </style>
+ <style name="action_bar_icon_cgeo">
+ <item name="android:layout_width">@dimen/actionbar_height</item>
+ <item name="android:layout_height">@dimen/actionbar_height</item>
+ <item name="android:padding">4dip</item>
+ <item name="android:scaleType">center</item>
+ <item name="android:focusable">true</item>
+ <item name="android:src">@drawable/actionbar_cgeo</item>
+ <item name="android:background">@drawable/actionbar_button</item>
+ </style>
- <style name="action_bar_separator">
- <item name="android:layout_width">@dimen/actionbar_separator_width</item>
- <item name="android:layout_height">@dimen/actionbar_separator_height</item>
- <item name="android:background">@drawable/actionbar_separator</item>
- </style>
+ <style name="action_bar_action">
+ <item name="android:layout_width">@dimen/actionbar_height</item>
+ <item name="android:layout_height">@dimen/actionbar_height</item>
+ <item name="android:padding">2dip</item>
+ <item name="android:scaleType">center</item>
+ <item name="android:focusable">true</item>
+ <item name="android:src">@drawable/actionbar_home</item>
+ <item name="android:background">@drawable/actionbar_button</item>
+ </style>
- <style name="action_bar_progress" parent="@android:style/Widget.ProgressBar.Small">
- <item name="android:id">@id/actionbar_progress</item>
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginLeft">15dip</item>
- <item name="android:layout_marginRight">15dip</item>
- <item name="android:indeterminate">true</item>
- </style>
+ <style name="action_bar_separator">
+ <item name="android:layout_width">@dimen/actionbar_separator_width</item>
+ <item name="android:layout_height">@dimen/actionbar_separator_height</item>
+ <item name="android:background">@drawable/actionbar_separator</item>
+ </style>
- <style name="action_bar_title">
- <item name="android:id">@id/actionbar_title</item>
- <item name="android:layout_width">0dip</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_weight">1</item>
- <item name="android:paddingLeft">6dip</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:lines">1</item>
- <item name="android:textSize">20dip</item>
- <item name="android:textColor">@color/just_white</item>
- <item name="android:text">c:geo</item>
- </style>
+ <style name="action_bar_progress" parent="@android:style/Widget.ProgressBar.Small">
+ <item name="android:id">@id/actionbar_progress</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">15dip</item>
+ <item name="android:layout_marginRight">15dip</item>
+ <item name="android:indeterminate">true</item>
+ </style>
-<!-- button: full width -->
- <style name="button">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginLeft">10dip</item>
- <item name="android:layout_marginRight">10dip</item>
- <item name="android:layout_marginBottom">5dip</item>
- </style>
+ <style name="action_bar_title">
+ <item name="android:id">@id/actionbar_title</item>
+ <item name="android:layout_width">0dip</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:paddingLeft">6dip</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:lines">1</item>
+ <item name="android:textSize">20dip</item>
+ <item name="android:textColor">@color/just_white</item>
+ <item name="android:text">c:geo</item>
+ </style>
-<!-- button: small -->
- <style name="button_small">
- <item name="android:layout_width">125dip</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_gravity">right</item>
- <item name="android:layout_marginLeft">6dip</item>
- <item name="android:layout_marginRight">6dip</item>
- <item name="android:layout_marginTop">3dip</item>
- <item name="android:layout_marginBottom">3dip</item>
- <item name="android:padding">3dip</item>
- <item name="android:textSize">14dip</item>
- </style>
+ <!-- button: full width -->
+ <style name="button">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">10dip</item>
+ <item name="android:layout_marginRight">10dip</item>
+ <item name="android:layout_marginBottom">5dip</item>
+ </style>
-<!-- edittext -->
- <style name="edittext">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginLeft">10dip</item>
- <item name="android:layout_marginRight">10dip</item>
- <item name="android:layout_marginBottom">5dip</item>
- </style>
+ <!-- button: small -->
+ <style name="button_small">
+ <item name="android:layout_width">125dip</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">right</item>
+ <item name="android:layout_marginLeft">6dip</item>
+ <item name="android:layout_marginRight">6dip</item>
+ <item name="android:layout_marginTop">3dip</item>
+ <item name="android:layout_marginBottom">3dip</item>
+ <item name="android:padding">3dip</item>
+ <item name="android:textSize">14dip</item>
+ </style>
- <style name="edittext_dialog">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginLeft">10dip</item>
- <item name="android:layout_marginRight">10dip</item>
- <item name="android:layout_marginBottom">5dip</item>
- <item name="android:textColor">@color/text_dark</item>
- <item name="android:textColorHint">@color/text_hint_dark</item>
- <item name="android:background">@drawable/input_bcg_dark</item>
- </style>
+ <!-- edittext -->
+ <style name="edittext">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">10dip</item>
+ <item name="android:layout_marginRight">10dip</item>
+ <item name="android:layout_marginBottom">5dip</item>
+ </style>
-<!-- mainscreen icon -->
- <style name="icon_mainscreen">
- <item name="android:layout_width">48dip</item>
- <item name="android:layout_height">48dip</item>
- <item name="android:layout_gravity">center_horizontal</item>
- <item name="android:gravity">center</item>
- <item name="android:layout_margin">4dip</item>
- <item name="android:focusable">true</item>
- </style>
+ <style name="edittext_dialog">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">10dip</item>
+ <item name="android:layout_marginRight">10dip</item>
+ <item name="android:layout_marginBottom">5dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ <item name="android:textColorHint">@color/text_hint_dark</item>
+ <item name="android:background">@drawable/input_bcg_dark</item>
+ </style>
- <style name="icon_mainscreen_text">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_gravity">center_horizontal</item>
- <item name="android:gravity">center</item>
- <item name="android:paddingTop">1dip</item>
- <item name="android:paddingBottom">1dip</item>
- <item name="android:paddingLeft">5dip</item>
- <item name="android:paddingRight">5dip</item>
- <item name="android:singleLine">true</item>
- <item name="android:lines">1</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">13dip</item>
- <item name="android:textColor">@color/text_icon</item>
- <item name="android:background">@drawable/icon_bcg</item>
- </style>
+ <!-- mainscreen icon -->
+ <style name="icon_mainscreen">
+ <item name="android:layout_width">48dip</item>
+ <item name="android:layout_height">48dip</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_margin">4dip</item>
+ <item name="android:focusable">true</item>
+ </style>
- <style name="icon_mainscreen_count">
- <item name="android:visibility">gone</item>
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_gravity">center_horizontal</item>
- <item name="android:layout_alignParentTop">true</item>
- <item name="android:layout_alignParentRight">true</item>
- <item name="android:layout_marginRight">4dip</item>
- <item name="android:layout_marginLeft">4dip</item>
- <item name="android:gravity">center</item>
- <item name="android:paddingTop">2dip</item>
- <item name="android:paddingBottom">2dip</item>
- <item name="android:paddingLeft">5dip</item>
- <item name="android:paddingRight">5dip</item>
- <item name="android:singleLine">true</item>
- <item name="android:lines">1</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">11dip</item>
- <item name="android:textColor">@color/just_white</item>
- <item name="android:background">@drawable/count_bcg</item>
- <item name="android:text"></item>
- </style>
+ <style name="icon_mainscreen_text">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:gravity">center</item>
+ <item name="android:paddingTop">1dip</item>
+ <item name="android:paddingBottom">1dip</item>
+ <item name="android:paddingLeft">5dip</item>
+ <item name="android:paddingRight">5dip</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:lines">1</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">13dip</item>
+ <item name="android:textColor">@color/text_icon</item>
+ <item name="android:background">@drawable/icon_bcg</item>
+ </style>
-<!-- current location -->
- <style name="location_current">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:gravity">center_horizontal</item>
- <item name="android:paddingLeft">5dip</item>
- <item name="android:paddingRight">5dip</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">14dip</item>
- <item name="android:textColor">@color/text_icon</item>
- <item name="android:background">@drawable/icon_bcg</item>
- </style>
+ <style name="icon_mainscreen_count">
+ <item name="android:visibility">gone</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:layout_alignParentTop">true</item>
+ <item name="android:layout_alignParentRight">true</item>
+ <item name="android:layout_marginRight">4dip</item>
+ <item name="android:layout_marginLeft">4dip</item>
+ <item name="android:gravity">center</item>
+ <item name="android:paddingTop">2dip</item>
+ <item name="android:paddingBottom">2dip</item>
+ <item name="android:paddingLeft">5dip</item>
+ <item name="android:paddingRight">5dip</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:lines">1</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">11dip</item>
+ <item name="android:textColor">@color/just_white</item>
+ <item name="android:background">@drawable/count_bcg</item>
+ <item name="android:text"></item>
+ </style>
- <style name="location_current_type">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_alignParentBottom">true</item>
- <item name="android:layout_alignParentRight">true</item>
- <item name="android:layout_gravity">right</item>
- <item name="android:paddingLeft">3dip</item>
- <item name="android:paddingRight">3dip</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">12dip</item>
- <item name="android:textColor">@color/text_dark</item>
- </style>
+ <!-- current location -->
+ <style name="location_current">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:paddingLeft">5dip</item>
+ <item name="android:paddingRight">5dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">14dip</item>
+ <item name="android:textColor">@color/text_icon</item>
+ <item name="android:background">@drawable/icon_bcg</item>
+ </style>
- <style name="location_current_accuracy">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_alignParentBottom">true</item>
- <item name="android:layout_centerHorizontal">true</item>
- <item name="android:layout_gravity">right</item>
- <item name="android:paddingLeft">3dip</item>
- <item name="android:paddingRight">3dip</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">12dip</item>
- <item name="android:textColor">@color/text_dark</item>
- </style>
+ <style name="location_current_type">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentBottom">true</item>
+ <item name="android:layout_alignParentRight">true</item>
+ <item name="android:layout_gravity">right</item>
+ <item name="android:paddingLeft">3dip</item>
+ <item name="android:paddingRight">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">12dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ </style>
- <style name="location_current_satellites">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_alignParentBottom">true</item>
- <item name="android:layout_alignParentLeft">true</item>
- <item name="android:layout_gravity">left</item>
- <item name="android:paddingLeft">3dip</item>
- <item name="android:paddingRight">3dip</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">12dip</item>
- <item name="android:textColor">@color/text_dark</item>
- </style>
+ <style name="location_current_accuracy">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentBottom">true</item>
+ <item name="android:layout_centerHorizontal">true</item>
+ <item name="android:layout_gravity">right</item>
+ <item name="android:paddingLeft">3dip</item>
+ <item name="android:paddingRight">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">12dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ </style>
-<!-- separators -->
- <style name="separator_horizontal">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">1dip</item>
- <item name="android:layout_centerInParent">true</item>
- <item name="android:background">?separator_color</item>
- </style>
+ <style name="location_current_satellites">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentBottom">true</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ <item name="android:layout_gravity">left</item>
+ <item name="android:paddingLeft">3dip</item>
+ <item name="android:paddingRight">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">12dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ </style>
- <style name="separator_horizontal_layout">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginTop">2dip</item>
- <item name="android:layout_marginBottom">2dip</item>
- </style>
+ <!-- separators -->
+ <style name="separator_horizontal">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">1dip</item>
+ <item name="android:layout_centerInParent">true</item>
+ <item name="android:background">?separator_color</item>
+ </style>
- <style name="separator_horizontal_headline">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_alignParentLeft">true</item>
- <item name="android:layout_marginLeft">15dip</item>
- <item name="android:padding">3dip</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:textSize">22dip</item>
- <item name="android:textColor">?text_color_headline</item>
- <item name="android:background">?background_color</item>
- </style>
-
-<!-- filter bar -->
- <style name="filter_bar">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:orientation">horizontal</item>
- <item name="android:background">@drawable/filter_bar_background</item>
- <item name="android:gravity">center_vertical</item>
- </style>
-
- <style name="filter_bar_image">
- <item name="android:layout_width">30dp</item>
- <item name="android:layout_height">30dp</item>
- <item name="android:padding">6dp</item>
- <item name="android:scaleType">fitCenter</item>
- </style>
-
- <style name="filter_bar_text">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:singleLine">true</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:lines">1</item>
- <item name="android:textColor">@android:color/white</item>
- </style>
-</resources>
+ <style name="separator_horizontal_layout">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">2dip</item>
+ <item name="android:layout_marginBottom">2dip</item>
+ </style>
+
+ <style name="separator_horizontal_headline">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ <item name="android:layout_marginLeft">15dip</item>
+ <item name="android:padding">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">22dip</item>
+ <item name="android:textColor">?text_color_headline</item>
+ <item name="android:background">?background_color</item>
+ </style>
+
+ <!-- filter bar -->
+ <style name="filter_bar">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:background">@drawable/filter_bar_background</item>
+ <item name="android:gravity">center_vertical</item>
+ </style>
+
+ <style name="filter_bar_image">
+ <item name="android:layout_width">30dp</item>
+ <item name="android:layout_height">30dp</item>
+ <item name="android:padding">6dp</item>
+ <item name="android:scaleType">fitCenter</item>
+ </style>
+
+ <style name="filter_bar_text">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:lines">1</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+
+ <!-- pager -->
+ <style name="pager_indicator">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:background">@drawable/pagerindicator_background</item>
+ </style>
+
+ <style name="pager_indicator.title">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_margin">5dip</item>
+ <item name="android:layout_centerInParent">true</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textSize">16dip</item>
+ <item name="android:textColor">@color/text_pagerindicator</item>
+ <item name="android:background">@null</item>
+ </style>
+
+ <style name="pager_indicator.side">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_margin">1dip</item>
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:textSize">12dip</item>
+ <item name="android:textColor">@color/text_pagerindicator_sides</item>
+ <item name="android:background">@null</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/main/res/values/themes.xml b/main/res/values/themes.xml
index ba07eb2..8b8c914 100644
--- a/main/res/values/themes.xml
+++ b/main/res/values/themes.xml
@@ -31,6 +31,7 @@
<item name="text_color_grey">@color/text_grey_dark</item>
<item name="text_color_hint">@color/text_hint_dark</item>
<item name="text_color_link">@color/link</item>
+ <item name="text_color_pagerindicator">@color/text_pagerindicator</item>
<item name="button_color_enabled">@color/button_enabled</item>
<item name="button_color_disabled">@color/button_disabled</item>
<item name="background_color">@color/background_dark</item>
@@ -63,6 +64,7 @@
<item name="text_color_grey">@color/text_grey_light</item>
<item name="text_color_hint">@color/text_hint_light</item>
<item name="text_color_link">@color/link</item>
+ <item name="text_color_pagerindicator">@color/text_pagerindicator</item>
<item name="button_color_enabled">@color/button_enabled</item>
<item name="button_color_disabled">@color/button_disabled</item>
<item name="background_color">@color/background_light</item>
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
new file mode 100644
index 0000000..242033f
--- /dev/null
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -0,0 +1,2268 @@
+package cgeo.geocaching;
+
+import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.activity.Progress;
+import cgeo.geocaching.apps.cache.GeneralAppsFactory;
+import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
+import cgeo.geocaching.compatibility.Compatibility;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.network.HtmlImage;
+import cgeo.geocaching.utils.BaseUtils;
+import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.CryptUtils;
+import cgeo.geocaching.utils.UnknownTagsHandler;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import android.R.color;
+import android.app.AlertDialog;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcelable;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.style.StrikethroughSpan;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.TextView.BufferType;
+
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Activity to handle all single-cache-stuff.
+ *
+ * e.g. details, description, logs, waypoints, inventory...
+ */
+public class CacheDetailActivity extends AbstractActivity {
+
+ private static final int MENU_SHARE = 12;
+ private static final int MENU_CALENDAR = 11;
+ private static final int MENU_CACHES_AROUND = 10;
+ private static final int MENU_BROWSER = 7;
+ private static final int MENU_NAVIGATE = 2;
+
+ private static final int CONTEXT_MENU_WAYPOINT_DELETE = 1235;
+ private static final int CONTEXT_MENU_WAYPOINT_DUPLICATE = 1234;
+
+ private cgGeo geolocation;
+ private cgCache cache;
+ private final Map<Integer, String> calendars = new HashMap<Integer, String>();
+ private final Progress progress = new Progress();
+ private cgSearch search;
+ private final LocationUpdater locationUpdater = new LocationUpdater();
+ private String contextMenuUser = null;
+
+ /**
+ * The index of the current page. We need this hack because {@link onPageSelected()} is not called after
+ * initialization.
+ */
+ private int currentPageIndex = 0;
+
+ /**
+ * A {@link List} of all available pages.
+ */
+ private final List<Page> pageOrder = new ArrayList<Page>();
+
+ /**
+ * Instances of all {@link PageViewCreator}.
+ */
+ private final Map<Page, PageViewCreator> viewCreators = new HashMap<Page, PageViewCreator>();
+
+ /**
+ * The {@link ViewPagerAdapter} for this activity.
+ */
+ private ViewPagerAdapter viewPagerAdapter;
+
+ /**
+ * The {@link ViewPagerIndicator} for this activity.
+ */
+ private ViewPagerIndicator viewPagerIndicator;
+
+ /**
+ * If another activity is called and can modify the data of this activity, we refresh it on resume.
+ */
+ private boolean refreshOnResume = false;
+
+ // some views that must be available from everywhere // TODO: Reference can block GC?
+ private TextView cacheDistanceView;
+
+ public CacheDetailActivity() {
+ // identifier for manual
+ super("c:geolocation-cache-details");
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // initialize the main view and set a default title
+ setTheme();
+ setContentView(R.layout.cacheview);
+ setTitle(res.getString(R.string.cache));
+
+ if (geolocation == null) {
+ geolocation = app.startGeo(this, locationUpdater, 0, 0);
+ }
+
+ String geocode = null;
+ String guid = null;
+ String name = null;
+
+ // TODO Why can it happen that search is not null? onCreate should be called only once and it is not set before.
+ if (search != null) {
+ cache = app.getCache(search);
+ if (cache != null && cache.getGeocode() != null) {
+ geocode = cache.getGeocode();
+ }
+ }
+
+ // get parameters
+ final Bundle extras = getIntent().getExtras();
+ final Uri uri = getIntent().getData();
+
+ // try to get data from extras
+ if (geocode == null && extras != null) {
+ geocode = extras.getString("geocode");
+ name = extras.getString("name");
+ guid = extras.getString("guid");
+ }
+
+ // try to get data from URI
+ if (geocode == null && guid == null && uri != null) {
+ String uriHost = uri.getHost().toLowerCase();
+ String uriPath = uri.getPath().toLowerCase();
+ String uriQuery = uri.getQuery();
+
+ if (uriQuery != null) {
+ Log.i(Settings.tag, "Opening URI: " + uriHost + uriPath + "?" + uriQuery);
+ } else {
+ Log.i(Settings.tag, "Opening URI: " + uriHost + uriPath);
+ }
+
+ if (uriHost.contains("geocaching.com")) {
+ geocode = uri.getQueryParameter("wp");
+ guid = uri.getQueryParameter("guid");
+
+ if (StringUtils.isNotBlank(geocode)) {
+ geocode = geocode.toUpperCase();
+ guid = null;
+ } else if (StringUtils.isNotBlank(guid)) {
+ geocode = null;
+ guid = guid.toLowerCase();
+ } else {
+ showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
+ }
+ } else if (uriHost.contains("coord.info")) {
+ if (uriPath != null && uriPath.startsWith("/gc")) {
+ geocode = uriPath.substring(1).toUpperCase();
+ } else {
+ showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
+ }
+ }
+ }
+
+ // no given data
+ if (geocode == null && guid == null) {
+ showToast(res.getString(R.string.err_detail_cache));
+ finish();
+ return;
+ }
+
+ // Go4Cache
+ if (StringUtils.isNotBlank(geocode)) {
+ app.setAction(geocode);
+ }
+
+ final LoadCacheHandler loadCacheHandler = new LoadCacheHandler();
+
+ try {
+ String title = res.getString(R.string.cache);
+ if (StringUtils.isNotBlank(name)) {
+ title = name;
+ } else if (StringUtils.isNotBlank(geocode)) {
+ title = geocode.toUpperCase();
+ }
+ progress.show(this, title, res.getString(R.string.cache_dialog_loading_details), true, loadCacheHandler.cancelMessage());
+ } catch (Exception e) {
+ // nothing, we lost the window
+ }
+
+ // initialize ViewPager
+ ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
+ viewPagerIndicator = new ViewPagerIndicator();
+ pager.setOnPageChangeListener(viewPagerIndicator);
+ viewPagerAdapter = new ViewPagerAdapter();
+ pager.setAdapter(viewPagerAdapter);
+
+ // Initialization done. Let's load the data with the given information.
+ new LoadCacheThread(geocode, guid, loadCacheHandler).start();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ // Maybe keyboard hidden or display orientation changed. No need for update the UI or something else.
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (geolocation == null) {
+ geolocation = app.startGeo(this, locationUpdater, 0, 0);
+ }
+
+ if (refreshOnResume) {
+ notifyDataSetChanged();
+ refreshOnResume = false;
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geolocation != null) {
+ geolocation = app.removeGeo();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geolocation != null) {
+ geolocation = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geolocation != null) {
+ geolocation = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+ switch (viewId) {
+ case R.id.author:
+ case R.id.value:
+ if (viewId == R.id.author) { // Author of a log entry
+ contextMenuUser = ((TextView) view).getText().toString();
+ } else if (viewId == R.id.value) { // The owner of the cache
+ if (StringUtils.isNotBlank(cache.getOwnerReal())) {
+ contextMenuUser = cache.getOwnerReal();
+ } else {
+ contextMenuUser = cache.getOwner();
+ }
+ }
+
+ menu.setHeaderTitle(res.getString(R.string.user_menu_title) + " " + contextMenuUser);
+ menu.add(viewId, 1, 0, res.getString(R.string.user_menu_view_hidden));
+ menu.add(viewId, 2, 0, res.getString(R.string.user_menu_view_found));
+ menu.add(viewId, 3, 0, res.getString(R.string.user_menu_open_browser));
+ break;
+ case -1:
+ if (null != cache.getWaypoints()) {
+ try {
+ final ViewGroup parent = ((ViewGroup) view.getParent());
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ if (parent.getChildAt(i) == view) {
+ final List<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.getWaypoints());
+ Collections.sort(sortedWaypoints);
+ final cgWaypoint waypoint = sortedWaypoints.get(i);
+ final int index = cache.getWaypoints().indexOf(waypoint);
+ menu.setHeaderTitle(res.getString(R.string.waypoint));
+ menu.add(CONTEXT_MENU_WAYPOINT_DUPLICATE, index, 0, R.string.waypoint_duplicate);
+ if (waypoint.isUserDefined()) {
+ menu.add(CONTEXT_MENU_WAYPOINT_DELETE, index, 0, R.string.waypoint_delete);
+ }
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int groupId = item.getGroupId();
+ final int index = item.getItemId();
+ switch (groupId) {
+ case R.id.author:
+ case R.id.value:
+ final int itemId = item.getItemId();
+ switch (itemId) {
+ case 1:
+ cgeocaches.startActivityOwner(this, contextMenuUser);
+ return true;
+ case 2:
+ cgeocaches.startActivityUserName(this, contextMenuUser);
+ return true;
+ case 3:
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser))));
+ return true;
+ default:
+ break;
+ }
+ break;
+ case CONTEXT_MENU_WAYPOINT_DUPLICATE:
+ if (null != cache.getWaypoints() && index < cache.getWaypoints().size()) {
+ final cgWaypoint copy = new cgWaypoint(cache.getWaypoints().get(index));
+ copy.setUserDefined();
+ copy.setName(res.getString(R.string.waypoint_copy_of) + " " + copy.getName());
+ cache.getWaypoints().add(index + 1, copy);
+ app.saveOwnWaypoint(-1, cache.getGeocode(), copy);
+ app.removeCacheFromCache(cache.getGeocode());
+ notifyDataSetChanged();
+ }
+ break;
+ case CONTEXT_MENU_WAYPOINT_DELETE:
+ if (null != cache.getWaypoints() && index < cache.getWaypoints().size()) {
+ final cgWaypoint waypoint = cache.getWaypoints().get(index);
+ if (waypoint.isUserDefined()) {
+ cache.getWaypoints().remove(index);
+ app.deleteWaypoint(waypoint.getId());
+ app.removeCacheFromCache(cache.getGeocode());
+ notifyDataSetChanged();
+ }
+ }
+ break;
+ default:
+ return onOptionsItemSelected(item);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (null != cache) {
+ menu.add(0, MENU_NAVIGATE, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ final SubMenu subMenu = menu.addSubMenu(1, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_mapmode);
+ NavigationAppFactory.addMenuItems(subMenu, this, res);
+ GeneralAppsFactory.addMenuItems(subMenu, this, res, cache);
+
+ menu.add(1, MENU_CALENDAR, 0, res.getString(R.string.cache_menu_event)).setIcon(android.R.drawable.ic_menu_agenda); // add event to calendar
+ addVisitMenu(menu, cache);
+ menu.add(0, MENU_CACHES_AROUND, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+ menu.add(1, MENU_BROWSER, 0, res.getString(R.string.cache_menu_browser)).setIcon(R.drawable.ic_menu_globe); // browser
+ menu.add(0, MENU_SHARE, 0, res.getString(R.string.cache_menu_share)).setIcon(android.R.drawable.ic_menu_share); // share cache
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ menu.findItem(MENU_NAVIGATE).setVisible(null != cache.getCoords());
+ menu.findItem(MENU_CALENDAR).setVisible(cache.canBeAddedToCalendar());
+ menu.findItem(MENU_CACHES_AROUND).setVisible(null != cache.getCoords() && cache.supportsCachesAround());
+ menu.findItem(MENU_BROWSER).setVisible(cache.canOpenInBrowser());
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ // no menu selected, but a new sub menu shown
+ if (menuItem == 0) {
+ return false;
+ }
+
+ if (menuItem == MENU_NAVIGATE) {
+ startCompassNavigation();
+ return true;
+ } else if (menuItem == MENU_LOG_VISIT) {
+ cache.logVisit(this);
+ return true;
+ } else if (menuItem == MENU_BROWSER) {
+ cache.openInBrowser(this);
+ return true;
+ } else if (menuItem == MENU_CACHES_AROUND) {
+ cachesAround();
+ return true;
+ } else if (menuItem == MENU_CALENDAR) {
+ addToCalendar();
+ return true;
+ } else if (menuItem == MENU_SHARE) {
+ if (cache != null) {
+ cache.shareCache(this, res);
+ return true;
+ }
+ return false;
+ }
+ if (NavigationAppFactory.onMenuItemSelected(item, geolocation, this, res, cache, search, null, null)) {
+ return true;
+ }
+ if (GeneralAppsFactory.onMenuItemSelected(item, this, cache)) {
+ return true;
+ }
+
+ int logType = menuItem - MENU_LOG_VISIT_OFFLINE;
+ cache.logOffline(this, logType);
+ return true;
+ }
+
+ private class LoadCacheHandler extends CancellableHandler {
+ @Override
+ public void handleRegularMessage(final Message msg) {
+ if (cgBase.UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) {
+ updateStatusMsg((String) msg.obj);
+ } else {
+ if (search == null) {
+ showToast(res.getString(R.string.err_dwld_details_failed));
+
+ finish();
+ return;
+ }
+
+ if (cgeoapplication.getError(search) != null) {
+ showToast(res.getString(R.string.err_dwld_details_failed_reason) + " " + cgeoapplication.getError(search) + ".");
+
+ finish();
+ return;
+ }
+
+ updateStatusMsg(res.getString(R.string.cache_dialog_loading_details_status_render));
+
+ // Data loaded, we're ready to show it!
+ notifyDataSetChanged();
+ }
+ }
+
+ private void updateStatusMsg(final String msg) {
+ progress.setMessage(res.getString(R.string.cache_dialog_loading_details)
+ + "\n\n"
+ + msg);
+ }
+
+ @Override
+ public void handleCancel(final Object extra) {
+ finish();
+ }
+
+ }
+
+ private void notifyDataSetChanged() {
+ if (search == null) {
+ return;
+ }
+
+ cache = app.getCache(search);
+
+ if (cache == null) {
+ progress.dismiss();
+ showToast(res.getString(R.string.err_detail_cache_find_some));
+ finish();
+ return;
+ }
+
+ // notify all creators that the data has changed
+ for (PageViewCreator creator : viewCreators.values()) {
+ creator.notifyDataSetChanged();
+ }
+
+ // actionbar: title and icon (default: mystery-icon)
+ setTitle(cache.getGeocode().toUpperCase());
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(cgBase.getCacheIcon(cache.getType())), null, null, null);
+
+ // add available pages (remove old pages first)
+ pageOrder.clear();
+
+ pageOrder.add(Page.DETAILS);
+ pageOrder.add(Page.DESCRIPTION);
+ if (CollectionUtils.isNotEmpty(cache.getLogs())) {
+ pageOrder.add(Page.LOGS);
+ }
+ pageOrder.add(Page.WAYPOINTS);
+ if (CollectionUtils.isNotEmpty(cache.getInventory())) {
+ pageOrder.add(Page.INVENTORY);
+ }
+
+ // notify the adapter that the data has changed
+ viewPagerAdapter.notifyDataSetChanged();
+
+ // notify the indicator about the change
+ viewPagerIndicator.onPageSelected(currentPageIndex);
+
+ // rendering done! remove progress-popup if any there
+ progress.dismiss();
+ }
+
+ private class LocationUpdater extends cgUpdateLoc {
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+ if (cacheDistanceView == null) {
+ return;
+ }
+
+ try {
+ StringBuilder dist = new StringBuilder();
+
+ if (geo.coordsNow != null && cache != null && cache.getCoords() != null) {
+ dist.append(cgBase.getHumanDistance(geo.coordsNow.distanceTo(cache.getCoords())));
+ }
+
+ if (cache != null && cache.getElevation() != null) {
+ if (geo.altitudeNow != null) {
+ Double diff = (cache.getElevation() - geo.altitudeNow);
+ if (diff >= 0) {
+ dist.append(" ↗");
+ } else if (diff < 0) {
+ dist.append(" ↘");
+ }
+ if (Settings.isUseMetricUnits()) {
+ dist.append(String.format("%.0f", (Math.abs(diff))));
+ dist.append(" m");
+ } else {
+ dist.append(String.format("%.0f", (Math.abs(diff) * 3.2808399)));
+ dist.append(" ft");
+ }
+ }
+ }
+
+ cacheDistanceView.setText(dist.toString());
+ cacheDistanceView.bringToFront();
+ } catch (Exception e) {
+ Log.w(Settings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ /**
+ * Loads the cache with the given geocode or guid.
+ */
+ private class LoadCacheThread extends Thread {
+
+ private CancellableHandler handler = null;
+ private String geocode;
+ private String guid;
+
+ public LoadCacheThread(final String geocode, final String guid, final CancellableHandler handlerIn) {
+ handler = handlerIn;
+
+ if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid)) {
+ showToast(res.getString(R.string.err_detail_cache_forgot));
+
+ finish();
+ return;
+ }
+
+ this.geocode = geocode;
+ this.guid = guid;
+ }
+
+ @Override
+ public void run() {
+ search = cgBase.searchByGeocode(geocode, StringUtils.isBlank(geocode) ? guid : null, 0, false, handler);
+ handler.sendMessage(new Message());
+ }
+ }
+
+ /**
+ * Starts activity to search for caches near this cache.
+ *
+ * Also finishes this activity.
+ */
+ private void cachesAround() {
+ cgeocaches.startActivityCachesAround(this, cache.getCoords());
+
+ finish();
+ }
+
+ /**
+ * Adds the cache to the Android-calendar if it is an event.
+ */
+ private void addToCalendar() {
+ String[] projection = new String[] { "_id", "displayName" };
+ Uri calendarProvider = Compatibility.getCalendarProviderURI();
+
+ Cursor cursor = managedQuery(calendarProvider, projection, "selected=1", null, null);
+
+ calendars.clear();
+ int cnt = 0;
+ if (cursor != null) {
+ cnt = cursor.getCount();
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ int calId = 0;
+ String calIdPre = null;
+ String calName = null;
+ int calIdIn = cursor.getColumnIndex("_id");
+ int calNameIn = cursor.getColumnIndex("displayName");
+
+ do {
+ calIdPre = cursor.getString(calIdIn);
+ if (calIdPre != null) {
+ calId = new Integer(calIdPre);
+ }
+ calName = cursor.getString(calNameIn);
+
+ if (calId > 0 && calName != null) {
+ calendars.put(calId, calName);
+ }
+ } while (cursor.moveToNext());
+ }
+ }
+
+ final CharSequence[] items = calendars.values().toArray(new CharSequence[calendars.size()]);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.cache_calendars);
+ builder.setItems(items, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ addToCalendarFn(item);
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+
+ /**
+ * Helper for {@link addToCalendar()}.
+ *
+ * @param index
+ * The selected calendar
+ */
+ private void addToCalendarFn(int index) {
+ if (MapUtils.isEmpty(calendars)) {
+ return;
+ }
+
+ try {
+ Uri calendarProvider = Compatibility.getCalenderEventsProviderURI();
+
+ final Integer[] keys = calendars.keySet().toArray(new Integer[calendars.size()]);
+ final Integer calId = keys[index];
+
+ final Date eventDate = cache.getHiddenDate();
+ eventDate.setHours(0);
+ eventDate.setMinutes(0);
+ eventDate.setSeconds(0);
+
+ StringBuilder description = new StringBuilder();
+ description.append(cache.getUrl());
+ description.append("\n\n");
+ if (StringUtils.isNotBlank(cache.getShortdesc())) {
+ description.append(Html.fromHtml(cache.getShortdesc()).toString());
+ }
+
+ if (StringUtils.isNotBlank(cache.getPersonalNote())) {
+ description.append("\n\n" + Html.fromHtml(cache.getPersonalNote()).toString());
+ }
+
+ ContentValues event = new ContentValues();
+ event.put("calendar_id", calId);
+ event.put("dtstart", eventDate.getTime() + 43200000); // noon
+ event.put("dtend", eventDate.getTime() + 43200000 + 3600000); // + one hour
+ event.put("eventTimezone", "UTC");
+ event.put("title", Html.fromHtml(cache.getName()).toString());
+ event.put("description", description.toString());
+ String location = "";
+ if (cache.getCoords() != null) {
+ location += cache.getCoords();
+ }
+ if (StringUtils.isNotBlank(cache.getLocation())) {
+ boolean addParenteses = false;
+ if (location.length() > 0) {
+ addParenteses = true;
+ location += " (";
+ }
+
+ location += Html.fromHtml(cache.getLocation()).toString();
+ if (addParenteses) {
+ location += ")";
+ }
+ }
+ if (location.length() > 0) {
+ event.put("eventLocation", location);
+ }
+ event.put("allDay", 1);
+ event.put("hasAlarm", 0);
+
+ getContentResolver().insert(calendarProvider, event);
+
+ showToast(res.getString(R.string.event_success));
+ } catch (Exception e) {
+ showToast(res.getString(R.string.event_fail));
+
+ Log.e(Settings.tag, "CacheDetailActivity.addToCalendarFn: " + e.toString());
+ }
+ }
+
+ /**
+ * Creates a {@link List} of all coordinates (cache and waypoints) for the current cache.
+ *
+ * @return A {@link List} of all coordinates
+ */
+ public List<cgCoord> getCoordinates() {
+ List<cgCoord> coordinates = new ArrayList<cgCoord>();
+
+ // cache
+ try {
+ final cgCoord coords = new cgCoord();
+ coords.setCoordType("cache");
+ if (StringUtils.isNotBlank(cache.getName())) {
+ coords.setName(cache.getName());
+ } else {
+ coords.setName(cache.getGeocode().toUpperCase());
+ }
+ coords.setCoords(cache.getCoords());
+ coordinates.add(coords);
+ } catch (Exception e) {
+ Log.e(Settings.tag, "CacheDetailActivity.getCoordinates (cache)", e);
+ }
+
+ // waypoints
+ try {
+ if (null != cache.getWaypoints()) {
+ for (cgWaypoint waypoint : cache.getWaypoints()) {
+ if (null != waypoint.getCoords()) {
+ final cgCoord coords = new cgCoord();
+ coords.setCoordType("waypoint");
+ coords.setName(waypoint.getName());
+ coords.setCoords(waypoint.getCoords());
+ coordinates.add(coords);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(Settings.tag, "CacheDetailActivity.getCoordinates (waypoint)", e);
+ }
+
+ return coordinates;
+ }
+
+ /**
+ * Tries to navigate to the {@link cgCache} of this activity.
+ */
+ private void startCompassNavigation() {
+ if (cache == null || cache.getCoords() == null) {
+ showToast(res.getString(R.string.err_location_unknown));
+ return;
+ }
+
+ cgeonavigate.startActivity(this, cache.getGeocode(), cache.getName(), cache.getCoords(), getCoordinates());
+ }
+
+ /**
+ * Wrapper for the referenced method in the xml-layout.
+ */
+ public void startCompassNavigation(@SuppressWarnings("unused") View view) {
+ startCompassNavigation();
+ }
+
+ /**
+ * Opens a context menu to do actions on an username
+ */
+ private class UserActionsClickListener implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+ if (!cache.supportsUserActions()) {
+ return;
+ }
+
+ try {
+ registerForContextMenu(view);
+ openContextMenu(view);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+ public static void startActivity(final Context context, final String geocode) {
+ final Intent detailIntent = new Intent(context, CacheDetailActivity.class);
+ detailIntent.putExtra("geocode", geocode.toUpperCase());
+ context.startActivity(detailIntent);
+ }
+
+ /**
+ * The ViewPagerAdapter for scrolling through pages of the CacheDetailActivity.
+ */
+ private class ViewPagerAdapter extends PagerAdapter {
+
+ @Override
+ public void destroyItem(View container, int position, Object object) {
+ ((ViewPager) container).removeView((View) object);
+ }
+
+ @Override
+ public void finishUpdate(View container) {
+ }
+
+ @Override
+ public int getCount() {
+ return pageOrder.size();
+ }
+
+ @Override
+ public Object instantiateItem(View container, int position) {
+ final Page page = pageOrder.get(position);
+
+ PageViewCreator creator = viewCreators.get(page);
+
+ if (null == creator) {
+ // The creator is not instantiated yet, let's do it.
+ switch (page) {
+ case DETAILS:
+ creator = new DetailsViewCreator();
+ break;
+
+ case DESCRIPTION:
+ creator = new DescriptionViewCreator();
+ break;
+
+ case LOGS:
+ creator = new LogsViewCreator();
+ break;
+
+ case WAYPOINTS:
+ creator = new WaypointsViewCreator();
+ break;
+
+ case INVENTORY:
+ creator = new InventoryViewCreator();
+ break;
+ }
+ viewCreators.put(page, creator);
+ }
+
+ View view = null;
+
+ try {
+ if (null != creator) {
+ // Result from getView() is maybe cached, but it should be valid because the
+ // creator should be informed about data-changes with notifyDataSetChanged()
+ view = creator.getView();
+ ((ViewPager) container).addView(view, 0);
+ }
+ } catch (Exception e) {
+ Log.e(Settings.tag, "ViewPagerAdapter.instantiateItem ", e);
+ }
+
+ return view;
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return (view == object);
+ }
+
+ @Override
+ public void restoreState(Parcelable arg0, ClassLoader arg1) {
+ }
+
+ @Override
+ public Parcelable saveState() {
+ return null;
+ }
+
+ @Override
+ public void startUpdate(View arg0) {
+ }
+
+ @Override
+ public int getItemPosition(Object object) {
+ // We are doing the caching. So pretend that the view is gone.
+ // The ViewPager will get it back in instantiateItem()
+ return POSITION_NONE;
+ }
+ }
+
+ private class ViewPagerIndicator implements ViewPager.OnPageChangeListener {
+
+ // TODO: Clickable prev + next
+ private TextView indicatorPrev;
+ private TextView indicatorCurrent;
+ private TextView indicatorNext;
+
+ public ViewPagerIndicator() {
+ super();
+
+ indicatorPrev = (TextView) findViewById(R.id.indicator_prev);
+ indicatorCurrent = (TextView) findViewById(R.id.indicator_current);
+ indicatorNext = (TextView) findViewById(R.id.indicator_next);
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ currentPageIndex = position;
+
+ indicatorCurrent.setText(res.getString(pageOrder.get(position).titleStringId));
+
+ if (position > 0) {
+ indicatorPrev.setText(res.getString(pageOrder.get(position - 1).titleStringId));
+ indicatorPrev.setVisibility(View.VISIBLE);
+ } else {
+ indicatorPrev.setVisibility(View.GONE);
+ }
+
+ if (position < (pageOrder.size() - 1)) {
+ indicatorNext.setText(res.getString(pageOrder.get(position + 1).titleStringId));
+ indicatorNext.setVisibility(View.VISIBLE);
+ } else {
+ indicatorNext.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ /**
+ * Enum of all possible pages with methods to get the view and a title.
+ */
+ private enum Page {
+ DETAILS(R.string.detail),
+ DESCRIPTION(R.string.cache_description),
+ LOGS(R.string.cache_logs),
+ WAYPOINTS(R.string.cache_waypoints),
+ INVENTORY(R.string.cache_inventory);
+
+ public final int titleStringId;
+
+ private Page(final int titleStringId) {
+ this.titleStringId = titleStringId;
+ }
+ }
+
+ private interface PageViewCreator {
+ /**
+ * Returns a validated view.
+ *
+ * @return
+ */
+ public View getDispatchedView();
+
+ /**
+ * Returns a (maybe cached) view.
+ *
+ * @return
+ */
+ public View getView();
+
+ /**
+ * Handles changed data-sets.
+ */
+ public void notifyDataSetChanged();
+ }
+
+ /**
+ * Creator for details-view.
+ */
+ private class DetailsViewCreator implements PageViewCreator {
+ /**
+ * The main view for this creator
+ */
+ private ScrollView view;
+
+ /**
+ * Reference to the details list, so that the helper-method can access it without an additional argument
+ */
+ private LinearLayout detailsList;
+
+ // TODO Do we need this thread-references?
+ private StoreCacheThread storeThread;
+ private RefreshCacheThread refreshThread;
+ private Thread watchlistThread;
+
+ @Override
+ public void notifyDataSetChanged() {
+ // There is a lot of data in this view, let's update everything
+ view = null;
+ }
+
+ @Override
+ public View getView() {
+ if (view == null) {
+ view = (ScrollView) getDispatchedView();
+ }
+
+ return view;
+ }
+
+ @Override
+ public View getDispatchedView() {
+ if (cache == null) {
+ // something is really wrong
+ return null;
+ }
+
+ view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_details, null);
+
+ detailsList = (LinearLayout) view.findViewById(R.id.details_list);
+
+ // cache name (full name)
+ Spannable span = (new Spannable.Factory()).newSpannable(Html.fromHtml(cache.getName()).toString());
+ if (cache.isDisabled() || cache.isArchived()) { // strike
+ span.setSpan(new StrikethroughSpan(), 0, span.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ addCacheDetail(R.string.cache_name, span);
+
+ // cache type
+ addCacheDetail(R.string.cache_type, cache.getType().getL10n());
+
+ // size
+ if (null != cache.getSize() && cache.showSize()) {
+ addCacheDetail(R.string.cache_size, cache.getSize().getL10n());
+ }
+
+ // gc-code
+ addCacheDetail(R.string.cache_geocode, cache.getGeocode().toUpperCase());
+
+ // cache state
+ if (cache.isLogOffline() || cache.isArchived() || cache.isDisabled() || cache.isMembers() || cache.isFound()) {
+ final StringBuilder state = new StringBuilder();
+ if (cache.isLogOffline()) {
+ state.append(res.getString(R.string.cache_status_offline_log));
+ }
+ if (cache.isFound()) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_found));
+ }
+ if (cache.isArchived()) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_archived));
+ }
+ if (cache.isDisabled()) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_disabled));
+ }
+ if (cache.isMembers()) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_premium));
+ }
+
+ addCacheDetail(R.string.cache_status, state.toString());
+ }
+
+ // distance
+ cacheDistanceView = addCacheDetail(R.string.cache_distance, cache.getDistance() != null ? "~" + cgBase.getHumanDistance(cache.getDistance()) : "--");
+
+ // difficulty
+ if (cache.getDifficulty() != null && cache.getDifficulty() > 0) {
+ addStarRating(R.string.cache_difficulty, cache.getDifficulty());
+ }
+
+ // terrain
+ if (cache.getTerrain() != null && cache.getTerrain() > 0) {
+ addStarRating(R.string.cache_terrain, cache.getTerrain());
+ }
+
+ // rating
+ if (cache.getRating() != null && cache.getRating() > 0) {
+ final RelativeLayout itemLayout = addStarRating(R.string.cache_rating, cache.getRating());
+ if (cache.getVotes() != null) {
+ final TextView itemAddition = (TextView) itemLayout.findViewById(R.id.addition);
+ itemAddition.setText("(" + cache.getVotes() + ")");
+ itemAddition.setVisibility(View.VISIBLE);
+ }
+ }
+
+ // favourite count
+ if (cache.getFavouriteCnt() != null) {
+ addCacheDetail(R.string.cache_favourite, String.format("%d", cache.getFavouriteCnt()) + "×");
+ }
+
+ // cache author
+ if (StringUtils.isNotBlank(cache.getOwner()) || StringUtils.isNotBlank(cache.getOwnerReal())) {
+ TextView ownerView = addCacheDetail(R.string.cache_owner, "");
+ if (StringUtils.isNotBlank(cache.getOwner())) {
+ ownerView.setText(Html.fromHtml(cache.getOwner()), TextView.BufferType.SPANNABLE);
+ } else if (StringUtils.isNotBlank(cache.getOwnerReal())) {
+ ownerView.setText(Html.fromHtml(cache.getOwnerReal()), TextView.BufferType.SPANNABLE);
+ }
+ ownerView.setOnClickListener(new UserActionsClickListener());
+ }
+
+ // cache hidden
+ if (cache.getHiddenDate() != null && cache.getHiddenDate().getTime() > 0) {
+ addCacheDetail(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, cgBase.formatFullDate(cache.getHiddenDate().getTime()));
+ }
+
+ // cache location
+ if (StringUtils.isNotBlank(cache.getLocation())) {
+ addCacheDetail(R.string.cache_location, cache.getLocation());
+ }
+
+ // cache coordinates
+ if (cache.getCoords() != null) {
+ addCacheDetail(R.string.cache_coordinates, cache.getCoords().toString())
+ .setOnClickListener(new View.OnClickListener() {
+ private int position = 0;
+ private GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] {
+ GeopointFormatter.Format.LAT_LON_DECMINUTE,
+ GeopointFormatter.Format.LAT_LON_DECSECOND,
+ GeopointFormatter.Format.LAT_LON_DECDEGREE
+ };
+
+ // rotate coordinate formats on click
+ @Override
+ public void onClick(View view) {
+ position = (position + 1) % availableFormats.length;
+
+ final TextView valueView = (TextView) view.findViewById(R.id.value);
+ valueView.setText(cache.getCoords().format(availableFormats[position]));
+ }
+ });
+ }
+
+ updateOfflineBox();
+
+ // watchlist
+ Button buttonWatchlistAdd = (Button) view.findViewById(R.id.add_to_watchlist);
+ Button buttonWatchlistRemove = (Button) view.findViewById(R.id.remove_from_watchlist);
+ buttonWatchlistAdd.setOnClickListener(new AddToWatchlistClickListener());
+ buttonWatchlistRemove.setOnClickListener(new RemoveFromWatchlistClickListener());
+ updateWatchlistBox();
+
+ // data license
+ IConnector connector = ConnectorFactory.getConnector(cache);
+ if (connector != null) {
+ String license = connector.getLicenseText(cache);
+ if (StringUtils.isNotBlank(license)) {
+ ((LinearLayout) view.findViewById(R.id.license_box)).setVisibility(View.VISIBLE);
+ TextView licenseView = ((TextView) view.findViewById(R.id.license));
+ licenseView.setText(Html.fromHtml(license), BufferType.SPANNABLE);
+ licenseView.setClickable(true);
+ licenseView.setMovementMethod(LinkMovementMethod.getInstance());
+ } else {
+ ((LinearLayout) view.findViewById(R.id.license_box)).setVisibility(View.GONE);
+ }
+ }
+
+ if (geolocation != null) {
+ locationUpdater.updateLoc(geolocation);
+ }
+
+ return view;
+ }
+
+ private TextView addCacheDetail(final int nameId, final CharSequence value) {
+ final RelativeLayout layout = (RelativeLayout) getLayoutInflater().inflate(R.layout.cache_item, null);
+ ((TextView) layout.findViewById(R.id.name)).setText(res.getString(nameId));
+ final TextView valueView = (TextView) layout.findViewById(R.id.value);
+ valueView.setText(value);
+ detailsList.addView(layout);
+ return valueView;
+ }
+
+ private RelativeLayout addStarRating(final int nameId, final float value) {
+ final RelativeLayout layout = (RelativeLayout) getLayoutInflater().inflate(R.layout.cache_layout, null);
+ TextView viewName = (TextView) layout.findViewById(R.id.name);
+ TextView viewValue = (TextView) layout.findViewById(R.id.value);
+ LinearLayout layoutStars = (LinearLayout) layout.findViewById(R.id.stars);
+
+ viewName.setText(res.getString(nameId));
+ viewValue.setText(String.format("%.1f", value) + ' ' + res.getString(R.string.cache_rating_of) + " 5");
+ layoutStars.addView(cgBase.createStarRating(value, 5, CacheDetailActivity.this), 1);
+
+ detailsList.addView(layout);
+ return layout;
+ }
+
+ private class StoreCacheHandler extends CancellableHandler {
+ @Override
+ public void handleRegularMessage(Message msg) {
+ storeThread = null;
+
+ try {
+ cache = app.getCache(search); // reload cache details
+ } catch (Exception e) {
+ showToast(res.getString(R.string.err_store_failed));
+
+ Log.e(Settings.tag, "CacheDetailActivity.storeCacheHandler: " + e.toString());
+ }
+
+ CacheDetailActivity.this.notifyDataSetChanged();
+ }
+ }
+
+ private class RefreshCacheHandler extends CancellableHandler {
+ @Override
+ public void handleRegularMessage(Message msg) {
+ refreshThread = null;
+
+ try {
+ cache = app.getCache(search); // reload cache details
+ } catch (Exception e) {
+ showToast(res.getString(R.string.err_refresh_failed));
+
+ Log.e(Settings.tag, "CacheDetailActivity.refreshCacheHandler: " + e.toString());
+ }
+
+ CacheDetailActivity.this.notifyDataSetChanged();
+ }
+ }
+
+ private class DropCacheHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ CacheDetailActivity.this.notifyDataSetChanged();
+ }
+ }
+
+ private class StoreCacheClickListener implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (progress.isShowing()) {
+ showToast(res.getString(R.string.err_detail_still_working));
+ return;
+ }
+
+ final StoreCacheHandler storeCacheHandler = new StoreCacheHandler();
+
+ progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true, storeCacheHandler.cancelMessage());
+
+ if (storeThread != null) {
+ storeThread.interrupt();
+ }
+
+ storeThread = new StoreCacheThread(storeCacheHandler);
+ storeThread.start();
+ }
+ }
+
+ private class RefreshCacheClickListener implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (progress.isShowing()) {
+ showToast(res.getString(R.string.err_detail_still_working));
+ return;
+ }
+
+ final RefreshCacheHandler refreshCacheHandler = new RefreshCacheHandler();
+
+ progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true, refreshCacheHandler.cancelMessage());
+
+ if (refreshThread != null) {
+ refreshThread.interrupt();
+ }
+
+ refreshThread = new RefreshCacheThread(refreshCacheHandler);
+ refreshThread.start();
+ }
+ }
+
+ private class StoreCacheThread extends Thread {
+ final private CancellableHandler handler;
+
+ public StoreCacheThread(final CancellableHandler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ int reason = cache.getReason() > 1 ? cache.getReason() : 1;
+ cgBase.storeCache(app, CacheDetailActivity.this, cache, null, reason, handler);
+ }
+ }
+
+ private class RefreshCacheThread extends Thread {
+ final private CancellableHandler handler;
+
+ public RefreshCacheThread(final CancellableHandler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ app.removeCacheFromCache(cache.getGeocode());
+ search = cgBase.searchByGeocode(cache.getGeocode(), null, 0, true, handler);
+
+ handler.sendEmptyMessage(0);
+ }
+ }
+
+ private class DropCacheClickListener implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (progress.isShowing()) {
+ showToast(res.getString(R.string.err_detail_still_working));
+ return;
+ }
+
+ final DropCacheHandler dropCacheHandler = new DropCacheHandler();
+
+ progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true, null);
+ new DropCacheThread(dropCacheHandler).start();
+ }
+ }
+
+ private class DropCacheThread extends Thread {
+
+ private Handler handler = null;
+
+ public DropCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ cgBase.dropCache(app, cache, handler);
+ }
+ }
+
+ /**
+ * Abstract Listener for add / remove buttons for watchlist
+ */
+ private abstract class AbstractWatchlistClickListener implements View.OnClickListener {
+ public void doExecute(int titleId, int messageId, Thread thread) {
+ if (progress.isShowing()) {
+ showToast(res.getString(R.string.err_watchlist_still_managing));
+ return;
+ }
+ progress.show(CacheDetailActivity.this, res.getString(titleId), res.getString(messageId), true, null);
+
+ if (watchlistThread != null) {
+ watchlistThread.interrupt();
+ }
+
+ watchlistThread = thread;
+ watchlistThread.start();
+ }
+ }
+
+ /**
+ * Listener for "add to watchlist" button
+ */
+ private class AddToWatchlistClickListener extends AbstractWatchlistClickListener {
+ public void onClick(View arg0) {
+ doExecute(R.string.cache_dialog_watchlist_add_title,
+ R.string.cache_dialog_watchlist_add_message,
+ new WatchlistAddThread(new WatchlistHandler()));
+ }
+ }
+
+ /**
+ * Listener for "remove from watchlist" button
+ */
+ private class RemoveFromWatchlistClickListener extends AbstractWatchlistClickListener {
+ public void onClick(View arg0) {
+ doExecute(R.string.cache_dialog_watchlist_remove_title,
+ R.string.cache_dialog_watchlist_remove_message,
+ new WatchlistRemoveThread(new WatchlistHandler()));
+ }
+ }
+
+ /** Thread to add this cache to the watchlist of the user */
+ private class WatchlistAddThread extends Thread {
+ private final Handler handler;
+
+ public WatchlistAddThread(Handler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ handler.sendEmptyMessage(cgBase.addToWatchlist(cache));
+ }
+ }
+
+ /** Thread to remove this cache from the watchlist of the user */
+ private class WatchlistRemoveThread extends Thread {
+ private final Handler handler;
+
+ public WatchlistRemoveThread(Handler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ handler.sendEmptyMessage(cgBase.removeFromWatchlist(cache));
+ }
+ }
+
+ /**
+ * shows/hides buttons, sets text in watchlist box
+ */
+ private void updateWatchlistBox() {
+ LinearLayout layout = (LinearLayout) view.findViewById(R.id.watchlist_box);
+ boolean supportsWatchList = cache.supportsWatchList();
+ layout.setVisibility(supportsWatchList ? View.VISIBLE : View.GONE);
+ if (!supportsWatchList) {
+ return;
+ }
+ Button buttonAdd = (Button) view.findViewById(R.id.add_to_watchlist);
+ Button buttonRemove = (Button) view.findViewById(R.id.remove_from_watchlist);
+ TextView text = (TextView) view.findViewById(R.id.watchlist_text);
+
+ if (cache.isOnWatchlist()) {
+ buttonAdd.setVisibility(View.GONE);
+ buttonRemove.setVisibility(View.VISIBLE);
+ text.setText(R.string.cache_watchlist_on);
+ } else {
+ buttonAdd.setVisibility(View.VISIBLE);
+ buttonRemove.setVisibility(View.GONE);
+ text.setText(R.string.cache_watchlist_not_on);
+ }
+ }
+
+ /**
+ * Handler, called when watchlist add or remove is done
+ */
+ private class WatchlistHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ watchlistThread = null;
+ progress.dismiss();
+ if (msg.what == -1) {
+ showToast(res.getString(R.string.err_watchlist_failed));
+ } else {
+ updateWatchlistBox();
+ }
+ }
+ }
+
+ private void updateOfflineBox() {
+ // offline use
+ final TextView offlineText = (TextView) view.findViewById(R.id.offline_text);
+ final Button offlineRefresh = (Button) view.findViewById(R.id.offline_refresh);
+ final Button offlineStore = (Button) view.findViewById(R.id.offline_store);
+
+ if (cache.getReason() >= 1) {
+ Long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes
+
+ String ago = "";
+ if (diff < 15) {
+ ago = res.getString(R.string.cache_offline_time_mins_few);
+ } else if (diff < 50) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + diff + " " + res.getString(R.string.cache_offline_time_mins);
+ } else if (diff < 90) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + res.getString(R.string.cache_offline_time_hour);
+ } else if (diff < (48 * 60)) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / 60) + " " + res.getString(R.string.cache_offline_time_hours);
+ } else {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / (24 * 60)) + " " + res.getString(R.string.cache_offline_time_days);
+ }
+
+ offlineText.setText(res.getString(R.string.cache_offline_stored) + "\n" + ago);
+ offlineRefresh.setOnClickListener(new StoreCacheClickListener());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_drop));
+ offlineStore.setClickable(true);
+ offlineStore.setOnClickListener(new DropCacheClickListener());
+ } else {
+ offlineText.setText(res.getString(R.string.cache_offline_not_ready));
+ offlineRefresh.setOnClickListener(new RefreshCacheClickListener());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_store));
+ offlineStore.setClickable(true);
+ offlineStore.setOnClickListener(new StoreCacheClickListener());
+ }
+ offlineRefresh.setVisibility(cache.supportsRefresh() ? View.VISIBLE : View.GONE);
+ offlineRefresh.setClickable(true);
+ }
+ }
+
+ private class DescriptionViewCreator implements PageViewCreator {
+
+ private ViewGroup attributeIconsLayout; // layout for attribute icons
+ private ViewGroup attributeDescriptionsLayout; // layout for attribute descriptions
+ private boolean attributesShowAsIcons = true; // default: show icons
+ /**
+ * True, if the cache was imported with an older version of c:geo.
+ * These older versions parsed the attribute description from the tooltip in the web
+ * page and put them into the DB. No icons can be matched for these.
+ */
+ private boolean noAttributeIconsFound = false;
+ private int attributeBoxMaxWidth;
+
+ ScrollView view;
+
+ @Override
+ public void notifyDataSetChanged() {
+ view = null;
+ }
+
+ @Override
+ public View getView() {
+ if (view == null) {
+ view = (ScrollView) getDispatchedView();
+ }
+
+ return view;
+ }
+
+ @Override
+ public View getDispatchedView() {
+ if (cache == null) {
+ // something is really wrong
+ return null;
+ }
+
+ view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_description, null);
+
+ // cache short description
+ if (StringUtils.isNotBlank(cache.getShortdesc())) {
+ TextView descView = (TextView) view.findViewById(R.id.shortdesc);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(Html.fromHtml(cache.getShortdesc().trim(), new HtmlImage(CacheDetailActivity.this, cache.getGeocode(), true, cache.getReason(), false), null), TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ // long description
+ if (StringUtils.isNotBlank(cache.getDescription())) {
+ if (Settings.isAutoLoadDescription()) {
+ loadLongDescription();
+ } else {
+ Button showDesc = (Button) view.findViewById(R.id.show_description);
+ showDesc.setVisibility(View.VISIBLE);
+ showDesc.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View arg0) {
+ loadLongDescription();
+ }
+ });
+ }
+ }
+
+ // cache attributes
+ if (CollectionUtils.isNotEmpty(cache.getAttributes())) {
+
+ final LinearLayout attribBox = (LinearLayout) view.findViewById(R.id.attributes_innerbox);
+
+ // maximum width for attribute icons is screen width - paddings of parents
+ attributeBoxMaxWidth = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay().getWidth();
+ ViewParent child = attribBox;
+ do {
+ if (child instanceof View) {
+ attributeBoxMaxWidth = attributeBoxMaxWidth - ((View) child).getPaddingLeft()
+ - ((View) child).getPaddingRight();
+ }
+ child = child.getParent();
+ } while (child != null);
+
+ // delete views holding description / icons
+ attributeDescriptionsLayout = null;
+ attributeIconsLayout = null;
+
+ attribBox.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // toggle between attribute icons and descriptions
+ toggleAttributeDisplay(attribBox, attributeBoxMaxWidth);
+ }
+ });
+
+ // icons or text?
+ //
+ // also show icons when noAttributeImagesFound == true. Explanation:
+ // 1. no icons could be found in the first invocation of this method
+ // 2. user refreshes cache from web
+ // 3. now this method is called again
+ // 4. attributeShowAsIcons is false but noAttributeImagesFound is true
+ // => try to show them now
+ if (attributesShowAsIcons || noAttributeIconsFound) {
+ showAttributeIcons(attribBox, attributeBoxMaxWidth);
+ } else {
+ showAttributeDescriptions(attribBox);
+ }
+
+ view.findViewById(R.id.attributes_box).setVisibility(View.VISIBLE);
+ }
+
+ // cache personal note
+ if (StringUtils.isNotBlank(cache.getPersonalNote())) {
+ ((LinearLayout) view.findViewById(R.id.personalnote_box)).setVisibility(View.VISIBLE);
+
+ TextView personalNoteText = (TextView) view.findViewById(R.id.personalnote);
+ personalNoteText.setVisibility(View.VISIBLE);
+ personalNoteText.setText(cache.getPersonalNote(), TextView.BufferType.SPANNABLE);
+ personalNoteText.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ else {
+ ((LinearLayout) view.findViewById(R.id.personalnote_box)).setVisibility(View.GONE);
+ }
+
+ // cache hint and spoiler images
+ if (StringUtils.isNotBlank(cache.getHint()) || CollectionUtils.isNotEmpty(cache.getSpoilers())) {
+ ((LinearLayout) view.findViewById(R.id.hint_box)).setVisibility(View.VISIBLE);
+ } else {
+ ((LinearLayout) view.findViewById(R.id.hint_box)).setVisibility(View.GONE);
+ }
+
+ if (StringUtils.isNotBlank(cache.getHint())) {
+ TextView hintView = ((TextView) view.findViewById(R.id.hint));
+ hintView.setText(CryptUtils.rot13(cache.getHint().trim()));
+ hintView.setVisibility(View.VISIBLE);
+ hintView.setClickable(true);
+ hintView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // code hint
+ TextView hintView = (TextView) view;
+ hintView.setText(CryptUtils.rot13(hintView.getText().toString()));
+ }
+ });
+ } else {
+ TextView hintView = ((TextView) view.findViewById(R.id.hint));
+ hintView.setVisibility(View.GONE);
+ hintView.setClickable(false);
+ hintView.setOnClickListener(null);
+ }
+
+ if (CollectionUtils.isNotEmpty(cache.getSpoilers())) {
+ TextView spoilerlinkView = ((TextView) view.findViewById(R.id.hint_spoilerlink));
+ spoilerlinkView.setVisibility(View.VISIBLE);
+ spoilerlinkView.setClickable(true);
+ spoilerlinkView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ if (cache == null || CollectionUtils.isEmpty(cache.getSpoilers())) {
+ showToast(res.getString(R.string.err_detail_no_spoiler));
+ return;
+ }
+
+ cgeoimages.startActivitySpoilerImages(CacheDetailActivity.this, cache.getGeocode(), cache.getSpoilers());
+ }
+ });
+ } else {
+ TextView spoilerlinkView = ((TextView) view.findViewById(R.id.hint_spoilerlink));
+ spoilerlinkView.setVisibility(View.GONE);
+ spoilerlinkView.setClickable(true);
+ spoilerlinkView.setOnClickListener(null);
+ }
+
+ return view;
+ }
+
+ private void loadLongDescription() {
+ Button showDesc = (Button) view.findViewById(R.id.show_description);
+ showDesc.setVisibility(View.GONE);
+ showDesc.setOnClickListener(null);
+ view.findViewById(R.id.loading).setVisibility(View.VISIBLE);
+
+ new LoadLongDescriptionThread(new LoadLongDescriptionHandler()).start();
+ }
+
+ private class LoadLongDescriptionHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ Spanned longDesc = (Spanned) msg.obj;
+
+ if (longDesc != null) {
+ TextView descView = (TextView) view.findViewById(R.id.longdesc);
+ if (StringUtils.isNotBlank(cache.getDescription())) {
+ descView.setText(longDesc, TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ // handle caches with black font color
+ if (!Settings.isLightSkin()) {
+ if (cache.getDescription().contains("color=\"#000000")) {
+ descView.setBackgroundResource(color.darker_gray);
+ }
+ else {
+ descView.setBackgroundResource(color.black);
+ }
+ }
+ }
+
+ descView.setVisibility(View.VISIBLE);
+ } else {
+ showToast(res.getString(R.string.err_load_descr_failed));
+ }
+
+ view.findViewById(R.id.loading).setVisibility(View.GONE);
+ }
+ }
+
+ private class LoadLongDescriptionThread extends Thread {
+ private Handler handler = null;
+
+ public LoadLongDescriptionThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ Spanned longDesc = Html.fromHtml(cache.getDescription().trim(), new HtmlImage(CacheDetailActivity.this, cache.getGeocode(), true, cache.getReason(), false), new UnknownTagsHandler());
+
+ handler.obtainMessage(0, longDesc).sendToTarget();
+ }
+ }
+
+ /**
+ * lazy-creates the layout holding the icons of the chaches attributes
+ * and makes it visible
+ */
+ private void showAttributeIcons(LinearLayout attribBox, int parentWidth) {
+ if (attributeIconsLayout == null) {
+ attributeIconsLayout = createAttributeIconsLayout(parentWidth);
+ // no matching icons found? show text
+ if (noAttributeIconsFound) {
+ showAttributeDescriptions(attribBox);
+ return;
+ }
+ }
+ attribBox.removeAllViews();
+ attribBox.addView(attributeIconsLayout);
+ attributesShowAsIcons = true;
+ }
+
+ /**
+ * lazy-creates the layout holding the discriptions of the chaches attributes
+ * and makes it visible
+ */
+ private void showAttributeDescriptions(LinearLayout attribBox) {
+ if (attributeDescriptionsLayout == null) {
+ attributeDescriptionsLayout = createAttributeDescriptionsLayout();
+ }
+ attribBox.removeAllViews();
+ attribBox.addView(attributeDescriptionsLayout);
+ attributesShowAsIcons = false;
+ }
+
+ /**
+ * toggle attribute descriptions and icons
+ */
+ private void toggleAttributeDisplay(LinearLayout attribBox, int parentWidth) {
+ // Don't toggle when there are no icons to show.
+ if (noAttributeIconsFound) {
+ return;
+ }
+
+ // toggle
+ if (attributesShowAsIcons) {
+ showAttributeDescriptions(attribBox);
+ } else {
+ showAttributeIcons(attribBox, parentWidth);
+ }
+ }
+
+ private ViewGroup createAttributeIconsLayout(int parentWidth) {
+ LinearLayout rows = new LinearLayout(CacheDetailActivity.this);
+ rows.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
+ rows.setOrientation(LinearLayout.VERTICAL);
+
+ LinearLayout attributeRow = newAttributeIconsRow();
+ rows.addView(attributeRow);
+
+ noAttributeIconsFound = true;
+
+ final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName();
+ for (String attributeName : cache.getAttributes()) {
+ boolean strikethru = attributeName.endsWith("_no");
+ // cut off _yes / _no
+ if (attributeName.endsWith("_no") || attributeName.endsWith("_yes")) {
+ attributeName = attributeName.substring(0, attributeName.lastIndexOf("_"));
+ }
+ // check if another attribute icon fits in this row
+ attributeRow.measure(0, 0);
+ int rowWidth = attributeRow.getMeasuredWidth();
+ FrameLayout fl = (FrameLayout) getLayoutInflater().inflate(R.layout.attribute_image, null);
+ ImageView iv = (ImageView) fl.getChildAt(0);
+ if ((parentWidth - rowWidth) < iv.getLayoutParams().width) {
+ // make a new row
+ attributeRow = newAttributeIconsRow();
+ rows.addView(attributeRow);
+ }
+
+ // dynamically search icon of the attribute
+ Drawable d = null;
+ int id = res.getIdentifier("attribute_" + attributeName, "drawable", packageName);
+ if (id > 0) {
+ noAttributeIconsFound = false;
+ d = res.getDrawable(id);
+ iv.setImageDrawable(d);
+ // strike through?
+ if (strikethru) {
+ // generate strikethru image with same properties as attribute image
+ ImageView strikethruImage = new ImageView(CacheDetailActivity.this);
+ strikethruImage.setLayoutParams(iv.getLayoutParams());
+ d = res.getDrawable(R.drawable.attribute__strikethru);
+ strikethruImage.setImageDrawable(d);
+ fl.addView(strikethruImage);
+ }
+ } else {
+ d = res.getDrawable(R.drawable.attribute_icon_not_found);
+ iv.setImageDrawable(d);
+ }
+
+ attributeRow.addView(fl);
+ }
+
+ return rows;
+ }
+
+ private LinearLayout newAttributeIconsRow() {
+ LinearLayout rowLayout = new LinearLayout(CacheDetailActivity.this);
+ rowLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ rowLayout.setOrientation(LinearLayout.HORIZONTAL);
+ return rowLayout;
+ }
+
+ private ViewGroup createAttributeDescriptionsLayout() {
+ final LinearLayout descriptions = (LinearLayout) getLayoutInflater().inflate(
+ R.layout.attribute_descriptions, null);
+ TextView attribView = (TextView) descriptions.getChildAt(0);
+
+ StringBuilder buffer = new StringBuilder();
+ String attribute;
+ final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName();
+ for (int i = 0; i < cache.getAttributes().size(); i++) {
+ attribute = cache.getAttributes().get(i);
+
+ // dynamically search for a translation of the attribute
+ int id = res.getIdentifier("attribute_" + attribute, "string", packageName);
+ if (id > 0) {
+ String translated = res.getString(id);
+ if (StringUtils.isNotBlank(translated)) {
+ attribute = translated;
+ }
+ }
+ if (buffer.length() > 0) {
+ buffer.append('\n');
+ }
+ buffer.append(attribute);
+ }
+
+ if (noAttributeIconsFound) {
+ buffer.append("\n\n").append(res.getString(R.string.cache_attributes_no_icons));
+ }
+
+ attribView.setText(buffer);
+
+ return descriptions;
+ }
+ }
+
+ private class LogsViewCreator implements PageViewCreator {
+
+ ScrollView view;
+
+ @Override
+ public void notifyDataSetChanged() {
+ view = null;
+ }
+
+ @Override
+ public View getView() {
+ if (view == null) {
+ view = (ScrollView) getDispatchedView();
+ }
+
+ return view;
+ }
+
+ @Override
+ public View getDispatchedView() {
+ if (cache == null) {
+ // something is really wrong
+ return null;
+ }
+
+ view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_logs, null);
+
+ TextView logCounterView = (TextView) view.findViewById(R.id.log_count);
+ int logCounter = 0;
+ if (cache != null && cache.getLogCounts() != null) {
+ final StringBuilder text = new StringBuilder();
+ text.append(res.getString(R.string.cache_log_types));
+ text.append(": ");
+
+ // sort the log counts by type id ascending. that way the FOUND, DNF log types are the first and most visible ones
+ List<Entry<Integer, Integer>> sortedLogCounts = new ArrayList<Entry<Integer, Integer>>();
+ sortedLogCounts.addAll(cache.getLogCounts().entrySet());
+ Collections.sort(sortedLogCounts, new Comparator<Entry<Integer, Integer>>() {
+
+ @Override
+ public int compare(Entry<Integer, Integer> logCountItem1,
+ Entry<Integer, Integer> logCountItem2) {
+ return logCountItem1.getKey().compareTo(logCountItem2.getKey());
+ }
+ });
+ for (Entry<Integer, Integer> pair : sortedLogCounts) {
+ int logTypeId = pair.getKey().intValue();
+ String logTypeLabel = cgBase.logTypes1.get(logTypeId);
+ // it may happen that the label is unknown -> then avoid any output for this type
+ if (logTypeLabel != null) {
+ if (logCounter > 0) {
+ text.append(", ");
+ }
+ text.append(pair.getValue().intValue());
+ text.append("× ");
+ text.append(logTypeLabel);
+ }
+ logCounter++;
+ }
+ logCounterView.setText(text.toString());
+ }
+ // it may happen, that the logCounts map is available, but every log type has zero counts,
+ // therefore check again for the number of counted logs
+ if (logCounter > 0) {
+ logCounterView.setVisibility(View.VISIBLE);
+ } else {
+ logCounterView.setVisibility(View.GONE);
+ }
+
+ // cache logs
+ LinearLayout logListView = (LinearLayout) view.findViewById(R.id.log_list);
+
+ RelativeLayout rowView;
+
+ if (cache != null && cache.getLogs() != null) {
+ for (cgLog log : cache.getLogs()) {
+ rowView = (RelativeLayout) getLayoutInflater().inflate(R.layout.log_item, null);
+
+ if (log.date > 0) {
+ ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.formatShortDate(log.date));
+ } else {
+ ((TextView) rowView.findViewById(R.id.added)).setVisibility(View.GONE);
+ }
+
+ if (cgBase.logTypes1.containsKey(log.type)) {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(log.type));
+ } else {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(4)); // note if type is unknown
+ }
+ ((TextView) rowView.findViewById(R.id.author)).setText(StringEscapeUtils.unescapeHtml4(log.author));
+
+ if (log.found == -1) {
+ ((TextView) rowView.findViewById(R.id.count)).setVisibility(View.GONE);
+ } else if (log.found == 0) {
+ ((TextView) rowView.findViewById(R.id.count)).setText(res.getString(R.string.cache_count_no));
+ } else if (log.found == 1) {
+ ((TextView) rowView.findViewById(R.id.count)).setText(res.getString(R.string.cache_count_one));
+ } else {
+ ((TextView) rowView.findViewById(R.id.count)).setText(log.found + " " + res.getString(R.string.cache_count_more));
+ }
+ // avoid parsing HTML if not necessary
+ if (BaseUtils.containsHtml(log.log)) {
+ ((TextView) rowView.findViewById(R.id.log)).setText(Html.fromHtml(log.log, new HtmlImage(CacheDetailActivity.this, null, false, cache.getReason(), false), null), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) rowView.findViewById(R.id.log)).setText(log.log);
+ }
+ // add LogImages
+ LinearLayout logLayout = (LinearLayout) rowView.findViewById(R.id.log_layout);
+
+ if (CollectionUtils.isNotEmpty(log.logImages)) {
+
+ final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.logImages);
+
+ final View.OnClickListener listener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ cgeoimages.startActivityLogImages(CacheDetailActivity.this, cache.getGeocode(), logImages);
+ }
+ };
+
+ ArrayList<String> titles = new ArrayList<String>();
+ for (int i_img_cnt = 0; i_img_cnt < log.logImages.size(); i_img_cnt++) {
+ String img_title = log.logImages.get(i_img_cnt).getTitle();
+ if (!StringUtils.isBlank(img_title)) {
+ titles.add(img_title);
+ }
+ }
+ if (titles.isEmpty()) {
+ titles.add(res.getString(R.string.cache_log_image_default_title));
+ }
+
+ LinearLayout log_imgView = (LinearLayout) getLayoutInflater().inflate(R.layout.log_img, null);
+ TextView log_img_title = (TextView) log_imgView.findViewById(R.id.title);
+ log_img_title.setText(StringUtils.join(titles.toArray(new String[titles.size()]), ", "));
+ log_img_title.setOnClickListener(listener);
+ logLayout.addView(log_imgView);
+ }
+
+ // Add colored mark
+ final ImageView logMark = (ImageView) rowView.findViewById(R.id.log_mark);
+ if (log.type == cgBase.LOG_FOUND_IT
+ || log.type == cgBase.LOG_WEBCAM_PHOTO_TAKEN
+ || log.type == cgBase.LOG_ATTENDED) {
+ logMark.setImageResource(R.drawable.mark_green);
+ } else if (log.type == cgBase.LOG_PUBLISH_LISTING
+ || log.type == cgBase.LOG_ENABLE_LISTING
+ || log.type == cgBase.LOG_OWNER_MAINTENANCE) {
+ logMark.setImageResource(R.drawable.mark_green_more);
+ } else if (log.type == cgBase.LOG_DIDNT_FIND_IT
+ || log.type == cgBase.LOG_NEEDS_MAINTENANCE
+ || log.type == cgBase.LOG_NEEDS_ARCHIVE) {
+ logMark.setImageResource(R.drawable.mark_red);
+ } else if (log.type == cgBase.LOG_TEMP_DISABLE_LISTING
+ || log.type == cgBase.LOG_ARCHIVE) {
+ logMark.setImageResource(R.drawable.mark_red_more);
+ } else {
+ logMark.setVisibility(View.GONE);
+ }
+
+ ((TextView) rowView.findViewById(R.id.author)).setOnClickListener(new UserActionsClickListener());
+ ((TextView) logLayout.findViewById(R.id.log)).setOnClickListener(new DecryptLogClickListener());
+
+ logListView.addView(rowView);
+ }
+ }
+
+ return view;
+ }
+
+ private class DecryptLogClickListener implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+
+ try {
+ final TextView logView = (TextView) view;
+ CharSequence text = logView.getText();
+ if (text instanceof Spannable) {
+ Spannable span = (Spannable) text;
+ logView.setText(CryptUtils.rot13(span));
+ }
+ else {
+ String string = (String) text;
+ logView.setText(CryptUtils.rot13(string));
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+ }
+
+ private class WaypointsViewCreator implements PageViewCreator {
+
+ ScrollView view;
+
+ @Override
+ public void notifyDataSetChanged() {
+ view = null;
+ }
+
+ @Override
+ public View getView() {
+ if (view == null) {
+ view = (ScrollView) getDispatchedView();
+ }
+
+ return view;
+ }
+
+ @Override
+ public View getDispatchedView() {
+ if (cache == null) {
+ // something is really wrong
+ return null;
+ }
+
+ view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_waypoints, null);
+
+ LinearLayout waypoints = (LinearLayout) view.findViewById(R.id.waypoints);
+
+ if (CollectionUtils.isNotEmpty(cache.getWaypoints())) {
+ LinearLayout waypointView;
+
+ // sort waypoints: PP, Sx, FI, OWN
+ List<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.getWaypoints());
+ Collections.sort(sortedWaypoints);
+
+ for (cgWaypoint wpt : sortedWaypoints) {
+ waypointView = (LinearLayout) getLayoutInflater().inflate(R.layout.waypoint_item, null);
+
+ final List<String> infoTextList = new ArrayList<String>(3);
+ infoTextList.add(cgBase.waypointTypes.get(wpt.getWaypointType()));
+ if ("OWN".equalsIgnoreCase(wpt.getPrefix())) {
+ infoTextList.add(res.getString(R.string.waypoint_custom));
+ } else {
+ if (StringUtils.isNotBlank(wpt.getPrefix())) {
+ infoTextList.add(wpt.getPrefix());
+ }
+ if (StringUtils.isNotBlank(wpt.getLookup())) {
+ infoTextList.add(wpt.getLookup());
+ }
+ }
+ ((TextView) waypointView.findViewById(R.id.info)).setText(StringUtils.join(infoTextList, " · "));
+
+ TextView nameView = (TextView) waypointView.findViewById(R.id.name);
+ if (StringUtils.isNotBlank(wpt.getName())) {
+ nameView.setText(StringEscapeUtils.unescapeHtml4(wpt.getName()));
+ } else if (null != wpt.getCoords()) {
+ nameView.setText(wpt.getCoords().toString());
+ } else {
+ nameView.setText(res.getString(R.string.waypoint));
+ }
+
+ wpt.setIcon(res, nameView);
+
+ if (StringUtils.isNotBlank(wpt.getNote())) {
+ TextView noteView = (TextView) waypointView.findViewById(R.id.note);
+ noteView.setVisibility(View.VISIBLE);
+ if (BaseUtils.containsHtml(wpt.getNote())) {
+ noteView.setText(Html.fromHtml(wpt.getNote().trim()), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ noteView.setText(wpt.getNote().trim());
+ }
+ }
+
+ waypointView.setOnClickListener(new WaypointInfoClickListener(wpt.getId()));
+ registerForContextMenu(waypointView);
+
+ waypoints.addView(waypointView);
+ }
+ }
+
+ Button addWaypoint = (Button) view.findViewById(R.id.add_waypoint);
+ addWaypoint.setClickable(true);
+ addWaypoint.setOnClickListener(new AddWaypointClickListener());
+
+ return view;
+ }
+
+ private class AddWaypointClickListener implements View.OnClickListener {
+
+ public void onClick(View view) {
+ Intent addWptIntent = new Intent(CacheDetailActivity.this, cgeowaypointadd.class);
+
+ addWptIntent.putExtra("geocode", cache.getGeocode());
+ int wpCount = 0;
+ if (cache.getWaypoints() != null) {
+ wpCount = cache.getWaypoints().size();
+ }
+ addWptIntent.putExtra("count", wpCount);
+
+ startActivity(addWptIntent);
+ refreshOnResume = true;
+ }
+ }
+
+ private class WaypointInfoClickListener implements View.OnClickListener {
+ private int id = -1;
+
+ public WaypointInfoClickListener(int idIn) {
+ id = idIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent waypointIntent = new Intent(CacheDetailActivity.this, cgeowaypoint.class);
+ waypointIntent.putExtra("waypoint", id);
+ waypointIntent.putExtra("geocode", cache.getGeocode());
+ startActivity(waypointIntent);
+ }
+ }
+ }
+
+ private class InventoryViewCreator implements PageViewCreator {
+
+ ListView view;
+
+ @Override
+ public void notifyDataSetChanged() {
+ view = null;
+ }
+
+ @Override
+ public View getView() {
+ if (view == null) {
+ view = (ListView) getDispatchedView();
+ }
+
+ return view;
+ }
+
+ @Override
+ public View getDispatchedView() {
+ if (cache == null) {
+ // something is really wrong
+ return null;
+ }
+
+ view = (ListView) getLayoutInflater().inflate(R.layout.cacheview_inventory, null);
+
+ view.setAdapter(new ArrayAdapter<cgTrackable>(CacheDetailActivity.this, android.R.layout.simple_list_item_1, cache.getInventory()));
+ view.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+ Object selection = arg0.getItemAtPosition(arg2);
+ if (selection instanceof cgTrackable) {
+ cgTrackable trackable = (cgTrackable) selection;
+ cgeotrackable.startActivity(CacheDetailActivity.this, trackable.getGuid(), trackable.getGeocode(), trackable.getName());
+ }
+ }
+ });
+
+ return view;
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/cgCacheListAdapter.java b/main/src/cgeo/geocaching/cgCacheListAdapter.java
index 1fce381..1602f84 100644
--- a/main/src/cgeo/geocaching/cgCacheListAdapter.java
+++ b/main/src/cgeo/geocaching/cgCacheListAdapter.java
@@ -663,7 +663,7 @@ public class cgCacheListAdapter extends ArrayAdapter<cgCache> {
}
// load cache details
- Intent cachesIntent = new Intent(getContext(), cgeodetail.class);
+ Intent cachesIntent = new Intent(getContext(), CacheDetailActivity.class);
cachesIntent.putExtra("geocode", geocode);
cachesIntent.putExtra("name", name);
getContext().startActivity(cachesIntent);
diff --git a/main/src/cgeo/geocaching/cgTrackable.java b/main/src/cgeo/geocaching/cgTrackable.java
index c37d411..bcf3c83 100644
--- a/main/src/cgeo/geocaching/cgTrackable.java
+++ b/main/src/cgeo/geocaching/cgTrackable.java
@@ -1,5 +1,7 @@
package cgeo.geocaching;
+import android.text.Html;
+
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -174,4 +176,16 @@ public class cgTrackable implements ILogable {
this.logs = logs;
}
+ @Override
+ public String toString() {
+ if (null != name) {
+ return Html.fromHtml(name).toString();
+ }
+
+ if (guid != null) {
+ return guid;
+ }
+
+ return "???";
+ }
}
diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java
index 0c9dc90..e24a4bb 100644
--- a/main/src/cgeo/geocaching/cgeo.java
+++ b/main/src/cgeo/geocaching/cgeo.java
@@ -309,7 +309,7 @@ public class cgeo extends AbstractActivity {
String host = "http://coord.info/";
if (scan.toLowerCase().startsWith(host)) {
String geocode = scan.substring(host.length()).trim();
- cgeodetail.startActivity(this, geocode);
+ CacheDetailActivity.startActivity(this, geocode);
}
else {
showToast(res.getString(R.string.unknown_scan));
diff --git a/main/src/cgeo/geocaching/cgeoadvsearch.java b/main/src/cgeo/geocaching/cgeoadvsearch.java
index e0b68f5..5fe84c4 100644
--- a/main/src/cgeo/geocaching/cgeoadvsearch.java
+++ b/main/src/cgeo/geocaching/cgeoadvsearch.java
@@ -118,7 +118,7 @@ public class cgeoadvsearch extends AbstractActivity {
try {
if (gcCodeM.find()) { // GC-code
- final Intent cachesIntent = new Intent(this, cgeodetail.class);
+ final Intent cachesIntent = new Intent(this, CacheDetailActivity.class);
cachesIntent.putExtra("geocode", query.trim().toUpperCase());
startActivity(cachesIntent);
@@ -423,7 +423,7 @@ public class cgeoadvsearch extends AbstractActivity {
return;
}
- cgeodetail.startActivity(this, geocodeText);
+ CacheDetailActivity.startActivity(this, geocodeText);
}
private class findTrackableAction implements TextView.OnEditorActionListener {
diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java
index 40200db..f3b20b7 100644
--- a/main/src/cgeo/geocaching/cgeocaches.java
+++ b/main/src/cgeo/geocaching/cgeocaches.java
@@ -1203,7 +1203,7 @@ public class cgeocaches extends AbstractListActivity {
} else if (id == MENU_LOG_VISIT) {
return getCacheFromAdapter(adapterInfo).logVisit(this);
} else if (id == MENU_CACHE_DETAILS) {
- final Intent cachesIntent = new Intent(this, cgeodetail.class);
+ final Intent cachesIntent = new Intent(this, CacheDetailActivity.class);
final cgCache cache = getCacheFromAdapter(adapterInfo);
cachesIntent.putExtra("geocode", cache.getGeocode().toUpperCase());
cachesIntent.putExtra("name", cache.getName());
diff --git a/main/src/cgeo/geocaching/cgeopopup.java b/main/src/cgeo/geocaching/cgeopopup.java
index 11c8b25..2820448 100644
--- a/main/src/cgeo/geocaching/cgeopopup.java
+++ b/main/src/cgeo/geocaching/cgeopopup.java
@@ -389,7 +389,7 @@ public class cgeopopup extends AbstractActivity {
buttonMore.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
- Intent cachesIntent = new Intent(cgeopopup.this, cgeodetail.class);
+ Intent cachesIntent = new Intent(cgeopopup.this, CacheDetailActivity.class);
cachesIntent.putExtra("geocode", geocode.toUpperCase());
startActivity(cachesIntent);
diff --git a/main/src/cgeo/geocaching/cgeotrackable.java b/main/src/cgeo/geocaching/cgeotrackable.java
index 6258e2b..a7a93e4 100644
--- a/main/src/cgeo/geocaching/cgeotrackable.java
+++ b/main/src/cgeo/geocaching/cgeotrackable.java
@@ -168,7 +168,7 @@ public class cgeotrackable extends AbstractActivity {
if (cgTrackable.SPOTTED_CACHE == trackable.getSpottedType()) {
itemLayout.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
- Intent cacheIntent = new Intent(cgeotrackable.this, cgeodetail.class);
+ Intent cacheIntent = new Intent(cgeotrackable.this, CacheDetailActivity.class);
cacheIntent.putExtra("guid", trackable.getSpottedGuid());
cacheIntent.putExtra("name", trackable.getSpottedName());
startActivity(cacheIntent);
@@ -506,7 +506,7 @@ public class cgeotrackable extends AbstractActivity {
final String cacheName = log.cacheName;
((TextView) rowView.findViewById(R.id.location)).setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
- Intent cacheIntent = new Intent(cgeotrackable.this, cgeodetail.class);
+ Intent cacheIntent = new Intent(cgeotrackable.this, CacheDetailActivity.class);
cacheIntent.putExtra("guid", cacheGuid);
cacheIntent.putExtra("name", Html.fromHtml(cacheName).toString());
startActivity(cacheIntent);
diff --git a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java
index 9306041..c65b4ba 100644
--- a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java
+++ b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.maps;
+import cgeo.geocaching.CacheDetailActivity;
import cgeo.geocaching.Settings;
import cgeo.geocaching.cgeoapplication;
-import cgeo.geocaching.cgeodetail;
import cgeo.geocaching.go4cache.Go4CacheUser;
import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
@@ -143,7 +143,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay {
public void onClick(DialogInterface dialog, int id) {
if (geocode != null) {
- final Intent detailIntent = new Intent(context, cgeodetail.class);
+ final Intent detailIntent = new Intent(context, CacheDetailActivity.class);
detailIntent.putExtra("geocode", geocode);
context.startActivity(detailIntent);
}
diff --git a/main/src/cgeo/geocaching/utils/BaseUtils.java b/main/src/cgeo/geocaching/utils/BaseUtils.java
index 33a4be5..c5aea8a 100644
--- a/main/src/cgeo/geocaching/utils/BaseUtils.java
+++ b/main/src/cgeo/geocaching/utils/BaseUtils.java
@@ -151,4 +151,14 @@ public final class BaseUtils {
return String.valueOf(chars, 0, resultSize);
}
+ /**
+ * Quick and naive check for possible html-content of a string.
+ *
+ * @param str
+ * @return True, if <code>str</code> could contain html
+ */
+ public static boolean containsHtml(final String str) {
+ return str.indexOf('<') != -1 || str.indexOf('&') != -1;
+ }
+
}