diff options
Diffstat (limited to 'main')
58 files changed, 4549 insertions, 1376 deletions
diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml index 17fed31..95bbe8e 100644 --- a/main/AndroidManifest.xml +++ b/main/AndroidManifest.xml @@ -179,6 +179,24 @@ <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="www.geocaching.com" android:pathPrefix="/seek/cache_details.aspx" /> </intent-filter> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="http" android:host="opencaching.de" android:pathPrefix="/OC" /> + </intent-filter> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="http" android:host="www.opencaching.de" android:pathPrefix="/OC" /> + </intent-filter> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="http" android:host="www.opencaching.de" android:pathPrefix="/viewcache.php" /> + </intent-filter> </activity> <activity android:name="cgeo.geocaching.TrackableActivity" @@ -236,5 +254,11 @@ android:name=".speech.SpeechService" android:label="@string/tts_service" > </service> + <activity + android:name=".connector.oc.OCAuthorizationActivity" + android:label="@string/app_name" + android:windowSoftInputMode="stateHidden" + android:configChanges="keyboardHidden|orientation" > + </activity> </application> </manifest> diff --git a/main/build.xml b/main/build.xml index febb4ae..3d611d1 100644 --- a/main/build.xml +++ b/main/build.xml @@ -83,6 +83,12 @@ <copy file="./templates/mapsapikey.xml" todir="./res/values/" overwrite="true"> <filterset refid="build-tokens" /> </copy> + <copy file="./templates/ocde_okapi.xml" todir="./res/values/" overwrite="true"> + <filterset> + <filter token="ocde.okapi.consumer.key" value="${ocde.okapi.consumer.key}"/> + <filter token="ocde.okapi.consumer.secret" value="${ocde.okapi.consumer.secret}"/> + </filterset> + </copy> </target> <!-- diff --git a/main/project/attributes_okapi/AttrGen/.classpath b/main/project/attributes_okapi/AttrGen/.classpath new file mode 100644 index 0000000..18d70f0 --- /dev/null +++ b/main/project/attributes_okapi/AttrGen/.classpath @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/main/project/attributes_okapi/AttrGen/.project b/main/project/attributes_okapi/AttrGen/.project new file mode 100644 index 0000000..cccc238 --- /dev/null +++ b/main/project/attributes_okapi/AttrGen/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>AttrGen</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/main/project/attributes_okapi/AttrGen/.settings/org.eclipse.jdt.core.prefs b/main/project/attributes_okapi/AttrGen/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..8000cd6 --- /dev/null +++ b/main/project/attributes_okapi/AttrGen/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/main/project/attributes_okapi/AttrGen/.settings/org.eclipse.jdt.ui.prefs b/main/project/attributes_okapi/AttrGen/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000..cc7a309 --- /dev/null +++ b/main/project/attributes_okapi/AttrGen/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,54 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=false +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=false +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=true +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_blocks=true +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true diff --git a/main/project/attributes_okapi/AttrGen/build.xml b/main/project/attributes_okapi/AttrGen/build.xml new file mode 100644 index 0000000..e8426f3 --- /dev/null +++ b/main/project/attributes_okapi/AttrGen/build.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<project default="create_run_jar" name="Create Runnable Jar for Project AttrGen"> + <!--this file was created by Eclipse Runnable JAR Export Wizard--> + <!--ANT 1.7 is required --> + <target name="create_run_jar"> + <jar destfile="../genattr.jar" filesetmanifest="mergewithoutmain"> + <manifest> + <attribute name="Main-Class" value="GenerateAttributes"/> + <attribute name="Class-Path" value="."/> + </manifest> + <fileset dir="bin"/> + </jar> + </target> +</project> diff --git a/main/project/attributes_okapi/AttrGen/src/GenerateAttributes.java b/main/project/attributes_okapi/AttrGen/src/GenerateAttributes.java new file mode 100644 index 0000000..725dfff --- /dev/null +++ b/main/project/attributes_okapi/AttrGen/src/GenerateAttributes.java @@ -0,0 +1,172 @@ +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + + +public class GenerateAttributes { + + /** + * @param args + */ + public static void main(String[] args) { + + File inFile = new File(args[0]); + InputStream inputStream; + + try { + + writeHeader(); + + inputStream = new FileInputStream(inFile); + Reader reader = new InputStreamReader(inputStream,"UTF-8"); + + InputSource is = new InputSource(reader); + is.setEncoding("UTF-8"); + + parseAttributes(is); + + writeTrailer(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void writeHeader() { + System.out.print( +"// This is a generated file, do not change manually!\n" + +"\n" + +"package cgeo.geocaching.connector.oc;\n" + +"\n" + +"import java.util.HashMap;\n" + +"import java.util.Map;\n" + +"\n" + +"public class AttributeParser {\n" + +"\n" + +" private final static Map<String, Integer> attrMapDe;\n" + +" private final static Map<String, Integer> attrMapPl;\n" + +"\n" + +" static {\n" + +" attrMapDe = new HashMap<String, Integer>();\n" + +" attrMapPl = new HashMap<String, Integer>();\n" + +"\n" + +" // last header line\n"); + } + + private static void writeAttr(AttrInfo attr) { + + for(String name : attr.names) { + if (attr.oc_de_id > 0) { + System.out.println(" attrMapDe.put(\"" + name + "\", " + attr.oc_de_id + ");"); + } + if (attr.oc_pl_id > 0) { + System.out.println(" attrMapPl.put(\"" + name + "\", " + attr.oc_pl_id + ");"); + } + } + + } + + private static void writeTrailer() { + System.out.print( +" // first trailer line\n" + +"\n" + +" }\n" + +"\n" + +" public static int getOcDeId(final String name) {\n" + +"\n" + +" int result = 0;\n" + +"\n" + +" if (attrMapDe.containsKey(name)) {\n" + +" result = attrMapDe.get(name);\n" + +" }\n" + +" return result;\n" + +" }\n" + +"}\n"); + } + + private static void parseAttributes(InputSource stream) { + + try { + + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser = factory.newSAXParser(); + + DefaultHandler handler = new DefaultHandler() { + + AttrInfo attr; + ArrayList<String> names; + boolean readingName; + + public void startElement(String uri, String localName, + String qName, Attributes attributes) + throws SAXException { + + if (qName.equalsIgnoreCase("attr")) { + attr = new AttrInfo(); + names = new ArrayList<String>(); + } + + if (attr != null && qName.equalsIgnoreCase("opencaching")) { + if ("http://opencaching.de/".equalsIgnoreCase(attributes.getValue("site_url"))) { + attr.oc_de_id = Integer.parseInt(attributes.getValue("id")); + } else if ("http://opencaching.pl/".equalsIgnoreCase(attributes.getValue("site_url"))) { + attr.oc_pl_id = Integer.parseInt(attributes.getValue("id")); + } + } + + if (names != null && qName.equalsIgnoreCase("name")) { + readingName = true; + } + } + + public void endElement(String uri, String localName, + String qName) + throws SAXException { + + if (attr != null && qName.equalsIgnoreCase("attr")) { + attr.names = names.toArray(new String[]{}); + names = null; + writeAttr(attr); + attr = null; + } + + readingName = false; + } + + public void characters(char ch[], int start, int length) + throws SAXException { + + if (readingName) { + names.add(new String(ch, start, length)); + } + } + + }; + + saxParser.parse(stream, handler); + + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + static class AttrInfo { + public int oc_de_id; + public int oc_pl_id; + public String[] names; + } + +} diff --git a/main/project/attributes_okapi/AttributeParser.java b/main/project/attributes_okapi/AttributeParser.java new file mode 100644 index 0000000..63bee77 --- /dev/null +++ b/main/project/attributes_okapi/AttributeParser.java @@ -0,0 +1,327 @@ +// This is a generated file, do not change manually! + +package cgeo.geocaching.connector.oc; + +import java.util.HashMap; +import java.util.Map; + +public class AttributeParser { + + private final static Map<String, Integer> attrMapDe; + private final static Map<String, Integer> attrMapPl; + + static { + attrMapDe = new HashMap<String, Integer>(); + attrMapPl = new HashMap<String, Integer>(); + + // last header line + attrMapDe.put("Listed at Opencaching only", 6); + attrMapDe.put("Dostępna tylko na Opencaching", 6); + attrMapDe.put("Nur bei Opencaching logbar", 6); + attrMapDe.put("Solo loggeable en Opencaching", 6); + attrMapDe.put("Loggabile solo su Opencaching", 6); + attrMapPl.put("Near a Survey Marker", 54); + attrMapPl.put("W pobliżu punktu geodezyjnego", 54); + attrMapPl.put("Whereigo Cache", 55); + attrMapPl.put("Whereigo Cache", 55); + attrMapPl.put("Whereigo Cache", 55); + attrMapDe.put("Letterbox Cache", 8); + attrMapPl.put("Letterbox Cache", 56); + attrMapDe.put("Skrzynka typu Letterbox", 8); + attrMapPl.put("Skrzynka typu Letterbox", 56); + attrMapDe.put("Letterbox (benötigt Stempel)", 8); + attrMapPl.put("Letterbox (benötigt Stempel)", 56); + attrMapDe.put("Letterbox (necesita un estampador)", 8); + attrMapPl.put("Letterbox (necesita un estampador)", 56); + attrMapDe.put("Letterbox (richiede un timbro)", 8); + attrMapPl.put("Letterbox (richiede un timbro)", 56); + attrMapPl.put("GeoHotel", 43); + attrMapPl.put("GeoHotel", 43); + attrMapPl.put("GeoHotel", 43); + attrMapPl.put("Magnetic cache", 49); + attrMapPl.put("Przyczepiona magnesem", 49); + attrMapPl.put("magnetischer Cache", 49); + attrMapPl.put("Description contains an audio file", 50); + attrMapPl.put("Opis zawiera plik audio", 50); + attrMapPl.put("Offset cache", 51); + attrMapPl.put("Offset cache", 51); + attrMapPl.put("Peilungscache", 51); + attrMapPl.put("Garmin's wireless beacon", 52); + attrMapPl.put("Beacon - Garmin Chirp", 52); + attrMapPl.put("Funksignal – Garmin Chirp", 52); + attrMapPl.put("Dead Drop USB cache", 53); + attrMapPl.put("Dead Drop USB skrzynka", 53); + attrMapDe.put("Has a moving target", 31); + attrMapDe.put("bewegliches Ziel", 31); + attrMapDe.put("Objetivo en movimiento", 31); + attrMapDe.put("Oggetto in movimento", 31); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Other cache type", 57); + attrMapDe.put("sonstiger Cachetyp", 57); + attrMapDe.put("Otro tipo de cache", 57); + attrMapDe.put("Altro tipo di cache", 57); + attrMapDe.put("Investigation required", 54); + attrMapDe.put("Recherche", 54); + attrMapDe.put("Investigación", 54); + attrMapDe.put("Ricerca", 54); + attrMapDe.put("Puzzle / Mystery", 55); + attrMapDe.put("Rätsel", 55); + attrMapDe.put("Puzzle / Misterio", 55); + attrMapDe.put("Puzzle / Mystery", 55); + attrMapDe.put("Arithmetical problem", 56); + attrMapDe.put("Rechenaufgabe", 56); + attrMapDe.put("Problema matemático", 56); + attrMapDe.put("Problema matematico", 56); + attrMapDe.put("Ask owner for start conditions", 58); + attrMapDe.put("Startbedingungen beim Owner erfragen", 58); + attrMapDe.put("Ask owner for start conditions", 58); + attrMapDe.put("Ask owner for start conditions", 58); + attrMapPl.put("Wheelchair accessible", 44); + attrMapPl.put("Dostępna dla niepełnosprawnych", 44); + attrMapPl.put("rollstuhltauglich", 44); + attrMapDe.put("Near the parking area", 24); + attrMapDe.put("nahe beim Auto", 24); + attrMapDe.put("Cerca de un Parking", 24); + attrMapDe.put("Vicino all'area di parcheggio", 24); + attrMapPl.put("Access only by walk", 84); + attrMapPl.put("Dostępna tylko pieszo", 84); + attrMapDe.put("Long walk", 25); + attrMapDe.put("längere Wanderung", 25); + attrMapDe.put("Larga caminata", 25); + attrMapDe.put("Lunga camminata", 25); + attrMapDe.put("Swamp, marsh or wading", 26); + attrMapDe.put("sumpfig/matschiges Gelände / waten", 26); + attrMapDe.put("Pantano / terreno fangoso", 26); + attrMapDe.put("Palude o marcita", 26); + attrMapDe.put("Hilly area", 27); + attrMapDe.put("hügeliges Gelände", 27); + attrMapDe.put("Terreno montañoso", 27); + attrMapDe.put("Area collinare", 27); + attrMapDe.put("Some climbing (no gear needed)", 28); + attrMapDe.put("leichtes Klettern (ohne Ausrüstung)", 28); + attrMapDe.put("fácil de subir (sin equipo)", 28); + attrMapDe.put("Arrampicata (attrezzatura non necessaria)", 28); + attrMapDe.put("Swimming required", 29); + attrMapDe.put("Schwimmen erforderlich", 29); + attrMapDe.put("Requiere nadar", 29); + attrMapDe.put("Nuoto necessario", 29); + attrMapDe.put("Access or parking fee", 36); + attrMapDe.put("Zugangs- bzw. Parkentgelt", 36); + attrMapDe.put("Acceso o parking pagando", 36); + attrMapDe.put("Tassa di ingresso o di parcheggio", 36); + attrMapPl.put("Bikes allowed", 85); + attrMapPl.put("Dostępna rowerem", 85); + attrMapPl.put("Hidden in natural surroundings (forests, mountains, etc.)", 60); + attrMapPl.put("Umiejscowiona na łonie natury (lasy, góry, itp.)", 60); + attrMapPl.put("Historic site", 61); + attrMapPl.put("Miejsce historyczne", 61); + attrMapDe.put("Point of interest", 30); + attrMapDe.put("interessanter Ort", 30); + attrMapDe.put("Punto de interes", 30); + attrMapDe.put("Punto di interesse", 30); + attrMapDe.put("Hidden wihin enclosed rooms (caves, buildings etc.)", 33); + attrMapDe.put("in geschlossenen Räumen (Höhle, Gebäude, etc.)", 33); + attrMapDe.put("en espacios confinados (cuevas, edificios, etc)", 33); + attrMapDe.put("All'interno di stanze chiuse (caverne, edifici, ecc.)", 33); + attrMapDe.put("Hidden under water", 34); + attrMapDe.put("Im Wasser versteckt", 34); + attrMapDe.put("En el agua", 34); + attrMapDe.put("Nell'acqua", 34); + attrMapDe.put("Parking area nearby", 18); + attrMapDe.put("Parkplatz in der Nähe", 18); + attrMapDe.put("Parking cercano", 18); + attrMapDe.put("Parcheggio nei pressi", 18); + attrMapDe.put("Public transportation", 19); + attrMapDe.put("erreichbar mit ÖVM", 19); + attrMapDe.put("Transporte Público", 19); + attrMapDe.put("Trasporto pubblico", 19); + attrMapDe.put("Drinking water nearby", 20); + attrMapDe.put("Trinkwasser in der Nähe", 20); + attrMapDe.put("Agua potable en las cercanias", 20); + attrMapDe.put("Acqua potabile nei pressi", 20); + attrMapDe.put("Public restrooms nearby", 21); + attrMapDe.put("öffentliche Toilette in der Nähe", 21); + attrMapDe.put("Aseos públicos cercanos", 21); + attrMapDe.put("Bagni pubblici nei pressi", 21); + attrMapDe.put("Public phone nearby", 22); + attrMapDe.put("Telefon in der Nähe", 22); + attrMapDe.put("Teléfono Público en las cercanias", 22); + attrMapDe.put("Telefono pubblico nei pressi", 22); + attrMapDe.put("First aid available", 23); + attrMapDe.put("Erste Hilfe verfügbar", 23); + attrMapDe.put("Disponible socorro rapido", 23); + attrMapDe.put("Disponibile pronto soccorso", 23); + attrMapDe.put("Available 24/7", 38); + attrMapDe.put("rund um die Uhr machbar", 38); + attrMapDe.put("Disponible las 24 horas", 38); + attrMapDe.put("Disponibile 24 ore", 38); + attrMapDe.put("Not 24/7", 39); + attrMapPl.put("Not 24/7", 80); + attrMapDe.put("Dostępna w określonych godzinach", 39); + attrMapPl.put("Dostępna w określonych godzinach", 80); + attrMapDe.put("nur zu bestimmten Uhrzeiten", 39); + attrMapPl.put("nur zu bestimmten Uhrzeiten", 80); + attrMapDe.put("Sólo disponible a ciertas horas", 39); + attrMapPl.put("Sólo disponible a ciertas horas", 80); + attrMapDe.put("Disponibile solo in certi orari", 39); + attrMapPl.put("Disponibile solo in certi orari", 80); + attrMapDe.put("Not recommended at night", 40); + attrMapDe.put("nur tagüber", 40); + attrMapDe.put("solo por el día", 40); + attrMapDe.put("solo di giorno", 40); + attrMapPl.put("Recommended at night", 91); + attrMapPl.put("Zalecane szukanie nocą", 91); + attrMapPl.put("am besten nachts findbar", 91); + attrMapDe.put("Only at night", 1); + attrMapDe.put("nur bei Nacht", 1); + attrMapDe.put("Sólo por la noche", 1); + attrMapDe.put("Solo di notte", 1); + attrMapDe.put("All seasons", 42); + attrMapDe.put("ganzjähig zugänglich", 42); + attrMapDe.put("Todas las temporadas", 42); + attrMapDe.put("Tutte le stagioni", 42); + attrMapDe.put("Only available during specified seasons", 60); + attrMapDe.put("Nur zu bestimmten Zeiten im Jahr", 60); + attrMapDe.put("Sólo disponible durante las estaciones especificadas", 60); + attrMapDe.put("Disponibile solo in certe stagioni", 60); + attrMapDe.put("Breeding season / protected nature", 43); + attrMapDe.put("Brutsaison / Naturschutz", 43); + attrMapDe.put("Temporada de reproducción / protección de la naturaleza", 43); + attrMapDe.put("Stagione di riproduzione / natura protetta", 43); + attrMapDe.put("Available during winter", 44); + attrMapDe.put("schneesicheres Versteck", 44); + attrMapDe.put("Nieve en el escondite", 44); + attrMapDe.put("Luogo a prova di neve", 44); + attrMapDe.put("Not at high water level", 41); + attrMapDe.put("nicht bei Hochwasser oder Flut", 41); + attrMapDe.put("Compass required", 47); + attrMapPl.put("Compass required", 47); + attrMapDe.put("Potrzebny kompas", 47); + attrMapPl.put("Potrzebny kompas", 47); + attrMapDe.put("Kompass", 47); + attrMapPl.put("Kompass", 47); + attrMapDe.put("Brújula", 47); + attrMapPl.put("Brújula", 47); + attrMapDe.put("Bussola", 47); + attrMapPl.put("Bussola", 47); + attrMapPl.put("Take something to write", 48); + attrMapPl.put("Weź coś do pisania", 48); + attrMapPl.put("You may need a shovel", 81); + attrMapPl.put("Potrzebna łopatka", 81); + attrMapDe.put("Flashlight required", 48); + attrMapPl.put("Flashlight required", 82); + attrMapDe.put("Potrzebna latarka", 48); + attrMapPl.put("Potrzebna latarka", 82); + attrMapDe.put("Taschenlampe", 48); + attrMapPl.put("Taschenlampe", 82); + attrMapDe.put("Linterna", 48); + attrMapPl.put("Linterna", 82); + attrMapDe.put("Lampada tascabile", 48); + attrMapPl.put("Lampada tascabile", 82); + attrMapDe.put("Climbing gear required", 49); + attrMapDe.put("Kletterzeug", 49); + attrMapDe.put("Equipo de escalada", 49); + attrMapDe.put("Attrezzatura per arrampicata", 49); + attrMapDe.put("Cave equipment required", 50); + attrMapDe.put("Höhlenzeug", 50); + attrMapDe.put("Equipación para cuevas", 50); + attrMapDe.put("Attrezzatura per grotta", 50); + attrMapDe.put("Diving equipment required", 51); + attrMapDe.put("Taucherausrüstung", 51); + attrMapDe.put("Diving equipment", 51); + attrMapDe.put("Equipo de buceo", 51); + attrMapDe.put("Special tools required", 46); + attrMapPl.put("Special tools required", 83); + attrMapDe.put("Wymagany dodatkowy sprzęt", 46); + attrMapPl.put("Wymagany dodatkowy sprzęt", 83); + attrMapDe.put("spezielle Ausrüstung", 46); + attrMapPl.put("spezielle Ausrüstung", 83); + attrMapDe.put("Equipamiento especial", 46); + attrMapPl.put("Equipamiento especial", 83); + attrMapDe.put("Equipaggiamento speciale", 46); + attrMapPl.put("Equipaggiamento speciale", 83); + attrMapDe.put("Requires a boat", 52); + attrMapPl.put("Requires a boat", 86); + attrMapDe.put("Wymaga sprzętu pływającego", 52); + attrMapPl.put("Wymaga sprzętu pływającego", 86); + attrMapDe.put("Wasserfahrzeug", 52); + attrMapPl.put("Wasserfahrzeug", 86); + attrMapDe.put("Barca", 52); + attrMapPl.put("Barca", 86); + attrMapDe.put("Barca", 52); + attrMapPl.put("Barca", 86); + attrMapDe.put("No GPS required", 35); + attrMapDe.put("ohne GPS findbar", 35); + attrMapDe.put("Sin GPS", 35); + attrMapDe.put("Senza GPS", 35); + attrMapDe.put("Dangerous area", 9); + attrMapPl.put("Dangerous area", 90); + attrMapDe.put("Skrzynka niebezpieczna", 9); + attrMapPl.put("Skrzynka niebezpieczna", 90); + attrMapDe.put("gefährliches Gebiet", 9); + attrMapPl.put("gefährliches Gebiet", 90); + attrMapDe.put("Zona Peligrosa", 9); + attrMapPl.put("Zona Peligrosa", 90); + attrMapDe.put("Area pericolosa", 9); + attrMapPl.put("Area pericolosa", 90); + attrMapDe.put("Active railway nearby", 10); + attrMapDe.put("aktive Eisenbahnlinie in der Nähe", 10); + attrMapDe.put("Cerca del ferrocarril activo", 10); + attrMapDe.put("Ferrovia attiva nei pressi", 10); + attrMapDe.put("Cliff / Rocks", 11); + attrMapDe.put("Klippen / Felsen", 11); + attrMapDe.put("Acantilado / Rocas", 11); + attrMapDe.put("Scogliera / Rocce", 11); + attrMapDe.put("Hunting", 12); + attrMapDe.put("Jagdgebiet", 12); + attrMapDe.put("Zona de Caza", 12); + attrMapDe.put("Caccia", 12); + attrMapDe.put("Thorns", 13); + attrMapDe.put("Dornen", 13); + attrMapDe.put("Espinas", 13); + attrMapDe.put("Spine", 13); + attrMapDe.put("Ticks", 14); + attrMapDe.put("Zecken", 14); + attrMapDe.put("Garrapatas", 14); + attrMapDe.put("Zecche", 14); + attrMapDe.put("Abandoned mines", 15); + attrMapDe.put("Folgen des Bergbaus", 15); + attrMapDe.put("Mina abandonada", 15); + attrMapDe.put("Miniere abbandonate", 15); + attrMapDe.put("Poisonous plants", 16); + attrMapDe.put("giftige Pflanzen", 16); + attrMapDe.put("Planta venenosa", 16); + attrMapDe.put("Piante velenose", 16); + attrMapDe.put("Dangerous animals", 17); + attrMapDe.put("giftige/gefährliche Tiere", 17); + attrMapDe.put("Animales Peligrosos", 17); + attrMapDe.put("Animali pericolosi", 17); + attrMapPl.put("Quick cache", 40); + attrMapPl.put("Szybka skrzynka", 40); + attrMapDe.put("Overnight stay necessary", 37); + attrMapDe.put("Übernachtung erforderlich", 37); + attrMapDe.put("Necesario pernoctar", 37); + attrMapDe.put("Necessario pernottamento", 37); + attrMapPl.put("Take your children", 41); + attrMapPl.put("Można zabrać dzieci", 41); + attrMapDe.put("Suited for children (10-12 yo)", 59); + attrMapDe.put("kindgerecht (10-12 Jahre)", 59); + attrMapDe.put("Apto para niños (10-12 años)", 59); + attrMapDe.put("Suited for children (10-12 anni)", 59); + // first trailer line + + } + + public static int getOcDeId(final String name) { + + int result = 0; + + if (attrMapDe.containsKey(name)) { + result = attrMapDe.get(name); + } + return result; + } +} diff --git a/main/project/attributes_okapi/attributes.xml b/main/project/attributes_okapi/attributes.xml new file mode 100644 index 0000000..ede81a8 --- /dev/null +++ b/main/project/attributes_okapi/attributes.xml @@ -0,0 +1,1940 @@ +<!-- + +Current status: WORKING DRAFT + +This is the list of all geocache attributes supported by OKAPI. In +practise, it will usually include any atribute used by at least one of +the Opencaching installations. + + +NOTES FOR EXTERNAL APP DEVELOPERS +================================= + +DO NOT read or parse this file in your apps! It is NOT guaranteed to stay +backward-compatible. Use public OKAPI methods instead. + + +NOTES FOR OC/OKAPI DEVELOPERS +============================= + +Every OC installation has its own set of internal attributes. This file +allows them to be merged with other attributes from other OC installations. +It is periodically read by every OKAPI installation, *directly from +the repository*. + +This file defines the mapping between: + +1. Internal attribute IDs of various Opencaching nodes. +2. Groundspeak's attribute IDs (used by geocaching.com). +3. OKAPI's attribute IDs. + +Important: This is a verbose, many-to-many, optional relationship! Crow's foot +notation: http://i.imgur.com/cNGz1xt.png. All those attributes may appear not +very useful when provided this way, but there is nothing OKAPI can do about it. +We leave the UI clarity problem for app developers. + +--> + +<xml> + + <!-- Language forms - status: just an idea, unimplemented (see form="" + attributes in <attr> elements). TODO: fill missing form="" attributes. --> + + <form id="is / not is"> + <prefix lang="en"> + <include><b>Include</b> the cache, only if it is:</include> + <exclude><b>Exclude</b> the cache if it is:</exclude> + </prefix> + <prefix lang="pl"> + <include><b>Uwzględnij</b> skrzynkę, tylko jeśli jest:</include> + <exclude><b>Pomiń</b> skrzynkę, jeśli jest:</exclude> + </prefix> + </form> + + <form id="contains / does not contain"> + <prefix lang="en"> + <include><b>Include</b> the cache, only if it contains:</include> + <exclude><b>Exclude</b> the cache if it contains:</exclude> + </prefix> + <prefix lang="pl"> + <include><b>Uwzględnij</b> skrzynkę, tylko jeśli zawiera:</include> + <exclude><b>Pomiń</b> skrzynkę, jeśli nie zawiera:</exclude> + </prefix> + </form> + + <form id="allowed / not allowed"> + <prefix lang="en"> + <include>The following <b>must be allowed</b>:</include> + <exclude>The following <b>may not be allowed</b>:</exclude> + </prefix> + </form> + + <form id="required / not required"> + <prefix lang="en"> + <include>The following <b>must be required</b>:</include> + <exclude>The following <b>may not be required</b>:</exclude> + </prefix> + </form> + + <form id="if / if not"> + <prefix lang="en"> + <include>The following <b>must be true</b>:</include> + <exclude>The following <b>may not be true</b>:</exclude> + </prefix> + </form> + + <!-- + + NOTICE: Categories are currently NOT implemented. In particular, the + attr[categories] is ignored. See issue 70. + + <category id="de-cache-types"> + <name lang="en">TODO</name> + </category> + + <category id="de-location"> + <name lang="en">TODO</name> + </category> + + <category id="de-facilities"> + <name lang="en">TODO</name> + </category> + + <category id="de-time-and-seasons"> + <name lang="en">TODO</name> + </category> + + <category id="de-tools"> + <name lang="en">TODO</name> + </category> + + <category id="de-dangers"> + <name lang="en">TODO</name> + </category> + + <category id="de-rating"> + <name lang="en">TODO</name> + </category> + + <category id="de-preconditions"> + <name lang="en">TODO</name> + </category> + + <category id="de-accessibility"> + <name lang="en">TODO</name> + </category> + + --> + + <attr okapi_attr_id="oconly" categories="de-listing" form="is / is not"> + <opencaching site_url="http://opencaching.de/" id="6" /> + <name lang="en">Listed at Opencaching only</name> + <desc lang="en"> + This geocache is listed at Opencaching only. + </desc> + <name lang="pl">Dostępna tylko na Opencaching</name> + <desc lang="pl"> + Skrzynka "jednosystemowa", dostępna jedynie poprzez serwis Opencaching. + </desc> + <name lang="de">Nur bei Opencaching logbar</name> + <desc lang="de"> + Der Geocache ist nur bei Opencaching gelistet. Benutzer anderer + Geocache-Datenbanken haben so einen schnellen Überblick, welche Geocaches + es sich lohnt näher anzusehen. + </desc> + <name lang="es">Solo loggeable en Opencaching</name> + <desc lang="es"> + Este geocachee esta publicado sólo en Opencaching. Este atributo permite + a los usuarios de otras plataformas encontrar rápidamente caches + interesantes de calidad OC geocaching. + </desc> + <name lang="it">Loggabile solo su Opencaching</name> + <desc lang="it"> + Questa geocache è pubblicata solo su Opencaching. Questo attributo permette + agli utenti di altre piattaforme di geocaching di trovare velocemente + interessanti cache OC di qualità. + </desc> + </attr> + + <attr okapi_attr_id="near-survey-marker" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.pl/" id="54" /> + <name lang="en">Near a Survey Marker</name> + <desc lang="en"> + The cache is hidden in near proximity of a survey marker (also known + as geodetic marks). + </desc> + <name lang="pl">W pobliżu punktu geodezyjnego</name> + <desc lang="pl"> + Skrzynka ukryta w pobliżu punktu geodezyjnego. + <a href='http://wiki.opencaching.pl/index.php/Benchmark'>Więcej informacji</a>. + </desc> + </attr> + + <attr okapi_attr_id="wherigo" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.pl/" id="55" /> + <name lang="en">Whereigo Cache</name> + <desc lang="en"> + Cache description includes a file - the Whereigo cartridge. In order to + find the cache, you need to download the file and install it on + a proper compatible device. + </desc> + <name lang="pl">Whereigo Cache</name> + <desc lang="pl"> + Opis skrzynki zawiera scenariusz WIGO (ang. Whereigo). Aby móc zdobyć skrzynkę + należy pobrać scenariusz i wgrać go do kompatybilnego z nim urządzenia. + <a href='http://wiki.opencaching.pl/index.php/Wherigo_czyli_Scenariusze_WIGO'>Więcej informacji</a>. + </desc> + <name lang="de">Whereigo Cache</name> + </attr> + + <attr okapi_attr_id="letterbox" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.pl/" id="56" /> + <opencaching site_url="http://opencaching.de/" id="8" /> + <name lang="en">Letterbox Cache</name> + <desc lang="en"> + There is a stamp in the cache for stamping your personal logbook, and the + cache’s logbook will be stamped with your personal stamp. Take care not + to mix up stamps and to leave the cache’s stamp in the cache! + </desc> + <name lang="pl">Skrzynka typu Letterbox</name> + <desc lang="pl"> + W skrzynce znajduje się pieczątka, której nie można zabrać ze sobą. + Możesz jej użyć do ostemplowania swojego osobistego dziennika. + Logbook skrzynki powinien z kolei zostać ostemplowany Twoją własną + pieczątką. + <a href='http://wiki.opencaching.pl/index.php/Letterboxing'>Więcej informacji</a>. + </desc> + <name lang="de">Letterbox (benötigt Stempel)</name> + <desc lang="de"> + In dem Behälter vor Ort befindet sich ein Stempel, mit dem man sein + persönliches Logbuch abstempeln kann. Das Logbuch im Geocache wird + ebenfalls mit einem persönlichen Stempel signiert. Bitte achte unbedingt + darauf, dass du den Stempel aus dem Geocache nicht mitnimmst oder tauschst! + <a href='http://wiki.opencaching.de/index.php/Letterboxing'>Weitere Informationen</a>. + </desc> + <name lang="es">Letterbox (necesita un estampador)</name> + <desc lang="es"> + Hay un sello en el cache para estamparlo en su libro de registro personal, + y el libro de registro del cache será sellada con su sello personal. + ¡Tenga cuidado de no mezclar los sellos! + </desc> + <name lang="it">Letterbox (richiede un timbro)</name> + <desc lang="it"> + C'è un timbro nella cache per timbrare il tuo quaderno personale, + e il log della cache verrà timbrato con il tuo timbro personale. + Fate attenzione a non confondere i timbri e a lasciare il timbro della + cache nella cache! + </desc> + </attr> + + <attr okapi_attr_id="geohotel" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.pl/" id="43" /> + <name lang="en">GeoHotel</name> + <desc lang="en"> + Primary purpose of the "GeoHotel" caches is to exchange trackables + (TravelBugs, GeoKretys, etc.). + </desc> + <name lang="pl">GeoHotel</name> + <desc lang="pl"> + Atrybut ten oznacza skrzynki których głównym celem jest lokowanie + w tej skrzynce różnych wędrujących rzeczy np GeoKrety, GeoLutins, + GeoFish itp. + </desc> + <name lang="de">GeoHotel</name> + </attr> + + <attr okapi_attr_id="magnet" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.pl/" id="49" /> + <name lang="en">Magnetic cache</name> + <desc lang="en"> + This geocache is attached with a magnet. + </desc> + <name lang="pl">Przyczepiona magnesem</name> + <desc lang="pl"> + Skrzynka zawiera magnes i przymocowana jest za jego pomocą. + </desc> + <name lang="de">magnetischer Cache</name> + </attr> + + <attr okapi_attr_id="audiofile" categories="de-cache-types" form="if / if not"> + <opencaching site_url="http://opencaching.pl/" id="50" /> + <name lang="en">Description contains an audio file</name> + <desc lang="pl"> + In order to find this cache, you must listen to an audio recording, + which is attached to the cache description. + </desc> + <name lang="pl">Opis zawiera plik audio</name> + <desc lang="pl"> + Aby odnaleźć skrzynkę, należy odsłuchać plik dźwiękowy. Może on + zawierać zakodowane informacje, dźwięki otoczenia, opis dotarcia + do skrzynki. + </desc> + </attr> + + <attr okapi_attr_id="offset" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.pl/" id="51" /> + <name lang="en">Offset cache</name> + <desc lang="pl"> + A specific type of a MultiCache. The coordinates point to a starting + point. The description contains simple instructions to follow + once you are in the starting point (usually, an azimuth and a + distance). + </desc> + <name lang="pl">Offset cache</name> + <desc lang="pl"> + Szczególny przypadek skrzynki typu multicache, składający się z + punktu startowego (określonego współrzędnymi) oraz jasnych + informacjami o sposobie dotarcia do finału (np. azymutu i + odległości). + </desc> + <name lang="de">Peilungscache</name> + </attr> + + <attr okapi_attr_id="chirp" categories="de-cache-types" form="contains / does not contain"> + <groundspeak id="60" inc="true" name="Wireless Beacon" /> + <opencaching site_url="http://opencaching.pl/" id="52" /> + <name lang="en">Garmin's wireless beacon</name> + <desc lang="en"> + Contains Garmin's wireless chirp beacon. + </desc> + <name lang="pl">Beacon - Garmin Chirp</name> + <desc lang="pl"> + Skrzynka zawiera Beacon Garmin chirp. + </desc> + <name lang="de">Funksignal – Garmin Chirp</name> + </attr> + + <attr okapi_attr_id="usb" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.pl/" id="53" /> + <name lang="en">Dead Drop USB cache</name> + <desc lang="pl"> + The cache consists of an unmovable USB mass storage device, e.g. + fixed into a wall, curb etc. The device contains readme.txt file + with cache description and a logbook.txt file where you can log + your visit. + </desc> + <name lang="pl">Dead Drop USB skrzynka</name> + <desc lang="pl"> + Skrzynka typu USB Dead Drop. Pen-drive przymocowany lub wmurowany + w ścianę, budynek, krawiężnik itp. Aby zalogować znalezienie, należy + wpisać się do pliku logbook.txt znajdującego się w pamięci urządzenia. + <a href='http://wiki.opencaching.pl/index.php/Skrzynka_Dead_Drop'>Wiecej informacji</a>. + </desc> + </attr> + + <attr okapi_attr_id="moving" categories="de-cache-types" form="if / if not"> + <!-- This looks redundant to the 'moving cache' type, but it may also be a + moving final of a multi- or quiz cache. --> + <opencaching site_url="http://opencaching.de/" id="31" /> + <name lang="en">Has a moving target</name> + <desc lang="en"> + This geocache is moving around. For example, the owner might regularly + move the cache from one place to another, or the finders will do this + task and post new coordinates in their log entries. The owner must + update coordinates in the cache description after each move. + </desc> + <!-- TODO: "Has a" was added. --> + <name lang="de">bewegliches Ziel</name> + <desc lang="de"> + Der Geocache verändert seine Position und ist deshalb nicht immer am + gleichen Ort zu finden. Es gibt Varianten, bei denen der Geocache-Besitzer + den Geocache regelmäßig an anderen Orten versteckt, oder der Finder den + Geocache an einem neuen Ort versteckt. Danach muss der Besitzer jeweils + die Beschreibung aktualisieren. + </desc> + <name lang="es">Objetivo en movimiento</name> + <desc lang="es"> + Este geocache está en movimiento. Por ejemplo, el propietario podía mover + la caché periódicamente de un lugar a otro, o un geobuscador podría hacer + esto y ofrecer nuevos detalles en su registro. El propietario debe + actualizar las coordenadas en la descripción del cache después de cada + movimiento. + </desc> + <name lang="it">Oggetto in movimento</name> + <desc lang="it"> + Questa geocache è in muovimento. Per esempio, il proprietario potrebbe + spostare regolarmente la cache da un luogo ad un altro, o i cacher + potrebbero eseguire questa operazione e indicare nuove coordinate nel + loro log. Il proprietario deve aggiornare le coordinate nella descrizione + della cache dopo ogni mossa. + </desc> + </attr> + + <attr okapi_attr_id="webcam" categories="de-cache-types" form="is / is not"> + <opencaching site_url="http://opencaching.de/" id="32" /> + <name lang="en">Webcam Cache</name> + <desc lang="en"> + There is a webcam at the target location. You must record a webcam + picture of your visit and include it in your 'found' log entry. There + may be additional requirements like a geocaching banner on the photo. + The webcam’s address is included in the cache description. + </desc> + <name lang="de">Webcam Cache</name> + <desc lang="de"> + Am Ziel befindet sich eine Webcam, und für einen Fund muss man das Bild + der Webcam von sich selbst aufnehmen, um nachzuweisen, dass man vor Ort + war. Manche Webcam-Caches setzen auch weitere Bedingungen, z.B. einen + Geocaching-Banner auf dem Bild. Die Webadresse der Webcam ist in der + Beschreibung angegeben. + </desc> + <name lang="es">Webcam Cache</name> + <desc lang="es"> + Hay una webcam en el lugar de destino. necesidad a alguien para registrar + con un pantallazo de la imagen de la webcam de su visita e incluirlo en + el registro. Puede haber requisitos adicionales como un signo de + geocaching en la imagen. La dirección de la webcam está incluido en la + descripción de la cache. + </desc> + <name lang="it">Webcam Cache</name> + <desc lang="it"> + C'è una webcam nella posizione di destinazione. E' necessario registrare + una foto con la webcam della vostra visita e includerla nel log. Ci + possono essere requisiti addizionali come un segnale di geocaching sulla + foto. L'indirizzo della webcam è incluso nella descrizione della cache. + </desc> + </attr> + + <attr okapi_attr_id="other-type" categories="de-cache-types"> + <!-- + This looks redundant to the "unknown type" cache type, but + it is used vor special variants of basic cache types - e.g. a + multicache where you won't just find a box at the final but have + to meet an additional challenge there. + --> + <opencaching site_url="http://opencaching.de/" id="57" /> + <name lang="en">Other cache type</name> + <desc lang="en"> + This is none of the standard, pre-defined types of cache. + Use this attribute for special, unusual caches. + </desc> + <name lang="de">sonstiger Cachetyp</name> + <desc lang="de"> + Dieser Cache passt in keine der üblichen Kategorien von Caches (Cachearten). + </desc> + <name lang="es">Otro tipo de cache</name> + <desc lang="es"> + Este es un cache que no pertenece a ninguna de las categorías predefinicas + - estándar. + </desc> + <name lang="it">Altro tipo di cache</name> + <desc lang="it"> + Questa è una cache che non appartiene a nessuna delle categorie standard + perdefinite. Usa questo attributo per cache speciali e inusuali. + </desc> + </attr> + + <attr okapi_attr_id="investigation" categories="de-preconditions"> + <opencaching site_url="http://opencaching.de/" id="54" /> + <name lang="en">Investigation required</name> + <desc lang="en"> + You must investigate additional information before you can seek this cache. + </desc> + <name lang="de">Recherche</name> + <desc lang="de"> + Für diesen Cache muss vorab nach Informationen gesucht werden. + </desc> + <name lang="es">Investigación</name> + <desc lang="es"> + Necesitas encontrar más información antes de poder buscar este cache. + </desc> + <name lang="it">Ricerca</name> + <desc lang="it"> + È necessario trovare ulteriori informazioni prima di poter cercare + questa cache. + </desc> + </attr> + + <attr okapi_attr_id="puzzle" categories="de-preconditions"> + <groundspeak id="47" inc="true" name="Field puzzle" /> + <opencaching site_url="http://opencaching.de/" id="55" /> + <name lang="en">Puzzle / Mystery</name> + <desc lang="en"> + Puzzles or mysteries have to be solved before or while seeking this cache. + </desc> + <name lang="de">Rätsel</name> + <desc lang="de"> + Bei diesem Cache sind als Vorarbeit oder während der Suche Rütsel zu lösen. + </desc> + <name lang="es">Puzzle / Misterio</name> + <desc lang="es"> + Misterio o Puzzle para ser resuelto antes o durante la búsqueda de este cache. + </desc> + <name lang="it">Puzzle / Mystery</name> + <desc lang="it"> + Puzzle o Mystery devono essere risolti prima o durante la ricerca di + questa cache. + </desc> + </attr> + + <attr okapi_attr_id="maths" categories="de-preconditions"> + <opencaching site_url="http://opencaching.de/" id="56" /> + <name lang="en">Arithmetical problem</name> + <desc lang="en"> + Before or while seeking this cache, arithmetical problems must be solved + which go beyond very basic calculations. + </desc> + <name lang="de">Rechenaufgabe</name> + <desc lang="de"> + Es müssen vorab oder während der Suche Rechenaufgaben gelöst werden, die + über das kleine Geocacher 1x1 hinausgehen. zum Beispiel + Mittelpunktberechnungen oder Peilungen. + </desc> + <name lang="es">Problema matemático</name> + <desc lang="es"> + Antes o durante la búsqueda de este cache, resolver problemas matemáticos + sencillos más difícil a los cálculos de la base. + </desc> + <name lang="it">Problema matematico</name> + <desc lang="it"> + Prima o durante la ricerca di questa cache, devono essere risolti problemi + matematici più difficili di semplici calcoli base. + </desc> + </attr> + + <attr okapi_attr_id="ask-owner" categories="de-preconditions"> + <opencaching site_url="http://opencaching.de/" id="58" /> + <name lang="en">Ask owner for start conditions</name> + <desc lang="en"> + Before doing this cache, you must ask the owner for the starting conditions. + E.g. the cache may be linked to certain events at varying dates. + </desc> + <name lang="de">Startbedingungen beim Owner erfragen</name> + <desc lang="de"> + Bei diesem Cache ist es nötig, sich vor dem Angehen des Caches beim + Eigentümer über die Bedingungen zum Angehen zu informieren. + </desc> + <name lang="es">Ask owner for start conditions</name> + <desc lang="es"> + Pregunte a los propietarios por las condiciones iniciales + </desc> + <name lang="it">Ask owner for start conditions</name> + <desc lang="it"> + Chiedere al proprietario per le condizioni di partenza + </desc> + </attr> + + <attr okapi_attr_id="wheelchair" categories="de-accessibility"> + <groundspeak id="24" inc="true" name="Wheelchair accessible" /> + <opencaching site_url="http://opencaching.pl/" id="44" /> + <name lang="en">Wheelchair accessible</name> + <desc lang="en"> + The cache is hidden in a way which makes it possible to be found + when moving on a wheelchair. + </desc> + <name lang="pl">Dostępna dla niepełnosprawnych</name> + <desc lang="pl"> + Skrzynka ukryta w sposób umożliwiający jej znalezienie osobom + poruszającym się na wózku inwalidzkim. Dotyczy to zarówno + lokalizacji (np. dojazd alejką pod samą skrzynkę), jak i sposobu + ukrycia. + </desc> + <name lang="de">rollstuhltauglich</name> + </attr> + + <attr okapi_attr_id="drivein" categories="de-accessibility"> + <groundspeak id="53" inc="true" name="Park and grab" /> + <opencaching site_url="http://opencaching.de/" id="24" /> + <name lang="en">Near the parking area</name> + <desc lang="en"> + The geocache is located close to a parking area, only a few steps away. + </desc> + <name lang="de">nahe beim Auto</name> + <desc lang="de"> + Der Parkplatz befindet sich in unmittelbarer Nähe zum Geocache. + Es sind nicht mehr als einige Schritte notwendig um den Geocache zu finden. + </desc> + <name lang="es">Cerca de un Parking</name> + <desc lang="es"> + El geocache se encuentra cerca de un parking, a poca distancia. + </desc> + <name lang="it">Vicino all'area di parcheggio</name> + <desc lang="it"> + La geocache è posta vicino ad un'area di parcheggio, solo poco distante. + </desc> + </attr> + + <attr okapi_attr_id="walk-only" categories="de-accessibility"> + <opencaching site_url="http://opencaching.pl/" id="84" /> + <name lang="en">Access only by walk</name> + <desc lang="en"> + The cache is accessible by walk only. + </desc> + <name lang="pl">Dostępna tylko pieszo</name> + <desc lang="pl"> + Skrzynka dostępna tylko pieszo. + </desc> + </attr> + + <attr okapi_attr_id="hike" categories="de-accessibility"> + <groundspeak id="9" inc="true" name="Significant Hike" /> + <opencaching site_url="http://opencaching.de/" id="25" /> + <name lang="en">Long walk</name> + <desc lang="en"> + This cache requires a long walk - more than 5 km round trip. In the + mountains and other steep areas, the distance for a 'long walk' may be + shorter. Walking shoes and appropriate equipment are recommended. + </desc> + <name lang="de">längere Wanderung</name> + <desc lang="de"> + Bei diesem Cache erwartet euch eine Wanderung von mehr als 5 Kilometer, + vom Ausgangspunkt bis zum Cache und wieder zurück. Im Gebirge und bei + entsprechenden Steigungen kann das Attribut auch bei kürzeren Wegstrecken + gesetzt sein. Gute Wanderschuhe und entsprechende Ausrüstung empfehlen sich. + </desc> + <name lang="es">Larga caminata</name> + <desc lang="es"> + Esta cache requiere una larga caminata - más de 5 kilometros de ida y + vuelta. En las montañas escarpadas o en otras áreas. Recomendados calzado + para caminar y equipo adecuado. + </desc> + <name lang="it">Lunga camminata</name> + <desc lang="it"> + Questa cache richiede una lunga camminata - più di 5 km tra andata e + ritorno. In montagna o in altre aree ripide, la distanza per una cache + del genere può essere minore. Sono raccomandati scarpe da escursione ed + equipaggiamento adeguato. + </desc> + </attr> + + <attr okapi_attr_id="wading" categories="de-accessibility"> + <groundspeak id="11" inc="true" name="May require wading" /> + <opencaching site_url="http://opencaching.de/" id="26" /> + <name lang="en">Swamp, marsh or wading</name> + <desc lang="en"> + This cache requires passing swampy or marshy ground our wading throuh + shallow water. Wear appropriate clothes. After rainfall, the terrain + may be very demanding or not passable at all. + </desc> + <name lang="de">sumpfig/matschiges Gelände / waten</name> + <desc lang="de"> + Bei diesem Cache geht es durch sumpfiges oder matschiges Gelände oder + es muss durch flaches Wasser gewatet werden. Entsprechende Kleidung + wird empfohlen. Nach Regenfällen kann das Gelände wesentlich schwerer + oder überhaupt nicht begehbar sein. + </desc> + <!-- TODO: add 'wading' to Spanish translation --> + <name lang="es">Pantano / terreno fangoso</name> + <desc lang="es"> + Esta cache requiere la superación de pantanos. Usar ropa apropiada. + Después de la lluvia, el suelo puede ser difícil o no factible. + </desc> + <!-- TODO: add 'wading' to Italian translation --> + <name lang="it">Palude o marcita</name> + <desc lang="it"> + Questa cache richiede il superamento di terreno paludoso o + acquitrinoso. Indossare un abbigliamento adeguato. Dopo la pioggia, + il terreno può essere molto impegnativo o non praticabile a tutti. + </desc> + </attr> + + <attr okapi_attr_id="steep" categories="de-accessibility"> + <opencaching site_url="http://opencaching.de/" id="27" /> + <name lang="en">Hilly area</name> + <desc lang="en"> + One or more ascents lie between you and the cache. + </desc> + <name lang="de">hügeliges Gelände</name> + <desc lang="de"> + Auf dem Weg zum Geocache bzw. während der Cachesuche sind eine oder + mehrere Steigungen zu überwinden. + </desc> + <name lang="es">Terreno montañoso</name> + <desc lang="es"> + Una o más pendientes para acceder al cache. + </desc> + <name lang="it">Area collinare</name> + <desc lang="it"> + Una o più salite si trovano tra voi e la cache. + </desc> + </attr> + + <attr okapi_attr_id="climbing" categories="de-accessibility"> + <groundspeak id="10" inc="true" name="Difficult climbing" /> + <opencaching site_url="http://opencaching.de/" id="28" /> + <name lang="en">Some climbing (no gear needed)</name> + <desc lang="en"> + This cache requires some climbing and you may have to use your hands, + but you won’t need climbing gear. Be very careful during rainy weather + or before thunderstorms! + </desc> + <name lang="de">leichtes Klettern (ohne Ausrüstung)</name> + <desc lang="de"> + Während der Cachesuche ist leichtes Klettern notwendig, bei dem man sich + z.B. mit den Händen festhalten muss. Gute Trittsicherheit und + Schwindelfreiheit empfehlen sich. Es ist jedoch keine Spezialausrüstung + notwendig wie z.B. Sicherungsseil, Klettersteigset oder Steigeisen. + Besonders bei feuchter Witterung oder vor Gewittern sollte man mit der + entsprechenden Vorsicht handeln. + </desc> + <name lang="es">fácil de subir (sin equipo)</name> + <desc lang="es"> + Esta cache requiere un poco de escalada y puede ser necesario usar las + manos, pero no es necesario material de montaña. ¡Tenga mucho cuidado + durante la temporada de lluvias.! + </desc> + <name lang="it">Arrampicata (attrezzatura non necessaria)</name> + <desc lang="it"> + Questa cache richiede un po' di arrampicata e potrebbe essere necessario + usare le mani, ma non c'è bisogno di attrezzatura da arrampicata. + Prestare molta attenzione durante la stagione delle piogge o prima dei + temporali! + </desc> + </attr> + + <attr okapi_attr_id="swimming" categories="de-accessibility"> + <groundspeak id="12" inc="true" name="May require swimming" /> + <opencaching site_url="http://opencaching.de/" id="29" /> + <name lang="en">Swimming required</name> + <desc lang="en"> + This cache requires crossing a river or a lake. The water can be steep. + </desc> + <name lang="de">Schwimmen erforderlich</name> + <desc lang="de"> + Auf dem Weg zum Geocache muss ein Fluß oder See überquert werden. + Das Wasser ist tief genug um zu schwimmen. Je nach Örtlichkeit kann auch + ein Schlauchboot, Kajak oder ähnliches verwendet werden (näheres ist + in der Beschreibung zum Geocache zu finden). Die Entfernung ist aber ohne + besondere Ausdauer noch zu schwimmen. + </desc> + <name lang="es">Requiere nadar</name> + <desc lang="es"> + Esta cache requiere cruzar un río o un lago. El agua es lo suficientemente + profundo para nadar. Puede utilizar un barco, pero la distancia es lo + suficientemente corto como para ser asequible para un nadador. + </desc> + <name lang="it">Nuoto necessario</name> + <desc lang="it"> + Questa cache richiede l'attraversamento di un fiume o un lago. L'acqua è + abbastanza profonda per nuotare. È possibile utilizzare una barca, ma la + distanza è abbastanza breve per essere alla portata di un nuotatore medio. + </desc> + </attr> + + <attr okapi_attr_id="fee" categories="de-accessibility"> + <groundspeak id="2" inc="true" name="Access or parking fee" /> + <opencaching site_url="http://opencaching.de/" id="36" /> + <name lang="en">Access or parking fee</name> + <desc lang="en"> + You must pay an access or parking fee to access this cache. + </desc> + <name lang="de">Zugangs- bzw. Parkentgelt</name> + <desc lang="de"> + Um zum Cache zu gelangen, müsst ihr entweder einen Eintritt oder eine + Parkgebühr bezahlen. + </desc> + <name lang="es">Acceso o parking pagando</name> + <desc lang="es"> + Deberas pagar un acceso o estacionamiento para acceder a esta cache. + </desc> + <name lang="it">Tassa di ingresso o di parcheggio</name> + <desc lang="it"> + Devi pagare un accesso o parcheggio a pagamento per accedere a questa cache. + </desc> + </attr> + + <attr okapi_attr_id="bike" categories="de-accessibility"> + <groundspeak id="32" inc="true" name="Bicycles" /> + <opencaching site_url="http://opencaching.pl/" id="85" /> + <name lang="en">Bikes allowed</name> + <desc lang="en"> + You can reach the cache by bike. + </desc> + <name lang="pl">Dostępna rowerem</name> + <desc lang="pl"> + Można dojechać do skrzynki rowerem. + </desc> + <desc lang="de">Fahrräder erlaubt</desc> + </attr> + + <attr okapi_attr_id="nature" categories="de-location"> + <opencaching site_url="http://opencaching.pl/" id="60" /> + <name lang="en">Hidden in natural surroundings (forests, mountains, etc.)</name> <!-- i.e. not in a city? --> + <desc lang="en"> + The cache is hidden in a remote and quick place - a forest, wild + meadow, a swap, etc. + </desc> + <name lang="pl">Umiejscowiona na łonie natury (lasy, góry, itp.)</name> + <desc lang="pl"> + Umiejscowiona na łonie natury, z dala od cywilizacji - las, dzika + łąka, mokradła. + </desc> + <desc lang="de">in freier Natur versteckt</desc> + </attr> + + <attr okapi_attr_id="historic" categories="de-location"> + <opencaching site_url="http://opencaching.pl/" id="61" /> + <name lang="en">Historic site</name> + <desc lang="en"> + The cache is hidden near a historic site - a castle, battleplace, + cementary, old bunkers, etc. + </desc> + <name lang="pl">Miejsce historyczne</name> + <desc lang="pl"> + W sąsiedztwie miejsca historycznego - zamku, pałacu, pola bitwy, + cmentarza, ale także fortów czy bunkrów. + </desc> + <desc lang="de">historischer Ort</desc> + </attr> + + <attr okapi_attr_id="poi" categories="de-location"> + <opencaching site_url="http://opencaching.de/" id="30" /> + <name lang="en">Point of interest</name> + <desc lang="en"> + There is a point of interest at the cache, like a nice scenic view + or a larger castle ruin. This place is worth visiting it even + without a geocache nearby. + </desc> + <name lang="de">interessanter Ort</name> + <desc lang="de"> + Der Geocache ist in unmittelbarer Nähe zu einer Sehenswürdigkeit + versteckt. Das kann ein z.B. schüner Aussichtspunkt oder eine größere + Burgruine sein. Ein Besuch würde sich auch ohne besonderen Anlass + (den Geocache) lohnen. + </desc> + <name lang="es">Punto de interes</name> + <desc lang="es"> + Hay un monumento cerca del cache, como un paisaje hermoso o un castillo + en ruinas. Este lugar es digno de visitar, incluso sin un geocache cerca. + </desc> + <name lang="it">Punto di interesse</name> + <desc lang="it"> + C'è un punto di interesse alla cache, come un bel panorama o di un + castello in rovina. Questo luogo merita una visita anche senza una + geocache vicina. + </desc> + </attr> + + <attr okapi_attr_id="indoor" categories="de-location"> + <opencaching site_url="http://opencaching.de/" id="33" /> + <name lang="en">Hidden wihin enclosed rooms (caves, buildings etc.)</name> + <desc lang="en"> + This geocache is not hidden in the open air, but within a building, + a cave or similar. + </desc> + <name lang="de">in geschlossenen Räumen (Höhle, Gebäude, etc.)</name> + <desc lang="de"> + Das Ziel des Geocaches liegt nicht im Freien, sondern zum Beispiel in + einem Gebäude oder einer Höhle. + </desc> + <name lang="es">en espacios confinados (cuevas, edificios, etc)</name> + <desc lang="es"> + Este geocache no está al aire libre, esta oculto dentro de un edificio, + una cueva o similares. + </desc> + <name lang="it">All'interno di stanze chiuse (caverne, edifici, ecc.)</name> + <desc lang="it"> + Questa geocache non è nascosta all'aria aperta ma all'interno di un + edificio, di una grotta o simili. + </desc> + </attr> + + <attr okapi_attr_id="submerged" categories="de-location"> + <opencaching site_url="http://opencaching.de/" id="34" /> + <name lang="en">Hidden under water</name> + <desc lang="en"> + This cache or one of the stages is placed underwater. + You will get wet when doing this cache. + </desc> + <name lang="de">Im Wasser versteckt</name> + <desc lang="de"> + Der Geocache oder eine der Stationen ist im Wasser versteckt. Um die + Aufgabe zu lösen muss man ggf. das Wasser betreten, schwimmen oder tauchen. + </desc> + <name lang="es">En el agua</name> + <!-- TODO: update Spanish translation, English and German descriptions have slightly changed --> + <desc lang="es"> + Esta cache o una de sus etapas se encuentran bajo el agua. Usted debe + entrar en el agua, nadar o zambullirse. + </desc> + <name lang="it">Nell'acqua</name> + <!-- TODO: update Italian translation, English and German descriptions have slightly changed --> + <desc lang="it"> + Questa cache o uno dei suoi stadi sono posizionati sott'acqua. Devi + entrare in acqua, nuotare o fare una immersione. + </desc> + </attr> + + <attr okapi_attr_id="parking" categories="de-facilities"> + <groundspeak id="25" inc="true" name="Parking available" /> + <opencaching site_url="http://opencaching.de/" id="18" /> + <name lang="en">Parking area nearby</name> + <desc lang="en"> + A nearby parking area is situated as starting point for doing this cache. + </desc> + <name lang="de">Parkplatz in der Nähe</name> + <desc lang="de"> + Es gibt in der Nähe einen Parklplatz, der sich als Startpunkt für die + Cachesuche eignet. + </desc> + <name lang="es">Parking cercano</name> + <desc lang="es"> + Una zona de aparcamiento se encuentra cerca del punto de partida de + este cache. + </desc> + <name lang="it">Parcheggio nei pressi</name> + <desc lang="it"> + Una area di parcheggio è situata nei pressi del punto di partenza di + questa cache. + </desc> + </attr> + + <attr okapi_attr_id="public-transport" categories="de-facilities"> + <groundspeak id="26" inc="true" name="Public transportation" /> + <opencaching site_url="http://opencaching.de/" id="19" /> + <name lang="en">Public transportation</name> + <desc lang="en"> + This cache is located outside of urban areas and has a public + transport station nearby. + </desc> + <name lang="de">erreichbar mit ÖVM</name> + <desc lang="de"> + Dieser Cache lässt sich mit Hilfe von öffentlichen Verkehrsmitteln erreichen + und liegt außerhalb von Städten. + </desc> + <name lang="es">Transporte Público</name> + <desc lang="es"> + Este cache se encuentra también fuera de las zonas urbanas y una + estación de transporte público. + </desc> + <name lang="it">Trasporto pubblico</name> + <desc lang="it"> + Questa cache è situata al difuori di aree urbane e ha una stazione di + trasporto pubblico nelle vicinanze. + </desc> + </attr> + + <attr okapi_attr_id="drinking-water" categories="de-facilities"> + <groundspeak id="27" inc="true" name="Drinking water nearby" /> + <opencaching site_url="http://opencaching.de/" id="20" /> + <name lang="en">Drinking water nearby</name> + <desc lang="en"> + There is drinking water along the trail or near the cache. This may be + useful especially especially when doing event caches, longer hikes or + caches at probably dirty locations. + </desc> + <name lang="de">Trinkwasser in der Nähe</name> + <desc lang="de"> + Während der Cachetour oder in der Nähe des Geocaches ist Trinkwasser + verfügbar. Besonders bei Event-Caches, längeren Multicaches und bei + Geocaches wo man vermutlich schmutzig wird kann dies hilfreich sein. + </desc> + <name lang="es">Agua potable en las cercanias</name> + <desc lang="es"> + Hay agua potable a lo largo de la ruta o cerca de la cache. Este + atributo es especialmente útil en la planificación de Eventos, + o caches con viajes largos a lugares como las cuevas o minas + probablemente esté sucio. + </desc> + <name lang="it">Acqua potabile nei pressi</name> + <desc lang="it"> + C'è acqua potabile lungo il percorso o nelle vicinanze della cache. + Questo attributo è utile soprattutto nella pianificazione di cache + evento, di lunghe escursioni o di cache in luoghi probabilmente + sporchi come le grotte o le miniere. + </desc> + </attr> + + <attr okapi_attr_id="restrooms" categories="de-facilities"> + <groundspeak id="28" inc="true" name="Public restrooms nearby" /> + <opencaching site_url="http://opencaching.de/" id="21" /> + <name lang="en">Public restrooms nearby</name> + <desc lang="en"> + There are public restrooms along the way or near the cache. + </desc> + <name lang="de">öffentliche Toilette in der Nähe</name> + <desc lang="de"> + Während der Cachetour oder in der Nähe des Geocaches ist eine öffentliche + Toilette verfügbar. + </desc> + <name lang="es">Aseos públicos cercanos</name> + <desc lang="es"> + Hay baños públicos a lo largo de la carretera o en las proximidades + del cache. + </desc> + <name lang="it">Bagni pubblici nei pressi</name> + <desc lang="it"> + Ci sono WC pubblici lungo la strada o nelle vicinanze della cache. + </desc> + </attr> + + <attr okapi_attr_id="phone" categories="de-facilities"> + <groundspeak id="29" inc="true" name="Telephone nearby" /> + <opencaching site_url="http://opencaching.de/" id="22" /> + <name lang="en">Public phone nearby</name> + <desc lang="en"> + There is a public phone along the way or near the cache. + </desc> + <name lang="de">Telefon in der Nähe</name> + <desc lang="de"> + Während der Cachetour oder in der Nähe des Geocaches gibt es ein + öffentliches Telefon. + </desc> + <name lang="es">Teléfono Público en las cercanias</name> + <desc lang="es"> + Hay teléfonos públicos en la carretera o en las proximidades del cache. + </desc> + <name lang="it">Telefono pubblico nei pressi</name> + <desc lang="it"> + Ci sono telefoni pubblici lungo la strada o nelle vicinanze della cache. + </desc> + </attr> + + <attr okapi_attr_id="first-aid" categories="de-facilities"> + <opencaching site_url="http://opencaching.de/" id="23" /> + <name lang="en">First aid available</name> + <desc lang="en"> + There is a first aid station, call box, mountain rescue or similar + arrangement near the cache. + </desc> + <name lang="de">Erste Hilfe verfügbar</name> + <desc lang="de"> + In der Nähe des Caches findet ihr eine Erste Hilfe-Station, Notrufsäule, + Bergwacht oder entsprechende Einrichtung. + </desc> + <name lang="es">Disponible socorro rapido</name> + <desc lang="es"> + Hay un punto de socorro, un teléfono para pedir ayuda, un centro de + rescate de montaña o similar cerca del cache. + </desc> + <name lang="it">Disponibile pronto soccorso</name> + <desc lang="it"> + C'è un pronto soccorso, un telefono per chiamate di soccorso, un centro + di soccorso alpino o simili nelle vicinanze della cache. + </desc> + </attr> + + <attr okapi_attr_id="24-hours" categories="de-time-and-seasons"> + <groundspeak id="13" inc="true" name="Available at all times" /> + <opencaching site_url="http://opencaching.de/" id="38" /> + <name lang="en">Available 24/7</name> + <desc lang="en"> + This cache can be found at any time of day or week. + </desc> + <name lang="de">rund um die Uhr machbar</name> + <desc lang="de"> + Dieser Cache ist jederzeit machbar, sowohl am Tage als auch in der Nacht. + </desc> + <name lang="es">Disponible las 24 horas</name> + <desc lang="es"> + Esta cache se puede encontrar tanto de día como de noche. + </desc> + <name lang="it">Disponibile 24 ore</name> + <desc lang="it"> + Questa cache può essere trovata sia di giorno che di notte. + </desc> + </attr> + + <attr okapi_attr_id="not-24-hours" categories="de-time-and-seasons"> + <groundspeak id="13" inc="false" name="Available at all times" /> + <opencaching site_url="http://opencaching.pl/" id="80" /> + <opencaching site_url="http://opencaching.de/" id="39" /> + <name lang="en">Not 24/7</name> + <desc lang="en"> + This cache can only be done at certain times of day or week - see the cache + description for more details. For example, the cache may be placed in an + area with restricted opening hours. + </desc> + <name lang="pl">Dostępna w określonych godzinach</name> + <desc lang="pl"> + Dostępna w określonych dniach, godzinach, często wstęp płatny. + Często będzie to muzeum lub skansen. Szczegółowe informacje o + dostępności powinny znajdować się w opisie skrzynki. + </desc> + <name lang="de">nur zu bestimmten Uhrzeiten</name> + <desc lang="de"> + Dieser Cache lässt sich nur zu bestimmten Tageszeiten absolvieren. + Nähere Angaben sind in der Beschreibung des Caches zu finden. + </desc> + <name lang="es">Sólo disponible a ciertas horas</name> + <desc lang="es"> + Esta cache se puede hacer solamente en ciertos momentos del día - + véase la descripción de caché para obtener más detalles. + </desc> + <name lang="it">Disponibile solo in certi orari</name> + <desc lang="it"> + Questa cache può essere cercata solo a certe ore del giorno - + vedi la descrizione per ulteriori informazioni. + </desc> + </attr> + + <attr okapi_attr_id="daycache" categories="de-time-and-seasons"> + <groundspeak id="14" inc="false" name="Recommended at night" /> + <opencaching site_url="http://opencaching.de/" id="40" /> + <name lang="en">Not recommended at night</name> + <desc lang="en"> + Searching for this cache is not recommended by night. It might be + dangerous, or the cache may be hidden in an area where flashlights + may attract unwanted attention. + </desc> + <name lang="de">nur tagüber</name> + <desc lang="de"> + Dieser Cache lässt sich nur tagsüber angehen, zum Beispiel weil das Gelände + gefährlich ist oder die Suche mit Taschenlampen in einem Wohngebiet negativ + auffallen würde. + </desc> + <name lang="es">solo por el día</name> + <desc lang="es"> + Deberas encontrar este cache sólo durante el día. Por ejemplo, el área pued + ser peligroso y contienen rocas o abismos. O bien, el uso de linternas puede + ser imposible porque sería sospechoso en una zona residencial. + </desc> + <name lang="it">solo di giorno</name> + <desc lang="it"> + Si dovrebbe cercare questa cache solamente durante il giorno. Ad esempio, + l'area può essere pericolosa e contenere scogliere o abissi. Oppure, + l'utilizzo di torce elettriche potrebbe essere impossibile perché + risulterebbe sospetto all'interno di una zona residenziale. + </desc> + </attr> + + <attr okapi_attr_id="night-recommended" categories="de-time-and-seasons"> + <!-- + GS has "night cache" (52) and "recommended at night" (14). + night cache = can normally ONLY be done at night, reflectors etc. + recommended at night = can well be done at night + + On OCPL there is no distinction between these two. OCPL uses + "Recommended at night" attribute for "Night caches" too. + --> + <groundspeak id="14" inc="true" name="Recommended at night" /> + <opencaching site_url="http://opencaching.pl/" id="91" /> + <name lang="en">Recommended at night</name> + <desc lang="pl"> + It is recommended to search for this cache by night. I.e. there + might be some light-reflecting surfaces involved which are usually + invisible during daylight. + </desc> + <name lang="pl">Zalecane szukanie nocą</name> + <desc lang="pl"> + Aby znaleźć skrzynkę zalecane jest poszukiwanie jej nocą, ze + względu na miejsce ukrycia lub użyte elementy odblaskowe, których + oświetlenie umożliwia odnalezienie skrzynki. + </desc> + <name lang="de">am besten nachts findbar</name> + </attr> + + <attr okapi_attr_id="nightcache" categories="de-time-and-seasons"> + <!-- + GS has "night cache" (52) and "recommended at night" (14). + night cache = can normally ONLY be done at night, reflectors etc. + recommended at night = can well be done at night + --> + <groundspeak id="52" inc="true" name="Night Cache" /> + <opencaching site_url="http://opencaching.de/" id="1" /> + <name lang="en">Only at night</name> + <desc lang="en"> + This geocache can be found at night only - it is a so-called night cache. + There may be reflectors which have to be flashlighted and will point + to the hiding place, or other special night-caching mechanisms. + </desc> + <name lang="de">nur bei Nacht</name> + <desc lang="de"> + Der Geocache kann nur bei Nacht gelöst werden und wird deshalb Nachtcache + genannt. Zum Beispiel mössen Reflektoren mit einer Taschenlampe + angeleuchtet werden, die dann den Weg zum Versteck zeigen. + </desc> + <name lang="es">Sólo por la noche</name> + <desc lang="es"> + Esta cache se puede encontrar solamente por la noche - tienes que + considerar cache notturna. Puede haber placas reflectantes que + brillaran y te llevaran al cache, o otros mecanismo especiales para + caches nocturnos. + </desc> + <name lang="it">Solo di notte</name> + <desc lang="it"> + Questa cache può essere trovata solo di notte - è una cosiddetta + cache notturna. Ci possono essere targhette riflettenti che devono + essere illuminate e ti conducono al nascondiglio, o altri speciali + meccanismi di caching notturno. + </desc> + </attr> + + <attr okapi_attr_id="all-seasons" categories="de-time-and-seasons"> + <groundspeak id="62" inc="false" name="Seasonal access" /> + <opencaching site_url="http://opencaching.de/" id="42" /> + <name lang="en">All seasons</name> + <desc lang="en"> + This cache can be found the whole year round, while difficulty may + depend on seasons. + </desc> + <name lang="de">ganzjähig zugänglich</name> + <desc lang="de"> + Dieser Cache lässt sich während des gesamten Jahres finden, wobei je + nach Jahreszeit die Schwierigkeit bei der Suche schwanken kann. + </desc> + <name lang="es">Todas las temporadas</name> + <desc lang="es"> + Esta cache se encuentrar durante todo el año, mientras que la dificultad + puede depender de las estaciones. + </desc> + <name lang="it">Tutte le stagioni</name> + <desc lang="it"> + Questa cache si trova tutto l'anno, mentre la difficoltà può dipendere + dalle stagioni. + </desc> + </attr> + + <attr okapi_attr_id="not-all-seasons" categories="de-time-and-seasons"> + <groundspeak id="62" inc="true" name="Seasonal access" /> + <opencaching site_url="http://opencaching.de/" id="60" /> + <name lang="en">Only available during specified seasons</name> + <desc lang="en"> + This cache can be done at certain seasons only - see the cache + description for more details. + </desc> + <name lang="de">Nur zu bestimmten Zeiten im Jahr</name> + <desc lang="de"> + Dieser Cache lässt sich nur zu bestimmten Zeite im Jahr absolvieren. + Näheres ist in der Cachebeschreibung angegeben. + </desc> + <name lang="es">Sólo disponible durante las estaciones especificadas</name> + <desc lang="es"> + Esta cache se puede hacer en ciertas épocas del año solamente - vea la + descripción de cache para obtener más detalles. + </desc> + <name lang="it">Disponibile solo in certe stagioni</name> + <desc lang="it"> + Questa cache può essere cercata solo in certe stagioni - vedi la + descrizione per ulteriori informazioni. + </desc> + </attr> + + <attr okapi_attr_id="np-season" categories="de-time-and-seasons"> + <opencaching site_url="http://opencaching.de/" id="43" /> + <name lang="en">Breeding season / protected nature</name> + <desc lang="en"> + Don’t seek this cache during animal breeding season! See the cache + description on which time of year must be avoided. Also, pay + attention to the local terms and signs regarding nature protection. + </desc> + <name lang="de">Brutsaison / Naturschutz</name> + <desc lang="de"> + Dieser Cache sollte in der Brutsaison nicht absolviert werden. In der + Beschreibung sollte angegeben sein, welche Jahreszeit davon betroffen ist. + Achte bitte auch auf die örtliche Beschilderung zum Naturschutz. + </desc> + <name lang="es">Temporada de reproducción / protección de la naturaleza</name> + <desc lang="es"> + ¡No intente esta cache durante la temporada de cría de los animales! + Vvéase la descripción del cache de la época del año debe ser evitado. + Preste atención también a las condiciones o signos en cuanto al respeto + por la naturaleza. + </desc> + <name lang="it">Stagione di riproduzione / natura protetta</name> + <desc lang="it"> + Non cercare questa cache durante il periodo riproduttivo degli animali! + Vedi descrizione della cache quale periodo dell'anno debba essere evitato. + Prestate anche attenzione alle condizioni o ai cartelli riguardo il + rispetto della natura. + </desc> + </attr> + + <attr okapi_attr_id="snow-proof" categories="de-time-and-seasons"> + <groundspeak id="15" inc="true" name="Available during winter" /> + <opencaching site_url="http://opencaching.de/" id="44" /> + <name lang="en">Available during winter</name> + <desc lang="en"> + This cache can be found even after heavy snowing. All stages and the + geocache are hidden in a snow-safe way: they will not be covered by + fallen snow, or ice, etc. + </desc> + <name lang="de">schneesicheres Versteck</name> + <desc lang="de"> + Dieser Cache lässt sich auch nach starkem Schneefall suchen. Die einzelnen + Stationen und der Geocache sind so versteckt, dass sie nicht von Schnee + verdeckt werden, bzw. von Schneehaufen die durch Räumfahrzeuge entstehen. + </desc> + <name lang="es">Nieve en el escondite</name> + <desc lang="es"> + Este cache también se puede encontrar después de fuertes nevadas. Todas + las fases y geocaches se esconde en lugares seguros para la caída de la + nieve, no será cubierto por acumulaciones de nieve. + </desc> + <name lang="it">Luogo a prova di neve</name> + <desc lang="it"> + Questa cache può essere trovata anche dopo forti nevicate. Tutte le fasi + e la geocache sono nascosti in luoghi sicuri per la neve: non saranno + coperti da neve caduta né da cumuli di neve creati ad esempio da veicoli + spalaneve. + </desc> + </attr> + + <attr okapi_attr_id="lowwater" categories="de-time-and-seasons"> + <opencaching site_url="http://opencaching.de/" id="41" /> + <name lang="en">Not at high water level</name> + <desc lang="en"> + This cache can be done only at low or normal water level. It is + inaccessible during flood. + </desc> + <name lang="de">nicht bei Hochwasser oder Flut</name> + <desc lang="de"> + Der Geocache kann nur bei bei niedrigem oder normalem Wasserstand + bzw. bei Ebbe gesucht werden. Bei Hochwasser oder Flut ist er + unzugänglich. + </desc> + <!-- TODO: Spanish and Italian translations --> + </attr> + + <attr okapi_attr_id="compass" categories="de-tools"> + <opencaching site_url="http://opencaching.pl/" id="47" /> + <opencaching site_url="http://opencaching.de/" id="47" /> + <name lang="en">Compass required</name> + <desc lang="en"> + A compass is required. + </desc> + <name lang="pl">Potrzebny kompas</name> + <desc lang="pl"> + Kompas może okazać się niezbędny aby dotrzeć do wskazanego miejsca + skrzynki. + </desc> + <name lang="de">Kompass</name> + <desc lang="de"> + Für diesen Cache braucht ihr einen funktionierenden Kompass für Peilungen + oder Orientierungen. + </desc> + <name lang="es">Brújula</name> + <desc lang="es"> + Se necesita una brújula. + </desc> + <name lang="it">Bussola</name> + <desc lang="it"> + E' necessaria una bussola. + </desc> + </attr> + + <attr okapi_attr_id="pen" categories="de-tools"> + <opencaching site_url="http://opencaching.pl/" id="48" /> + <name lang="en">Take something to write</name> + <desc lang="en"> + There is no pencil in the cache. Take something to write with. + </desc> + <name lang="pl">Weź coś do pisania</name> + <desc lang="pl"> + Skrzynka nie zawiera ołówka, weź ze sobą coś do pisania. + </desc> + <desc lang="de">Stift mitbringen</desc> + </attr> + + <attr okapi_attr_id="digging" categories="de-tools"> + <opencaching site_url="http://opencaching.pl/" id="81" /> + <name lang="en">You may need a shovel</name> + <desc lang="en"> + The cache may require more digging. A shovel might come in handy. + </desc> + <name lang="pl">Potrzebna łopatka</name> + <desc lang="pl"> + Skrzynka jest zakopana w ziemi. + </desc> + <desc lang="de">Grabwerkzeug benötigt</desc> + </attr> + + <attr okapi_attr_id="flashlight" categories="de-tools"> + <groundspeak id="44" inc="true" name="Flashlight required" /> + <opencaching site_url="http://opencaching.pl/" id="82" /> + <opencaching site_url="http://opencaching.de/" id="48" /> + <name lang="en">Flashlight required</name> + <desc lang="en"> + You will need a flashlight to find this cache. + </desc> + <name lang="pl">Potrzebna latarka</name> + <desc lang="pl"> + Przy poszukiwaniach tej skrzynki potrzebna jest latarka. + </desc> + <name lang="de">Taschenlampe</name> + <desc lang="de"> + Um diesen Cache anzugehen, benötigt ihr eine funktionstüchtige + Taschenlampe. Denkt auch an Ersatzbatterien. + </desc> + <name lang="es">Linterna</name> + <desc lang="es"> + Es necesario una linterna para encontrar este cache. ¡No se olvide de las + baterías de repuesto! + </desc> + <name lang="it">Lampada tascabile</name> + <desc lang="it"> + E' necessaria una torcia portatile per trovare questa cache. Non + dimenticate le batterie di riserva! + </desc> + </attr> + + <attr okapi_attr_id="climbing-gear" categories="de-tools"> + <groundspeak id="3" inc="true" name="Climbing gear" /> + <opencaching site_url="http://opencaching.de/" id="49" /> + <name lang="en">Climbing gear required</name> + <desc lang="en"> + For this cache, you will need climbing equipment and the knowledge + how to use it properly. If you are a beginner, don’t do it alone but + use the support of an experienced climber or mountaineer. + </desc> + <name lang="de">Kletterzeug</name> + <desc lang="de"> + Um diesen Cache absolvieren zu können, benötigt ihr neben der normalen + Ausrüstung auch noch Kletterausrüstung, und entsprechendes Wissen um + deren Handhabung und ums Klettern. Laien sollten sich auf jeden Fall + von einem erfahrenen Kletterer oder Bergsteiger unterstützen lassen. + </desc> + <name lang="es">Equipo de escalada</name> + <desc lang="es"> + Para este cache, tendrá que utilizar los equipos y saber cómo utilizarlo + correctamente. Si usted es un principiante, no lo haga solos, sino que + utiliza el apoyo de un experimentado escalador o alpinista. + </desc> + <name lang="it">Attrezzatura per arrampicata</name> + <desc lang="it"> + Per questa cache, avrete bisogno di materiale da arrampicata e di saperlo + usare correttamente. Se sei un principiante, non farlo da solo, ma + utilizza il sostegno di uno scalatore esperto o un alpinista. + </desc> + </attr> + + <attr okapi_attr_id="cave-equipment" categories="de-tools"> + <opencaching site_url="http://opencaching.de/" id="50" /> + <name lang="en">Cave equipment required</name> + <desc lang="en"> + This geocache is hidden in a cave, and you should use appropriate + equipment to access it. Beware: Even small caves may confront you with + unforeseen problems and dangers, like thunder storms (water!) or a + sprained ankle. Have advice first from cave-experienced people! Also + take care of protected nature; e.g. bat places must not be disturbed. + </desc> + <name lang="de">Höhlenzeug</name> + <desc lang="de"> + Der Geocache ist in einer Höhle versteckt und man sollte entsprechende + Ausrüstung mitbringen. Vorsicht: Bereits kleinste Höhlensysteme können + bei unvorhergesehenen Problem z.B. Gewittern (Wasser!) oder einem + verstauchten Knöchel sehr gefährlich werden! Ihr solltet euch vorab + gründlich bei erfahreren Höhlengehern informieren. Beachtet auch den + Naturschutz – Fledermausquartiere dürfen nicht gestört werden! + </desc> + <name lang="es">Equipación para cuevas</name> + <desc lang="es"> + Este geocache está escondido en una cueva, y se debe utilizar el equipo + adecuado para acceder a ella. Tenga en cuenta que incluso las pequeñas + cuevas pueden prever los problemas imprevistos y peligros, como durante + las tormentas o con un esguince de tobillo. ¡Acceda con personas + experimentadas en cuevas! También debe protegerse la naturaleza sobre + todo en esos lugares donde los murciélagos no deben ser molestados. + </desc> + <name lang="it">Attrezzatura per grotta</name> + <desc lang="it"> + Questa geocache è nascosta in una grotta, e si dovrebbe utilizzare + attrezzature adeguate per accedervi. Attenzione: anche piccole grotte + possono prevedere problemi imprevisti e pericoli, come in caso di + temporali (acqua!) o una caviglia slogata. Consigliatevi prima con + persone che abbiano esperienza di grotte! Abbiate anche cura della + natura protetta, ad esempio dei luoghi dove i pipistrelli non devono + essere disturbati. + </desc> + </attr> + + <attr okapi_attr_id="diving-equipment" categories="de-tools"> + <groundspeak id="5" inc="true" name="Scuba gear" /> + <opencaching site_url="http://opencaching.de/" id="51" /> + <name lang="en">Diving equipment required</name> + <desc lang="en"> + You will need diving equipment to find this geocache. The water depth + of the cache location is specified in the description. Please note that + secure diving requires special training. Without diving experience, + you may search this cache in company of a diving teacher. + </desc> + <name lang="de">Taucherausrüstung</name> + <desc lang="de"> + Um den Geocache zu finden benötigt ihr eine Tauchausrüstung. In welcher + Tiefe der Geocache liegt ist in der Beschreibung angegeben. Bitte beachtet, + dass Ihr für einen sicheren Tauchgang eine entsprechende Ausbildung + benötigt. Als Nicht-Taucher könnt ihr den Geocache evtl. zusammen mit + einem Tauchlehrer suchen. + </desc> + <name lang="es">Diving equipment</name> + <desc lang="es"> + Necesitará un equipo de buceo para encontrar este geocache. La + profundidad del agua en la ubicación de la cache se especifica en la + descripción. Tenga en cuenta que el buceo requiere un entrenamiento + especial. Sin experiencia de buceo, puedes buscar por el caché, junto + con un buceador experimentado. + </desc> + <name lang="it">Equipo de buceo</name> + <desc lang="it"> + Avrete bisogno di attrezzatura subacquea per trovare questa geocache. + La profondità d'acqua nella posizione della cache viene specificata nella + descrizione. Si prega di notare che l'immersione in tutta sicurezza + richiede una formazione specifica. Senza esperienza di immersioni, è + possibile cercare questa cache in compagnia di un insegnante di sub. + </desc> + </attr> + + <attr okapi_attr_id="special-tools" categories="de-tools"> + <groundspeak id="51" inc="true" name="Special tool required" /> + <opencaching site_url="http://opencaching.pl/" id="83" /> + <opencaching site_url="http://opencaching.de/" id="46" /> + <name lang="en">Special tools required</name> + <desc lang="en"> + You will need special equipment which is not specified by other attributes. + See the cache description on what tools are required. + </desc> + <name lang="pl">Wymagany dodatkowy sprzęt</name> + <desc lang="pl"> + Niezbędny jest dodatkowy, niestandardowy sprzęt - może to być np. + kajak, sprzęt wspinaczkowy, ale również kalkulator, kalosze itp. + Ogólnie przedmioty, które nie należą do standardowego wyposażenia + poszukiwacza. + </desc> + <name lang="de">spezielle Ausrüstung</name> + <desc lang="de"> + Für diesen Cache benötigst du weitere Ausrüstung, die nicht durch die + anderen Attribute angegeben ist und nicht zur Standardausrüstung eines + Geocachers gehört. Was genau du benütigst, ist in der Beschreibung + angegeben. + </desc> + <name lang="es">Equipamiento especial</name> + <desc lang="es"> + Necesitarás un equipo especial no especificado por otros atributos. + </desc> + <name lang="it">Equipaggiamento speciale</name> + <desc lang="it"> + Avrete bisogno di attrezzature speciali non specificate da altri attributi. + </desc> + </attr> + + <attr okapi_attr_id="boat" categories="de-tools"> + <groundspeak id="4" inc="true" name="Boat" /> + <opencaching site_url="http://opencaching.pl/" id="86" /> + <opencaching site_url="http://opencaching.de/" id="52" /> + <name lang="en">Requires a boat</name> + <desc lang="en"> + This cache can usually be found only when using a watercraft. + Swimming is difficult or impossible because of the distance or currents. + See the cache description for more details. + </desc> + <name lang="pl">Wymaga sprzętu pływającego</name> + <desc lang="pl"> + Skrzynka z tym atrybutem najczęściej może być zdobyta jedynie przy + użyciu sprzętu pływającego (łodzi, pontonu, kajaka itp.) Dopłynięcie + wpław jest trudne lub niemożliwe, ze względu na dystans, silne + prądy itp. + </desc> + <name lang="de">Wasserfahrzeug</name> + <desc lang="de"> + Der Geocache kann – normalerweise – nicht ohne ein Wasserfahrzeug gefunden + werden. Zum Geocache kann wegen der Entfernung oder Strömung nicht + geschwommen werden. Details dazu sind in der Beschreibung des Geocaches + angegeben. + </desc> + <name lang="es">Barca</name> + <desc lang="es"> + Este cache por lo general sólo se puede encontrar con una moto de agua. + Nadando es imposible debido a la distancia o la corriente. Véase la + descripción del cache para obtener más detalles. + </desc> + <name lang="it">Barca</name> + <desc lang="it"> + Questa cache di solito può essere trovata solo con una moto d'acqua. Il + nuoto è impossibile a causa della distanza o delle correnti. Vedi la + descrizione della cache per maggiori dettagli. + </desc> + </attr> + + <attr okapi_attr_id="nogps" categories="de-tools"> + <opencaching site_url="http://opencaching.de/" id="35" /> + <name lang="en">No GPS required</name> + <desc lang="en"> + This cache can be found without a GPS device. No additional coordinates + are used besides of the starting coordinates. + </desc> + <name lang="de">ohne GPS findbar</name> + <desc lang="de"> + Dieser Cache lässt sich auch ohne GPS-Empfänger finden. Die Aufgaben + sind so gestellt, dass man außer den Startkoordinaten keine weiteren + Koordinaten verwenden muss. + </desc> + <name lang="es">Sin GPS</name> + <desc lang="es"> + Esta cache se puede encuentra sin un dispositivo GPS. Detalles adicionales + no se utilizan, además de las coordenadas iniciales. + </desc> + <name lang="it">Senza GPS</name> + <desc lang="it"> + Questa cache può essere trovata senza un dispositivo GPS. Non sono + utilizzate coordinate addizionali oltre alle coordinate iniziali. + </desc> + </attr> + + <attr okapi_attr_id="dangerous-area" categories="de-dangers"> + <groundspeak id="23" inc="true" name="Dangerous area" /> + <opencaching site_url="http://opencaching.de/" id="9" /> + <opencaching site_url="http://opencaching.pl/" id="90" /> + <name lang="en">Dangerous area</name> + <desc lang="en"> + The cache is located within a dangerous area, and danges may not be + obvious, e.g. like high-traffic roads, steep ground or falling rocks. + Safety measures should be taken, especially when geocaching with + children, large groups of people or during bad weather conditions. + </desc> + <name lang="pl">Skrzynka niebezpieczna</name> + <desc lang="pl"> + Skrzynka jest ukryta w niebezpiecznym terenie. Jej poszukiwania mogą + narazić na niebezpieczeństwo wypadku lub urazu. + </desc> + <name lang="de">gefährliches Gebiet</name> + <desc lang="de"> + In dem Gebiet, wo der Geocache versteckt wurde, ist mit Gefahren zu + rechnen, die unter Umständen nicht auf den ersten Blick erkennbar sind. + Das können z.B. stark befahrene Straßen, steile Abhänge oder Steinschlag + sein. Deshalb sollte man bei Geocaching-Touren mit Kindern oder größeren + Gruppen entsprechende Vorsichtsmaßnahmen ergreifen und je nachdem auch + auf die Witterung achten (z.B. Regen bei steilen Abhängen). + Näheres zu den Gefahren ist in der Cachebeschreibung erläutert. + </desc> + <name lang="es">Zona Peligrosa</name> + <desc lang="es"> + El cache está situado en una zona peligrosa, como tales como carreteras + con mucho tráfico, terreno empinado o caída de rocas. Usted debe tomar + medidas de seguridad o evitar ir a buscar el caché, sobre todo con niños, + con grupos grandes o en condiciones meteorológicas adversas. + </desc> + <name lang="it">Area pericolosa</name> + <desc lang="it"> + La cache è situata in un'area pericolosa come strade ad alto traffico, + terreno ripido o caduta sassi. Si dovrebbero adottare misure di sicurezza + o evitare di andare a cercare la cache, in particolare nel geocaching con + bambini, con gruppi numerosi o in condizioni climatiche sfavorevoli. + </desc> + </attr> + + <attr okapi_attr_id="railway" categories="de-dangers"> + <opencaching site_url="http://opencaching.de/" id="10" /> + <name lang="en">Active railway nearby</name> + <desc lang="en"> + There are active railroads nearby. Please be careful, keep a safe + distance and cross the rails only at level crossings etc.! + </desc> + <name lang="de">aktive Eisenbahnlinie in der Nähe</name> + <desc lang="de"> + In der Nähe dieses Caches gibt es genutzte Eisenbahnlinien. Bitte seid + entsprechend vorsichtig und achtet darauf, abseits von Bahnübergängen keine + Gleise zu betreten. + </desc> + <name lang="es">Cerca del ferrocarril activo</name> + <desc lang="es"> + ¡Hay ferrocarriles activos en las proximidades. Por favor, tenga + cuidado, manteniendo una distancia segura y cruzar los rieles sólo + en los cruces de ferrocarril, etc.! + </desc> + <name lang="it">Ferrovia attiva nei pressi</name> + <desc lang="it"> + Ci sono ferrovie attive nelle vicinanze. Per favore usate cautela, + tenendo una distanza di sicurezza e attraversando le rotaie solo ai + passaggi a livello ecc.! + </desc> + </attr> + + <attr okapi_attr_id="cliff" categories="de-dangers"> + <groundspeak id="21" inc="true" name="Cliff / falling rocks" /> + <opencaching site_url="http://opencaching.de/" id="11" /> + <name lang="en">Cliff / Rocks</name> + <desc lang="en"> + There are cliffs or dangerous rocks nearby. Beware of falling rocks + at the lower side, and be careful at the upper side of cliffs - + especially with children and while mountain biking. It can be very + dangerous to take a steep slope towards a cliff, because you may not + notice in time where the former ends and the latter starts. + </desc> + <name lang="de">Klippen / Felsen</name> + <desc lang="de"> + In der Nähe des Caches gibt es Klippen oder Felsen. Unterhalb von + Felsen sollte man auf Steinschlag achten, von der Oberseite der Klippen + sollte man sich entsprechend vorsichtig nähern (insbesondere mit Kindern + oder Mountainbikes). Besonders gefährlich - und nicht immer erkennbar - + ist es, sich über einen Steilhang von oben an eine Klippe zu nähern. + </desc> + <name lang="es">Acantilado / Rocas</name> + <desc lang="es"> + Hay acantilados o rocas peligrososas en las cercanas. Tenga cuidado + cuando esté bajo las piedras caídas, y tenga cuidado cuando esté sobre + el acantilado - especialmente con los niños y el ciclismo. Puede ser + muy peligroso tomar un camino empinado para subir el acantilado porque + no se puede saber de antemano cuando el primero termina y comienza otra. + </desc> + <name lang="it">Scogliera / Rocce</name> + <desc lang="it"> + Ci sono scogliere o rocce pericolose nelle vicinanze. Fate attenzione + alla caduta pietre quando siete sotto, e siate cauti quando siete sopra + la scogliera - specialmente con bambini e in bicicletta. Può essere molto + pericoloso prendere un sentiero ripido per salire la scogliera, poiché + non potete sapere in anticipo quando la prima termina e inizia l'altra. + </desc> + </attr> + + <attr okapi_attr_id="hunting" categories="de-dangers"> + <groundspeak id="22" inc="true" name="Hunting" /> + <opencaching site_url="http://opencaching.de/" id="12" /> + <name lang="en">Hunting</name> + <desc lang="en"> + The geocache is placed within a hunting ground. At twilight and in the + dark, a flashlight or headlight should always be used for security + reasons. Be considerate when meeting hunters. + </desc> + <name lang="de">Jagdgebiet</name> + <desc lang="de"> + Der Geocache liegt in einem Jagdgebiet. Bei Dämmerung oder Dunkelheit + sollte man aus Sicherheitsgründen immer eine Taschenlampe oder + Stirnlampe verwenden. Bei Begegnungen mit Jägern ist gegenseitige + Rücksichtnahme angebracht. + </desc> + <name lang="es">Zona de Caza</name> + <desc lang="es"> + El geocache se coloca dentro de un coto de caza. Al caer la tarde y en + la oscuridad, una linterna o faro siempre debe utilizarse por razones + de seguridad. + </desc> + <name lang="it">Caccia</name> + <desc lang="it"> + La geocache è situata nei pressi di una area di caccia. Al crepuscolo + e al buio, dovrebbe sempre essere usata una torcia portatile o frontale + per ragioni di sicurezza. Incontrando i cacciatori è opportuna una + reciproca gentilezza. + </desc> + </attr> + + <attr okapi_attr_id="thorns" categories="de-dangers"> + <groundspeak id="39" inc="true" name="Thorns" /> + <opencaching site_url="http://opencaching.de/" id="13" /> + <name lang="en">Thorns</name> + <desc lang="en"> + There are thorns near the cache. Wear appropriate clothes. + </desc> + <name lang="de">Dornen</name> + <desc lang="de"> + In er Nähe des Geocaches gibt es Dornen. Entsprechende Kleidung und + evtl. Handschuhe sind zu empfehlen. + </desc> + <name lang="es">Espinas</name> + <desc lang="es"> + Hay espinas cerca de la caché. Use ropa apropiada. + </desc> + <name lang="it">Spine</name> + <desc lang="it"> + Ci sono spine nei pressi della cache. Indossare indumenti appropriati. + </desc> + </attr> + + <attr okapi_attr_id="ticks" categories="de-dangers"> + <groundspeak id="19" inc="true" name="Ticks" /> + <opencaching site_url="http://opencaching.de/" id="14" /> + <name lang="en">Ticks</name> + <desc lang="en"> + There are seasonably many ticks in this area. It is recommended to wear + long trousers and to check yourself for ticks after geocaching. + There are regional risk maps for <i>tick-borne encephalitis</i> on the + internet. + </desc> + <name lang="de">Zecken</name> + <desc lang="de"> + Je nach Saison gibt es in dem Gebiet besonders viele Zecken. Es wird + daher empfohlen, entsprechend lange Kleidung zu tragen und nach der + Cachetour nach Zecken Ausschau zu halten. FSME-Risikogebiete und + weitere Informationen zum Thema Zecken könnt ihr z.B. auf + <a href='http://www.meningitis.de'>www.meningitis.de</a> nachsehen. + </desc> + <name lang="es">Garrapatas</name> + <desc lang="es"> + Cada temporada hay un montón de garrapatas en este lubar. Y es + recomendable llevar pantalón largo y examinarse en busca de garrapatas + después de encontrar el cache. + </desc> + <name lang="it">Zecche</name> + <desc lang="it"> + Stagionalmente ci sono molte zecche in questa area. E' raccomandabile + indossare pantaloni lunghi e ispezionarsi alla ricerca di zecche dopo + il geocaching. In internet ci sono mappe di rischio per <i>encefalite + e borelliosi da morso di zecca</i>. + </desc> + </attr> + + <attr okapi_attr_id="mines" categories="de-dangers"> + <groundspeak id="20" inc="true" name="Abandoned mines" /> + <opencaching site_url="http://opencaching.de/" id="15" /> + <name lang="en">Abandoned mines</name> + <desc lang="en"> + This cache leads into a (former) mining area. There may be dangers by + collapsing adits, or you may need to enter adits. Be careful and use + appropriate equipment, especially in the dark. Old mines may be covered + by historic preservation. + </desc> + <name lang="de">Folgen des Bergbaus</name> + <desc lang="de"> + Der Cache führt in eine (ehemalige) Bergbauregion. Möglicherweise + bestehen Gefahren durch verstürzte Stollenmundlöcher oder es müssen + Stollen betreten werden. Entsprechende Ausrüstung und Vorsicht, + besonders bei Dunkelheit, wird empfohlen. Historische Bergwerke stehen + möglicherweise unter Denkmalschutz. + </desc> + <name lang="es">Mina abandonada</name> + <desc lang="es"> + Esta cache le llevará a un área de la mina (abandonado). Puede haber + peligro con el colapso de túneles o galerías que puede ser necesario para + cruzar. Tenga cuidado y use de equipo adecuado, especialmente en la + oscuridad. Las minas antiguas pueden ser objeto de preservación histórica. + </desc> + <name lang="it">Miniere abbandonate</name> + <desc lang="it"> + Questa cache vi porta in una area di miniera (abbandonata). Ci possono + essere pericoli per crollo di gallerie, o potrebbe essere necessario + attraversare gallerie. Fare attenzione e utilizzate attrezzature adeguate, + soprattutto al buio. Le vecchie miniere possono essere oggetto di + conservazione storica. + </desc> + </attr> + + <attr okapi_attr_id="poisonous-plants" categories="de-dangers"> + <groundspeak id="17" inc="true" name="Poisonous plants" /> + <opencaching site_url="http://opencaching.de/" id="16" /> + <name lang="en">Poisonous plants</name> + <desc lang="en"> + There are poisonous plants near the cache. Take care and prevent + children and dogs from touching or eating them. + </desc> + <name lang="de">giftige Pflanzen</name> + <desc lang="de"> + In der Nähe des Caches gibt es giftige Pflanzen. Achtet also insbesondere + darauf, dass Kinder und Hunde diese nicht anfassen oder essen. + </desc> + <name lang="es">Planta venenosa</name> + <desc lang="es"> + Hay plantas venenosas en las cercanías. Tenga cuidado y asegúrese de que + los niños o los perros no las toquen ni tragarlas. + </desc> + <name lang="it">Piante velenose</name> + <desc lang="it"> + Ci sono piante velenose nelle vicinanze. Fate attenzione e controllate + che bambini o cani non le tocchino o le ingoino. + </desc> + </attr> + + <attr okapi_attr_id="dangerous-animals" categories="de-dangers"> + <groundspeak id="18" inc="true" name="Dangerous animals" /> + <opencaching site_url="http://opencaching.de/" id="17" /> + <name lang="en">Dangerous animals</name> + <desc lang="en"> + The area is inhabited by possibly dangerous animals, e.g. rabies areas, + venomous snakes, scorpions or bears. + </desc> + <name lang="de">giftige/gefährliche Tiere</name> + <desc lang="de"> + In dem Gebiet sind Wildtiere angesiedelt, die für Menschen eine Gefahr + darstellen können, z.B. Tollwutgebiete, giftige Schlangen, Skorpione + oder Bären. + </desc> + <name lang="es">Animales Peligrosos</name> + <desc lang="es"> + Esta zona es frecuentada por los animales potencialmente peligrosos, + por ejemplo. zorros rabiosos, serpientes venenosas, escorpiones, osos. + </desc> + <name lang="it">Animali pericolosi</name> + <desc lang="it"> + Quest area è frequentata da animali potenzialmente pericolosi, ad es. + volpi rabide, serpenti velenosi, scorpioni, orsi. + </desc> + </attr> + + <attr okapi_attr_id="quick" categories="de-rating"> + <!-- TODO: There is a groundspeak attribute called "Takes less than + 1 hour", is it applicable here? I'm not sure... In OCPL this attribute + was called "One-minute cache", and the official description includes + a 15 minutes limit. --> + <opencaching site_url="http://opencaching.pl/" id="40" /> + <name lang="en">Quick cache</name> + <desc lang="en"> + It shouldn't take more than 15 minutes to find this cache. Also, + there should be a parking nearby. + </desc> + <name lang="pl">Szybka skrzynka</name> + <desc lang="pl"> + Jej znalezienie nie powinno zająć więcej niż 15 minut oraz jest + łatwy dojazd w pobliże skrzynki samochodem. + </desc> + <desc lang="de">schnell findbar</desc> + </attr> + + <attr okapi_attr_id="overnight" categories="de-rating"> + <opencaching site_url="http://opencaching.de/" id="37" /> + <name lang="en">Overnight stay necessary</name> + <desc lang="en"> + This cache cannot be done within a single day or a single night. + You will have to visit the location for more than one time, + or you must stay overnight. Preparation time is not included in this + calculation, but only the time on site. + </desc> + <name lang="de">Übernachtung erforderlich</name> + <desc lang="de"> + Der Geocache kann nicht mit einer einzigen Tages- oder Nachttour gelöst + werden. Er muss entweder mehrmals angefahren werden oder es muss vor Ort + übernachtet werden. Zeit für Recherchen vorab sind dabei nicht + berücksicht, sondern nur die Zeit vor Ort. + </desc> + <name lang="es">Necesario pernoctar</name> + <desc lang="es"> + No puedrá encontrar este cache en un solo día o durante la noche. Usted + tendrá que visitar el lugar más de una vez, o necesitará pasar la noche. + El tiempo de preparación no está incluido en este cálculo, sólo el tiempo + en el sitio. + </desc> + <name lang="it">Necessario pernottamento</name> + <desc lang="it"> + Non è possibile trovare questa cache in un solo giorno o una sola notte. + Dovrete visitare il percorso per più di una volta, oppure è necessario il + pernottamento. Il tempo di preparazione non è incluso in questo calcolo, + ma solo il tempo sul sito. + </desc> + </attr> + + <attr okapi_attr_id="children6" categories="de-rating"> + <groundspeak id="6" inc="true" name="Recommended for kids" /> <!-- Not sure if this is correct. --> + <opencaching site_url="http://opencaching.pl/" id="41" /> + <name lang="en">Take your children</name> + <desc lang="pl"> + This search if simple and safe. It's okay to take small children + with you. + </desc> + <name lang="pl">Można zabrać dzieci</name> + <desc lang="pl"> + Jej poszukiwanie jest przyjemne, bezpieczne i można bez obaw + wybrać się z małymi dziećmi. + </desc> + </attr> + + <attr okapi_attr_id="children10" categories="de-rating"> + <groundspeak id="6" inc="true" name="Recommended for kids" /> + <opencaching site_url="http://opencaching.de/" id="59" /> + <name lang="en">Suited for children (10-12 yo)</name> + <desc lang="en"> + This geocache is suitable for children. All challenges can be solved by + child in the age of 10 to 12 years and the terrain has no risks + (like highways, abysms). There should be a large geocache container with + trading items inside and the challenges be interesting. + </desc> + <name lang="de">kindgerecht (10-12 Jahre)</name> + <desc lang="de"> + Der Geocache ist kindgerecht aufgebaut: Alle Aufgaben sind von Kindern + im Alter von 10 bis 12 Jahren selbstständig lösbar und das Gelände ist + nicht gefährlich (keine Haupstraßen, Klippen o.ä.). Am Ende des + Geocaches sollte sich eine Box mit Tauschgegenständen befinden, und + die Aufgaben sollten interessant aufgebaut sein. + </desc> + <name lang="es">Apto para niños (10-12 años)</name> + <desc lang="es"> + Este geocache se creó para los niños. Todas las tareas se puede + completar por los niños entre los años 10 y 12 y el terrno no está + exenta de riesgo (tales como carreteras, acantilados). Hay un gra + contenedor con intercambio final y las tareas son interesantes. + </desc> + <name lang="it">Suited for children (10-12 anni)</name> + <desc lang="it"> + Questa geocache è stata creata per i bambini. Tutte i compiti possono + essere portati a termine da bambini tra 10 e 12 anni e il terreno non + presenta rischi (come autostrade, abissi). C'e un grande contenitore + finale con oggetti di scambio e i compiti sono interessanti. + </desc> + </attr> + +</xml> diff --git a/main/project/attributes_okapi/genattr.jar b/main/project/attributes_okapi/genattr.jar Binary files differnew file mode 100644 index 0000000..7ee5bc4 --- /dev/null +++ b/main/project/attributes_okapi/genattr.jar diff --git a/main/project/attributes_okapi/genattr.sh b/main/project/attributes_okapi/genattr.sh new file mode 100644 index 0000000..7cc23be --- /dev/null +++ b/main/project/attributes_okapi/genattr.sh @@ -0,0 +1,2 @@ +#!/bin/bash +java -jar genattr.jar attributes.xml > AttributeParser.java diff --git a/main/project/attributes_okapi/readme.txt b/main/project/attributes_okapi/readme.txt new file mode 100644 index 0000000..5382ebe --- /dev/null +++ b/main/project/attributes_okapi/readme.txt @@ -0,0 +1,10 @@ +In the current version of OKAPI (rev. 798) are attributes not returned with a unified id but only with the localized text. +Luckily a metadata file to prepare the unification of these attributes has already been prepared by the OKAPI project +(http://code.google.com/p/opencaching-api/source/browse/trunk/etc/attributes.xml), which do not officially publish as a stable definition, +but which can serve as an easier starting point for the generation of a parser class. +To allow the representation with icons we need to map these localized texts to our internal ids which is done with a parser +generated from the aforementioned file. Soo the AttrGen project for more details. + +If attributes.xml will be updated, we need of course to check first if it is structurally compatible to the previous version. +If present it seems to be necessary to remove the BOM at the beginning of the file. Then you can run genattr.sh +and copy the generated AttributeParser.java to the appropriate location (connector.oc). diff --git a/main/res/layout/twitter_authorization_activity.xml b/main/res/layout/authorization_activity.xml index ec9aa8a..931441d 100644 --- a/main/res/layout/twitter_authorization_activity.xml +++ b/main/res/layout/authorization_activity.xml @@ -19,6 +19,7 @@ android:orientation="vertical" > <TextView + android:id="@+id/auth_1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="left|center_vertical" @@ -28,11 +29,11 @@ android:drawableLeft="@drawable/cgeo" android:drawablePadding="15dip" android:gravity="left|center_vertical" - android:text="@string/about_auth_1" android:textColor="?text_color" android:textSize="14sp" /> <TextView + android:id="@+id/auth_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|center_vertical" @@ -40,7 +41,6 @@ android:layout_marginLeft="10dip" android:layout_marginRight="10dip" android:gravity="left|center_vertical" - android:text="@string/about_auth_2" android:textColor="?text_color" android:textSize="14sp" /> @@ -52,20 +52,17 @@ <Button android:id="@+id/start" - style="@style/button_full" - android:text="@string/auth_authorize" /> + style="@style/button_full" /> <EditText android:id="@+id/pin" style="@style/edittext_full" - android:hint="@string/auth_pin_hint" android:inputType="number" android:visibility="gone" /> <Button android:id="@+id/pin_button" style="@style/button_full" - android:text="@string/auth_finish" android:visibility="visible" /> </LinearLayout> </LinearLayout> diff --git a/main/res/layout/init.xml b/main/res/layout/init.xml index 2ee8a6b..e784b21 100644 --- a/main/res/layout/init.xml +++ b/main/res/layout/init.xml @@ -28,7 +28,32 @@ style="@style/separator_horizontal_headline" android:text="@string/init_geocaching" /> </RelativeLayout> - + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_margin="3dip" + android:orientation="horizontal" + android:padding="3dip" > + + <CheckBox android:id="@+id/gc_option" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="left" + android:padding="1dip" + android:gravity="center" /> + + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:gravity="left" + android:paddingRight="3dip" + android:textSize="14sp" + android:textColor="?text_color" + android:text="@string/init_gc_activate" /> + </LinearLayout> + <TextView android:id="@+id/legal_note" android:layout_width="wrap_content" @@ -85,14 +110,14 @@ android:layout_marginLeft="10dip" android:layout_marginRight="10dip" android:padding="3dip" - android:text="@string/init_oc_username_description" + android:text="@string/init_oc_de_description" android:textColor="?text_color" android:textSize="14sp" /> - <EditText - android:id="@+id/oc_username" - style="@style/edittext_full" - android:hint="@string/init_oc_username" /> + <Button + android:id="@+id/register_oc_de" + style="@style/button_full" + android:text="@string/init_register_oc_de" /> <!-- ** --> <RelativeLayout style="@style/separator_horizontal_layout" > @@ -824,4 +849,4 @@ </LinearLayout> </ScrollView> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/main/res/values-cs/strings.xml b/main/res/values-cs/strings.xml index db5ad9d..f29f7e6 100644 --- a/main/res/values-cs/strings.xml +++ b/main/res/values-cs/strings.xml @@ -364,8 +364,6 @@ <string name="init_gc_activate">Aktivace Geocaching.com na Aktivní mapě a ve vyhledávání</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Aktivace opencaching.de na Aktivní mapě a ve vyhledávání</string> - <string name="init_oc_username_description">Zadej své uživatelské jméno pro opencaching.de kvůli možnosti označovat nálezy.</string> - <string name="init_oc_username">Zadej své uživatelské jméno</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Uživatelské jméno</string> diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml index 266e6ce..69838db 100644 --- a/main/res/values-de/strings.xml +++ b/main/res/values-de/strings.xml @@ -372,8 +372,8 @@ <string name="init_gc_activate">Geocaching.com auf Live-Karte und für die Suche aktivieren</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Opencaching.de auf Live-Karte und für die Suche aktivieren</string> - <string name="init_oc_username_description">Benutzername für opencaching.de eingeben damit gefundene Caches markiert werden können.</string> - <string name="init_oc_username">Benutzername</string> + <string name="init_oc_de_description">Autorisiere c:geo dazu auf opencaching.de zuzugreifen um Caches zu suchen und nach deinen Funden zu filtern.</string> + <string name="init_register_oc_de">c:geo autorisieren</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Benutzername</string> @@ -486,7 +486,7 @@ <string name="sendToCgeo_download_fail">c:geo konnte Caches nicht laden. Entweder besteht keine Internetverbindung oder send2c:geo funktioniert nicht.</string> <string name="sendToCgeo_no_registration">c:geo konnte Caches nicht laden. Registrierung für send2c:geo ungültig. Bitte in Einstellungen neu registrieren.</string> - <!-- auth --> + <!-- auth twitter --> <string name="auth_twitter">Twitter</string> <string name="auth_authorize">c:geo autorisieren</string> <string name="auth_start">Starte Autorisierung</string> @@ -497,6 +497,22 @@ <string name="auth_dialog_pin_title">PIN Code</string> <string name="auth_dialog_pin_message">Bitte den Twitter-PIN-Code eingeben, dies ist notwendig um die Autorisierung abzuschließen.</string> <string name="auth_dialog_completed">c:geo ist nun autorisiert, Tweets bei Twitter zu erstellen.</string> + <string name="about_auth_1">Der folgende Prozess erlaubt es <b>c:geo</b> auf den persönlichen Twitter-Account zuzugreifen, wenn zugestimmt wird.</string> + <string name="about_auth_2">Ein Klick auf \"Starte Autorisierung\" öffnet eine Twitter-Seite in einem Browserfenster. Durch die Anmeldung und die Bestätigung wird <b>c:geo</b> ermöglicht, auf den persönlichen Twitter-Account zuzugreifen. Wird dies bestätigt, nennt Twitter eine numerische PIN, diese muss kopiert und in <b>c:geo</b> eingefügt werden. Das ist alles.</string> + + <!-- auth opencaching --> + <string name="auth_ocde">opencaching.de</string> + <string name="auth_authorize_oc">c:geo autorisieren</string> + <string name="auth_start_oc">Starte Autorisierung</string> + <string name="auth_again_oc">Neustarten</string> + <string name="auth_pin_hint_oc">%s-PIN</string> + <string name="auth_finish_oc">Fertig</string> + <string name="auth_dialog_wait_oc">Warten auf %s…</string> + <string name="auth_dialog_pin_title_oc">PIN Code</string> + <string name="auth_dialog_pin_message_oc">Bitte den %s-PIN-Code eingeben, dies ist notwendig um die Autorisierung abzuschließen.</string> + <string name="auth_dialog_completed_oc">c:geo ist nun autorisiert, caches zu laden und auf %s zu loggen.</string> + <string name="about_auth_1_oc">Der folgende Prozess erlaubt es <b>c:geo</b> auf den persönlichen %s-Account zuzugreifen, wenn zugestimmt wird.</string> + <string name="about_auth_2_oc">Ein Klick auf \"Starte Autorisierung\" öffnet eine %s-Seite in einem Browserfenster. Durch die Anmeldung und die Bestätigung wird <b>c:geo</b> ermöglicht, auf den persönlichen Account zuzugreifen. Wird dies bestätigt, nennt %s eine numerische PIN, diese muss kopiert und in <b>c:geo</b> eingefügt werden. Das ist alles.</string> <!-- cache --> <plurals name="cache_counts"> @@ -1066,8 +1082,6 @@ <string name="twitter">Twitter: <a href="">@android_GC</a></string> <string name="nutshellmanual">Benutzung: <a href="">c:geo Kurzanleitung</a></string> <string name="about_twitter">Soll jeder neue Fund auf Twitter veröffentlicht werden, wenn er über <b>c:geo</b> geloggt wird?</string> - <string name="about_auth_1">Der folgende Prozess erlaubt es <b>c:geo</b> auf den persönlichen Twitter-Account zuzugreifen, wenn zugestimmt wird.</string> - <string name="about_auth_2">Ein Klick auf \"Starte Autorisierung\" öffnet eine Twitter-Seite in einem Browserfenster. Durch die Anmeldung und die Bestätigung wird <b>c:geo</b> ermöglicht, auf den persönlichen Twitter-Account zuzugreifen. Wird dies bestätigt, nennt Twitter eine numerische PIN, diese muss kopiert und in <b>c:geo</b> eingefügt werden. Das ist alles.</string> <!-- status --> <string name="status_new_release" tools:ignore="UnusedResources">Neuer Release verfügbar.\nKlicken zum Installieren.</string> diff --git a/main/res/values-fr/strings.xml b/main/res/values-fr/strings.xml index 12d59a7..9f25083 100644 --- a/main/res/values-fr/strings.xml +++ b/main/res/values-fr/strings.xml @@ -371,8 +371,6 @@ <string name="init_gc_activate">Utiliser Geocaching.com pour la carte active et les recherches.</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Utiliser opencaching.de pour la carte active et les recherches.</string> - <string name="init_oc_username_description">Entrer votre nom d\'utilisateur opencaching.de afin de pouvoir marquer vos trouvailles.</string> - <string name="init_oc_username">Entrer votre nom d\'utilisateur</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Identifiant</string> diff --git a/main/res/values-it/strings.xml b/main/res/values-it/strings.xml index 00551f5..98fdf5f 100644 --- a/main/res/values-it/strings.xml +++ b/main/res/values-it/strings.xml @@ -367,8 +367,6 @@ <string name="init_gc_activate">Attiva Geocaching.com su mappa live e nelle ricerche</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Attiva opencaching.de su mappa live e nelle ricerche</string> - <string name="init_oc_username_description">Inserisci il tuo utente opencaching.de per marcare i tuoi ritrovamenti.</string> - <string name="init_oc_username">Inserisci nome utente</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Utente</string> diff --git a/main/res/values-ja/strings.xml b/main/res/values-ja/strings.xml index 4bb15a2..b88577b 100644 --- a/main/res/values-ja/strings.xml +++ b/main/res/values-ja/strings.xml @@ -345,8 +345,6 @@ <string name="init_geocaching">Geocaching.com</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">オンライン地図や検索でopencaching.deも使用する</string> - <string name="init_oc_username_description">見つけたキャッシュなどをマークするにはopencaching.deのユーザ名を入力してください。</string> - <string name="init_oc_username">ユーザ名</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">ユーザ名</string> diff --git a/main/res/values-nl/strings.xml b/main/res/values-nl/strings.xml index 4eb1bc6..c827848 100644 --- a/main/res/values-nl/strings.xml +++ b/main/res/values-nl/strings.xml @@ -347,8 +347,6 @@ <string name="init_geocaching">Geocaching.com</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Activeer opencaching.de op live-kaart en in zoekopdrachten.</string> - <string name="init_oc_username_description">Vul je opencaching.de gebruikersnaam in op caches als gevonden te markeren.</string> - <string name="init_oc_username">Vul gebruikersnaam in</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Gebruikersnaam</string> diff --git a/main/res/values-pl/strings.xml b/main/res/values-pl/strings.xml index 50a383f..e736bbb 100644 --- a/main/res/values-pl/strings.xml +++ b/main/res/values-pl/strings.xml @@ -364,8 +364,6 @@ <string name="init_gc_activate">Aktywuj Geocaching.com na aktualnej mapie i w wyszukiwaniu</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Aktywuj opencaching.de na mapie Live i w wyszukiwaniu</string> - <string name="init_oc_username_description">Wpisz swoją nazwę użytkownika opencaching.de w celu umożliwienia zaznaczania znalezionych przez Ciebie skrzynek.</string> - <string name="init_oc_username">Wpisz swoją nazwę użytkownika</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Nazwa użytkownika</string> diff --git a/main/res/values-sv/strings.xml b/main/res/values-sv/strings.xml index 51bee26..8501cf7 100644 --- a/main/res/values-sv/strings.xml +++ b/main/res/values-sv/strings.xml @@ -371,8 +371,6 @@ <string name="init_gc_activate">Aktivera Geocaching.com i live-kartor och sökningar</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Aktivera opencaching.de i live-kartor och sökningar</string> - <string name="init_oc_username_description">Ange användarnamn till opencaching.de för att kunna markera dina hittade cacher.</string> - <string name="init_oc_username">Ange ditt användarnamn</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Användare</string> diff --git a/main/res/values/.gitignore b/main/res/values/.gitignore new file mode 100644 index 0000000..1f65bef --- /dev/null +++ b/main/res/values/.gitignore @@ -0,0 +1 @@ +/ocde_okapi.xml diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 4d9202e..43f87ea 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -371,8 +371,8 @@ <string name="init_gc_activate">Activate Geocaching.com on live-map and in searches</string> <string name="init_oc">opencaching.de</string> <string name="init_oc_activate">Activate opencaching.de on live-map and in searches</string> - <string name="init_oc_username_description">Enter your opencaching.de user name in order to allow marking your finds.</string> - <string name="init_oc_username">Enter your user name</string> + <string name="init_oc_de_description">Authorize c:geo with opencaching.de to search for caches and access/filter your found caches.</string> + <string name="init_register_oc_de">Authorize c:geo</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="init_username">Username</string> @@ -486,8 +486,7 @@ <string name="sendToCgeo_download_fail">c:geo failed to download caches. No internet connection or send2c:geo is down.</string> <string name="sendToCgeo_no_registration">c:geo failed to download caches. Registration for send2c:geo expired. Please register in settings.</string> - - <!-- auth --> + <!-- auth twitter --> <string name="auth_twitter">Twitter</string> <string name="auth_authorize">Authorize c:geo</string> <string name="auth_start">Start authorization</string> @@ -498,6 +497,22 @@ <string name="auth_dialog_pin_title">PIN code</string> <string name="auth_dialog_pin_message">Please type in PIN code provided by the Twitter website. It is mandatory to complete the authorization.</string> <string name="auth_dialog_completed">c:geo is now authorized to post on Twitter.</string> + <string name="about_auth_1">The following process allows <b>c:geo</b> to access Twitter - if agreed.</string> + <string name="about_auth_2">A click on the \"authorize c:geo\" button will start the process. This process will open up a web browser with a Twitter page. Login on this page and allow <b>c:geo</b> to access your account. If this is accepted, Twitter will show up a numeric PIN code. This PIN must be pasted into <b>c:geo</b> and confirmed. That\'s all.</string> + + <!-- auth opencaching --> + <string name="auth_ocde">opencaching.de</string> + <string name="auth_authorize_oc">Authorize c:geo</string> + <string name="auth_start_oc">Start authorization</string> + <string name="auth_again_oc">Start again</string> + <string name="auth_pin_hint_oc">PIN assigned by %s</string> + <string name="auth_finish_oc">Finish</string> + <string name="auth_dialog_wait_oc">Waiting for %s…</string> + <string name="auth_dialog_pin_title_oc">PIN code</string> + <string name="auth_dialog_pin_message_oc">Please type in PIN code provided by the %s website. It is mandatory to complete the authorization.</string> + <string name="auth_dialog_completed_oc">c:geo is now authorized to interact with %s.</string> + <string name="about_auth_1_oc">The following process allows <b>c:geo</b> to access %s - if agreed.</string> + <string name="about_auth_2_oc">A click on the \"authorize c:geo\" button will start the process. This process will open up a web browser with a %s page. Login on this page and allow <b>c:geo</b> to access your account. If this is accepted, %s will show up a numeric PIN code. This PIN must be pasted into <b>c:geo</b> and confirmed. That\'s all.</string> <!-- cache --> <plurals name="cache_counts"> @@ -1070,8 +1085,6 @@ <string name="nutshellmanual">Manual: <a href="">c:geo in a Nutshell</a></string> <string name="market">Android: <a href="">c:geo on Google Play</a></string> <string name="about_twitter">Should <b>c:geo</b> publish a new status on Twitter every time you log a cache?</string> - <string name="about_auth_1">The following process allows <b>c:geo</b> to access Twitter - if agreed.</string> - <string name="about_auth_2">A click on the \"authorize c:geo\" button will start the process. This process will open up a web browser with a Twitter page. Login on this page and allow <b>c:geo</b> to access your account. If this is accepted, Twitter will show up a numeric PIN code. This PIN must be pasted into <b>c:geo</b> and confirmed. That\'s all.</string> <!-- status (used via string based resource loading) --> <string name="status_new_release" tools:ignore="UnusedResources">New release available.\nClick to install.</string> diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index fe6693b..33a6504 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -117,7 +117,7 @@ import java.util.regex.Pattern; * e.g. details, description, logs, waypoints, inventory... */ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page> - implements EditNoteDialogListener { + implements EditNoteDialogListener { private static final int MENU_FIELD_COPY = 1; private static final int MENU_FIELD_TRANSLATE = 2; @@ -259,6 +259,23 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc finish(); return; } + } else if (uriHost.contains("opencaching.de")) { + if (uriPath != null && uriPath.startsWith("/oc")) { + geocode = uriPath.substring(1).toUpperCase(Locale.US); + } else { + geocode = uri.getQueryParameter("wp"); + if (StringUtils.isNotBlank(geocode)) { + geocode = geocode.toUpperCase(Locale.US); + } else { + showToast(res.getString(R.string.err_detail_open)); + finish(); + return; + } + } + } else { + showToast(res.getString(R.string.err_detail_open)); + finish(); + return; } } @@ -1472,7 +1489,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { - handler.sendEmptyMessage(GCConnector.addToWatchlist(cache) ? 1 : -1); + handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).addToWatchlist(cache) ? 1 : -1); } } @@ -1486,7 +1503,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { - handler.sendEmptyMessage(GCConnector.removeFromWatchlist(cache) ? 1 : -1); + handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).removeFromWatchlist(cache) ? 1 : -1); } } @@ -2242,8 +2259,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } /** - * Read the position of the cursor pointed to by this holder. - * <br/> + * Read the position of the cursor pointed to by this holder. <br/> * This must be called by the UI thread. * * @return the cursor position @@ -2253,11 +2269,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } /** - * Set the position of the cursor pointed to by this holder. - * <br/> + * Set the position of the cursor pointed to by this holder. <br/> * This must be called by the UI thread. * - * @param position the cursor position + * @param position + * the cursor position */ public void setPosition(final int position) { this.position = position; diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java index 304f940..ac1c9b1 100644 --- a/main/src/cgeo/geocaching/Geocache.java +++ b/main/src/cgeo/geocaching/Geocache.java @@ -5,6 +5,7 @@ import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.IAbstractActivity; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.ILoggingManager; import cgeo.geocaching.connector.capability.ISearchByCenter; import cgeo.geocaching.connector.capability.ISearchByGeocode; import cgeo.geocaching.connector.gc.GCConnector; @@ -455,7 +456,7 @@ public class Geocache implements ICache, IWaypoint { } public void logVisit(final IAbstractActivity fromActivity) { - if (StringUtils.isBlank(cacheId)) { + if (!getConnector().canLog(this)) { fromActivity.showToast(((Activity) fromActivity).getResources().getString(R.string.err_cannot_log_visit)); return; } @@ -562,6 +563,10 @@ public class Geocache implements ICache, IWaypoint { return getConnector().supportsLogging(); } + public boolean supportsLogImages() { + return getConnector().supportsLogImages(); + } + public boolean supportsOwnCoordinates() { return getConnector().supportsOwnCoordinates(); } @@ -570,6 +575,10 @@ public class Geocache implements ICache, IWaypoint { return getConnector().getCacheRealm(); } + public ILoggingManager getLoggingManager(Activity activity) { + return getConnector().getLoggingManager(activity, this); + } + @Override public float getDifficulty() { return difficulty; diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java index 9b23554..4393eda 100644 --- a/main/src/cgeo/geocaching/MainActivity.java +++ b/main/src/cgeo/geocaching/MainActivity.java @@ -697,6 +697,10 @@ public class MainActivity extends AbstractActivity { return; } + if (!Settings.isGCConnectorActive()) { + return; + } + // login final StatusCode status = Login.login(); diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java index b5c8a6e..65283da 100644 --- a/main/src/cgeo/geocaching/Settings.java +++ b/main/src/cgeo/geocaching/Settings.java @@ -40,8 +40,8 @@ import java.util.Locale; */ public final class Settings { - private static final String KEY_TEMP_TOKEN_SECRET = "temp-token-secret"; - private static final String KEY_TEMP_TOKEN_PUBLIC = "temp-token-public"; + private static final String KEY_TEMP_TWITTER_TOKEN_SECRET = "temp-token-secret"; + private static final String KEY_TEMP_TWITTER_TOKEN_PUBLIC = "temp-token-public"; private static final String KEY_HELP_SHOWN = "helper"; private static final String KEY_ANYLONGITUDE = "anylongitude"; private static final String KEY_ANYLATITUDE = "anylatitude"; @@ -110,9 +110,14 @@ public final class Settings { private static final String KEY_PLAIN_LOGS = "plainLogs"; private static final String KEY_NATIVE_UA = "nativeUa"; private static final String KEY_MAP_DIRECTORY = "mapDirectory"; + private static final String KEY_CONNECTOR_GC_ACTIVE = "connectorGCActive"; private static final String KEY_CONNECTOR_OC_ACTIVE = "connectorOCActive"; - private static final String KEY_CONNECTOR_OC_USER = "connectorOCUser"; private static final String KEY_LOG_IMAGE_SCALE = "logImageScale"; + private static final String KEY_OCDE_TOKEN_SECRET = "ocde_tokensecret"; + private static final String KEY_OCDE_TOKEN_PUBLIC = "ocde_tokenpublic"; + private static final String KEY_TEMP_OCDE_TOKEN_SECRET = "ocde-temp-token-secret"; + private static final String KEY_TEMP_OCDE_TOKEN_PUBLIC = "ocde-temp-token-public"; + private final static int unitsMetric = 1; @@ -163,8 +168,8 @@ public final class Settings { final SharedPreferences old = cgeoapplication.getInstance().getSharedPreferences(oldPreferencesName, Context.MODE_PRIVATE); final Editor e = sharedPrefs.edit(); - e.putString(KEY_TEMP_TOKEN_SECRET, old.getString(KEY_TEMP_TOKEN_SECRET, null)); - e.putString(KEY_TEMP_TOKEN_PUBLIC, old.getString(KEY_TEMP_TOKEN_PUBLIC, null)); + e.putString(KEY_TEMP_TWITTER_TOKEN_SECRET, old.getString(KEY_TEMP_TWITTER_TOKEN_SECRET, null)); + e.putString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, old.getString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, null)); e.putBoolean(KEY_HELP_SHOWN, old.getInt(KEY_HELP_SHOWN, 0) != 0); e.putFloat(KEY_ANYLONGITUDE, old.getFloat(KEY_ANYLONGITUDE, 0)); e.putFloat(KEY_ANYLATITUDE, old.getFloat(KEY_ANYLATITUDE, 0)); @@ -284,6 +289,20 @@ public final class Settings { }); } + public static boolean isGCConnectorActive() { + return sharedPrefs.getBoolean(KEY_CONNECTOR_GC_ACTIVE, true); + } + + public static boolean setGCConnectorActive(final boolean isActive) { + return editSharedSettings(new PrefRunnable() { + + @Override + public void edit(Editor edit) { + edit.putBoolean(KEY_CONNECTOR_GC_ACTIVE, isActive); + } + }); + } + public static boolean isPremiumMember() { // Basic Member, Premium Member, ??? String memberStatus = Settings.getMemberStatus(); @@ -325,26 +344,44 @@ public final class Settings { }); } - public static String getOCConnectorUserName() { - String ocConnectorUser = sharedPrefs.getString(KEY_CONNECTOR_OC_USER, null); - if (StringUtils.isBlank(ocConnectorUser)) { - return StringUtils.EMPTY; - } - return ocConnectorUser; + public static String getOCDETokenPublic() { + return sharedPrefs.getString(KEY_OCDE_TOKEN_PUBLIC, ""); } - public static boolean setOCConnectorUserName(final String userName) { - return editSharedSettings(new PrefRunnable() { + public static String getOCDETokenSecret() { + return sharedPrefs.getString(KEY_OCDE_TOKEN_SECRET, ""); + } + + public static void setOCDETokens(final String tokenPublic, final String tokenSecret, boolean enableOcDe) { + editSharedSettings(new PrefRunnable() { @Override public void edit(Editor edit) { - if (StringUtils.isBlank(userName)) { - edit.remove(KEY_CONNECTOR_OC_USER); - } else { - edit.putString(KEY_CONNECTOR_OC_USER, userName); + edit.putString(KEY_OCDE_TOKEN_PUBLIC, tokenPublic); + edit.putString(KEY_OCDE_TOKEN_SECRET, tokenSecret); + if (tokenPublic != null) { + edit.remove(KEY_TEMP_OCDE_TOKEN_PUBLIC); + edit.remove(KEY_TEMP_OCDE_TOKEN_SECRET); } } }); + setOCConnectorActive(enableOcDe); + } + + public static void setOCDETempTokens(final String tokenPublic, final String tokenSecret) { + editSharedSettings(new PrefRunnable() { + @Override + public void edit(Editor edit) { + edit.putString(KEY_TEMP_OCDE_TOKEN_PUBLIC, tokenPublic); + edit.putString(KEY_TEMP_OCDE_TOKEN_SECRET, tokenSecret); + } + }); + } + + public static ImmutablePair<String, String> getTempOCDEToken() { + String tokenPublic = sharedPrefs.getString(KEY_TEMP_OCDE_TOKEN_PUBLIC, null); + String tokenSecret = sharedPrefs.getString(KEY_TEMP_OCDE_TOKEN_SECRET, null); + return new ImmutablePair<String, String>(tokenPublic, tokenSecret); } public static boolean isGCvoteLogin() { @@ -1122,8 +1159,8 @@ public final class Settings { edit.putString(KEY_TWITTER_TOKEN_PUBLIC, tokenPublic); edit.putString(KEY_TWITTER_TOKEN_SECRET, tokenSecret); if (tokenPublic != null) { - edit.remove(KEY_TEMP_TOKEN_PUBLIC); - edit.remove(KEY_TEMP_TOKEN_SECRET); + edit.remove(KEY_TEMP_TWITTER_TOKEN_PUBLIC); + edit.remove(KEY_TEMP_TWITTER_TOKEN_SECRET); } } }); @@ -1134,15 +1171,15 @@ public final class Settings { editSharedSettings(new PrefRunnable() { @Override public void edit(Editor edit) { - edit.putString(KEY_TEMP_TOKEN_PUBLIC, tokenPublic); - edit.putString(KEY_TEMP_TOKEN_SECRET, tokenSecret); + edit.putString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, tokenPublic); + edit.putString(KEY_TEMP_TWITTER_TOKEN_SECRET, tokenSecret); } }); } public static ImmutablePair<String, String> getTempToken() { - String tokenPublic = sharedPrefs.getString(KEY_TEMP_TOKEN_PUBLIC, null); - String tokenSecret = sharedPrefs.getString(KEY_TEMP_TOKEN_SECRET, null); + String tokenPublic = sharedPrefs.getString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, null); + String tokenSecret = sharedPrefs.getString(KEY_TEMP_TWITTER_TOKEN_SECRET, null); return new ImmutablePair<String, String>(tokenPublic, tokenSecret); } diff --git a/main/src/cgeo/geocaching/SettingsActivity.java b/main/src/cgeo/geocaching/SettingsActivity.java index f09f7d6..aa163ad 100644 --- a/main/src/cgeo/geocaching/SettingsActivity.java +++ b/main/src/cgeo/geocaching/SettingsActivity.java @@ -5,6 +5,7 @@ import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.connector.gc.Login; +import cgeo.geocaching.connector.oc.OCAuthorizationActivity; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.files.SimpleDirChooser; import cgeo.geocaching.maps.MapProviderFactory; @@ -169,7 +170,6 @@ public class SettingsActivity extends AbstractActivity { ((EditText) findViewById(R.id.username)).setText(""); ((EditText) findViewById(R.id.password)).setText(""); ((EditText) findViewById(R.id.passvote)).setText(""); - ((EditText) findViewById(R.id.oc_username)).setText(""); if (saveValues()) { showToast(res.getString(R.string.init_cleared)); @@ -213,6 +213,15 @@ public class SettingsActivity extends AbstractActivity { public void init() { // geocaching.com settings + final CheckBox gcCheck = (CheckBox) findViewById(R.id.gc_option); + gcCheck.setChecked(Settings.isGCConnectorActive()); + gcCheck.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Settings.setGCConnectorActive(gcCheck.isChecked()); + } + }); final ImmutablePair<String, String> login = Settings.getLogin(); if (login != null) { ((EditText) findViewById(R.id.username)).setText(login.left); @@ -242,10 +251,9 @@ public class SettingsActivity extends AbstractActivity { Settings.setOCConnectorActive(ocCheck.isChecked()); } }); - EditText ocUserEdit = (EditText) findViewById(R.id.oc_username); - if (ocUserEdit.getText().length() == 0) { - ocUserEdit.setText(Settings.getOCConnectorUserName()); - } + + Button checkOCUser = (Button) findViewById(R.id.register_oc_de); + checkOCUser.setOnClickListener(new OCDEAuthorizeCgeoListener()); // gcvote settings final ImmutablePair<String, String> gcvoteLogin = Settings.getGCvoteLogin(); @@ -829,7 +837,6 @@ public class SettingsActivity extends AbstractActivity { String signatureNew = ((EditText) findViewById(R.id.signature)).getText().toString(); String mapDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.map_directory)).getText().toString()); String themesDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.themefolder)).getText().toString()); - String ocUserName = StringUtils.trimToEmpty(((EditText) findViewById(R.id.oc_username)).getText().toString()); String altitudeNew = StringUtils.trimToNull(((EditText) findViewById(R.id.altitude)).getText().toString()); int altitudeNewInt = parseNumber(altitudeNew, 0); @@ -843,7 +850,6 @@ public class SettingsActivity extends AbstractActivity { final boolean status4 = Settings.setAltCorrection(altitudeNewInt); final boolean status5 = Settings.setMapFileDirectory(mapDirectoryNew); final boolean status6 = Settings.setCustomRenderThemeBaseFolder(themesDirectoryNew); - final boolean status7 = Settings.setOCConnectorUserName(ocUserName); Settings.setShowWaypointsThreshold(waypointThreshold); String importNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.gpx_importdir)).getText().toString()); @@ -851,7 +857,7 @@ public class SettingsActivity extends AbstractActivity { Settings.setGpxImportDir(importNew); Settings.setGpxExportDir(exportNew); - return status1 && status2 && status3 && status4 && status5 && status6 && status7; + return status1 && status2 && status3 && status4 && status5 && status6; } /** @@ -920,6 +926,15 @@ public class SettingsActivity extends AbstractActivity { } } + private class OCDEAuthorizeCgeoListener implements View.OnClickListener { + + @Override + public void onClick(View v) { + Intent authIntent = new Intent(SettingsActivity.this, OCAuthorizationActivity.class); + startActivity(authIntent); + } + } + private class WebAuthListener implements View.OnClickListener { @Override diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java index c19cceb..e99da8d 100644 --- a/main/src/cgeo/geocaching/VisitCacheActivity.java +++ b/main/src/cgeo/geocaching/VisitCacheActivity.java @@ -1,14 +1,13 @@ package cgeo.geocaching; -import cgeo.geocaching.connector.gc.GCParser; -import cgeo.geocaching.connector.gc.Login; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.ImageResult; +import cgeo.geocaching.connector.LogResult; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.LogTypeTrackable; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.gcvote.GCVote; -import cgeo.geocaching.loaders.UrlLoader; -import cgeo.geocaching.network.Parameters; import cgeo.geocaching.twitter.Twitter; import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.ui.dialog.DateDialog; @@ -20,7 +19,6 @@ import cgeo.geocaching.utils.LogTemplateProvider.LogContext; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; import android.app.Activity; import android.app.AlertDialog; @@ -31,8 +29,6 @@ import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.Menu; @@ -51,7 +47,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; -public class VisitCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent, LoaderManager.LoaderCallbacks<String> { +public class VisitCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent { static final String EXTRAS_GEOCODE = "geocode"; static final String EXTRAS_ID = "id"; @@ -71,7 +67,6 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD private String geocode = null; private String text = null; private List<LogType> possibleLogTypes = new ArrayList<LogType>(); - private String[] viewstates = null; private List<TrackableLog> trackables = null; private Button postButton = null; private CheckBox tweetCheck = null; @@ -79,6 +74,8 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD private boolean tbChanged = false; private SparseArray<TrackableLog> actionButtons; + private ILoggingManager loggingManager; + // Data to be saved while reconfiguring private double rating; private LogType typeSelected; @@ -87,30 +84,16 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD private String imageDescription; private Uri imageUri; - @Override - public Loader<String> onCreateLoader(final int id, final Bundle args) { - if (!Settings.isLogin()) { // allow offline logging - showToast(res.getString(R.string.err_login)); - return null; - } - return new UrlLoader(getBaseContext(), "http://www.geocaching.com/seek/log.aspx", new Parameters("ID", cacheid)); - } - @Override - public void onLoaderReset(final Loader<String> loader) { - // Nothing to do - } + public void onLoadFinished() { - @Override - public void onLoadFinished(final Loader<String> loader, final String page) { - if (page == null) { + if (loggingManager.hasLoaderError()) { showErrorLoadingData(); return; } - viewstates = Login.getViewstates(page); - trackables = GCParser.parseTrackableLog(page); - possibleLogTypes = GCParser.parseTypes(page); + trackables = loggingManager.getTrackables(); + possibleLogTypes = loggingManager.getPossibleLogTypes(); if (possibleLogTypes.isEmpty()) { showErrorLoadingData(); @@ -229,7 +212,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD if (!postButton.isEnabled()) { return res.getString(R.string.log_post_not_possible); } - if (typeSelected != LogType.FOUND_IT || !Settings.isGCvoteLogin()) { + if (typeSelected != LogType.FOUND_IT || !Settings.isGCvoteLogin() || !cache.supportsGCVote()) { return res.getString(R.string.log_post); } if (rating == 0) { @@ -295,7 +278,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } } updatePostButtonText(); - setImageButtonText(); + updateImageButton(); enablePostButton(false); final Button typeButton = (Button) findViewById(R.id.type); @@ -347,7 +330,9 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } }); - getSupportLoaderManager().initLoader(0, null, this); + loggingManager = cache.getLoggingManager(this); + + loggingManager.init(); } private void setDefaultValues() { @@ -393,7 +378,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD final EditText logView = (EditText) findViewById(R.id.log); logView.setText(StringUtils.EMPTY); - setImageButtonText(); + updateImageButton(); showToast(res.getString(R.string.info_log_cleared)); } @@ -433,7 +418,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - final boolean voteAvailable = Settings.isGCvoteLogin() && typeSelected == LogType.FOUND_IT && StringUtils.isNotBlank(cache.getGuid()); + final boolean voteAvailable = Settings.isGCvoteLogin() && typeSelected == LogType.FOUND_IT && StringUtils.isNotBlank(cache.getGuid()) && cache.supportsGCVote(); menu.findItem(SUBMENU_VOTE).setVisible(voteAvailable); return true; @@ -536,11 +521,9 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD protected StatusCode doInBackgroundInternal(final String[] logTexts) { final String log = logTexts[0]; try { - final ImmutablePair<StatusCode, String> postResult = GCParser.postLog(geocode, cacheid, viewstates, typeSelected, - date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), - log, trackables); + final LogResult logResult = loggingManager.postLog(cache, typeSelected, date, log, trackables); - if (postResult.left == StatusCode.NO_ERROR) { + if (logResult.getPostLogResult() == StatusCode.NO_ERROR) { final LogEntry logNow = new LogEntry(date, typeSelected, log); cache.getLogs().add(0, logNow); @@ -560,17 +543,17 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } if (StringUtils.isNotBlank(imageUri.getPath())) { - ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(postResult.right, imageCaption, imageDescription, imageUri); - final String uploadedImageUrl = imageResult.right; + ImageResult imageResult = loggingManager.postLogImage(logResult.getLogId(), imageCaption, imageDescription, imageUri); + final String uploadedImageUrl = imageResult.getImageUri(); if (StringUtils.isNotEmpty(uploadedImageUrl)) { logNow.addLogImage(new Image(uploadedImageUrl, imageCaption, imageDescription)); cgData.saveChangedCache(cache); } - return imageResult.left; + return imageResult.getPostResult(); } } - return postResult.left; + return logResult.getPostLogResult(); } catch (Exception e) { Log.e("cgeovisit.postLogFn", e); } @@ -705,14 +688,19 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD // Image capture failed, advise user showToast(getResources().getString(R.string.err_select_logimage_failed)); } - setImageButtonText(); + updateImageButton(); } } - private void setImageButtonText() { + private void updateImageButton() { final Button imageButton = (Button) findViewById(R.id.image_btn); - imageButton.setText(StringUtils.isNotBlank(imageUri.getPath()) ? + if (cache.supportsLogImages()) { + imageButton.setVisibility(View.VISIBLE); + imageButton.setText(StringUtils.isNotBlank(imageUri.getPath()) ? res.getString(R.string.log_image_edit) : res.getString(R.string.log_image_attach)); + } else { + imageButton.setVisibility(View.GONE); + } } } diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java index 413291c..905382f 100644 --- a/main/src/cgeo/geocaching/connector/AbstractConnector.java +++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java @@ -6,6 +6,8 @@ import cgeo.geocaching.geopoint.Geopoint; import org.apache.commons.lang3.StringUtils; +import android.app.Activity; + public abstract class AbstractConnector implements IConnector { @Override @@ -19,6 +21,16 @@ public abstract class AbstractConnector implements IConnector { } @Override + public boolean addToWatchlist(Geocache cache) { + return false; + } + + @Override + public boolean removeFromWatchlist(Geocache cache) { + return false; + } + + @Override public boolean supportsOwnCoordinates() { return false; } @@ -54,6 +66,21 @@ public abstract class AbstractConnector implements IConnector { } @Override + public boolean supportsLogImages() { + return false; + } + + @Override + public boolean canLog(Geocache cache) { + return false; + } + + @Override + public ILoggingManager getLoggingManager(Activity activity, Geocache cache) { + return new NoLoggingManager(); + } + + @Override public String getLicenseText(final Geocache cache) { return null; } diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java index 561bae2..50f56af 100644 --- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java +++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java @@ -1,14 +1,15 @@ package cgeo.geocaching.connector; import cgeo.geocaching.ICache; +import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Trackable; import cgeo.geocaching.connector.capability.ISearchByCenter; import cgeo.geocaching.connector.capability.ISearchByViewPort; import cgeo.geocaching.connector.gc.GCConnector; import cgeo.geocaching.connector.oc.OCApiConnector; +import cgeo.geocaching.connector.oc.OCApiLiveConnector; import cgeo.geocaching.connector.oc.OCConnector; -import cgeo.geocaching.connector.oc.OCXMLApiConnector; import cgeo.geocaching.connector.ox.OXConnector; import cgeo.geocaching.geopoint.Viewport; @@ -21,7 +22,7 @@ public final class ConnectorFactory { private static final UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector(); private static final IConnector[] connectors = new IConnector[] { GCConnector.getInstance(), - new OCXMLApiConnector("OpenCaching.DE", "www.opencaching.de", "OC"), + new OCApiLiveConnector("Opencaching.de", "www.opencaching.de", "OC", R.string.oc_de_okapi_consumer_key, R.string.oc_de_okapi_consumer_secret), new OCConnector("OpenCaching.CZ", "www.opencaching.cz", "OZ"), new OCApiConnector("OpenCaching.CO.UK", "www.opencaching.org.uk", "OK", "arU4okouc4GEjMniE2fq"), new OCConnector("OpenCaching.ES", "www.opencachingspain.es", "OC"), diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java index 9169b4a..011c507 100644 --- a/main/src/cgeo/geocaching/connector/IConnector.java +++ b/main/src/cgeo/geocaching/connector/IConnector.java @@ -5,6 +5,8 @@ import cgeo.geocaching.ICache; import cgeo.geocaching.enumerations.CacheRealm; import cgeo.geocaching.geopoint.Geopoint; +import android.app.Activity; + public interface IConnector { /** * get name for display (currently only used in links) @@ -45,6 +47,22 @@ public interface IConnector { public boolean supportsWatchList(); /** + * Add the cache to the watchlist + * + * @param cache + * @return True - success/False - failure + */ + public boolean addToWatchlist(Geocache cache); + + /** + * Remove the cache from the watchlist + * + * @param cache + * @return True - success/False - failure + */ + public boolean removeFromWatchlist(Geocache cache); + + /** * enable/disable favorite points controls in cache details * * @return @@ -59,6 +77,20 @@ public interface IConnector { public boolean supportsLogging(); /** + * enable/disable attaching image to log + * + * @return + */ + public boolean supportsLogImages(); + + /** + * Get an ILoggingManager to guide the logging process. + * + * @return + */ + public ILoggingManager getLoggingManager(Activity activity, Geocache cache); + + /** * get host name of the connector server for dynamic loading of data * * @return @@ -159,4 +191,13 @@ public interface IConnector { * @return <code>true</code> if the current user is the cache owner, <code>false</code> otherwise */ public boolean isOwner(final ICache cache); + + /** + * Check if the cache information is complete enough to be + * able to log online. + * + * @param geocache + * @return + */ + public boolean canLog(Geocache geocache); } diff --git a/main/src/cgeo/geocaching/connector/ILoggingManager.java b/main/src/cgeo/geocaching/connector/ILoggingManager.java new file mode 100644 index 0000000..f0029f9 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/ILoggingManager.java @@ -0,0 +1,32 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.enumerations.LogType; + +import android.net.Uri; + +import java.util.Calendar; +import java.util.List; + +public interface ILoggingManager { + + LogResult postLog(Geocache cache, + LogType logType, + Calendar date, + String log, + List<TrackableLog> trackableLogs); + + ImageResult postLogImage(String logId, + String imageCaption, + String imageDescription, + Uri imageUri); + + public boolean hasLoaderError(); + + public List<TrackableLog> getTrackables(); + + public List<LogType> getPossibleLogTypes(); + + public void init(); +} diff --git a/main/src/cgeo/geocaching/connector/ImageResult.java b/main/src/cgeo/geocaching/connector/ImageResult.java new file mode 100644 index 0000000..9314cad --- /dev/null +++ b/main/src/cgeo/geocaching/connector/ImageResult.java @@ -0,0 +1,23 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.enumerations.StatusCode; + +public class ImageResult { + + private final StatusCode postResult; + private final String imageUri; + + public ImageResult(StatusCode postResult, String imageUri) { + this.postResult = postResult; + this.imageUri = imageUri; + } + + public StatusCode getPostResult() { + return postResult; + } + + public String getImageUri() { + return imageUri; + } + +} diff --git a/main/src/cgeo/geocaching/connector/LogResult.java b/main/src/cgeo/geocaching/connector/LogResult.java new file mode 100644 index 0000000..62111a4 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/LogResult.java @@ -0,0 +1,23 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.enumerations.StatusCode; + +public class LogResult { + + private final StatusCode postLogResult; + private final String logId; + + public LogResult(StatusCode postLogResult, String logId) { + this.postLogResult = postLogResult; + this.logId = logId; + } + + public StatusCode getPostLogResult() { + return postLogResult; + } + + public String getLogId() { + return logId; + } + +} diff --git a/main/src/cgeo/geocaching/connector/NoLoggingManager.java b/main/src/cgeo/geocaching/connector/NoLoggingManager.java new file mode 100644 index 0000000..bfea4ca --- /dev/null +++ b/main/src/cgeo/geocaching/connector/NoLoggingManager.java @@ -0,0 +1,46 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; + +import android.net.Uri; + +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +public class NoLoggingManager implements ILoggingManager { + + @Override + public void init() { + // nothing to do + } + + @Override + public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) { + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) { + return new ImageResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public boolean hasLoaderError() { + return true; + } + + @Override + public List<TrackableLog> getTrackables() { + return Collections.emptyList(); + } + + @Override + public List<LogType> getPossibleLogTypes() { + return Collections.emptyList(); + } + +} diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index a2df060..82bd52a 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -7,6 +7,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.cgData; import cgeo.geocaching.connector.AbstractConnector; +import cgeo.geocaching.connector.ILoggingManager; import cgeo.geocaching.connector.capability.ISearchByCenter; import cgeo.geocaching.connector.capability.ISearchByGeocode; import cgeo.geocaching.connector.capability.ISearchByViewPort; @@ -20,6 +21,8 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import android.app.Activity; + import java.util.regex.Pattern; public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort { @@ -82,6 +85,21 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, } @Override + public boolean supportsLogImages() { + return true; + } + + @Override + public ILoggingManager getLoggingManager(Activity activity, Geocache cache) { + return new GCLoggingManager(activity, cache); + } + + @Override + public boolean canLog(Geocache cache) { + return StringUtils.isNotBlank(cache.getCacheId()); + } + + @Override public String getName() { return "GeoCaching.com"; } @@ -153,7 +171,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, } - public static boolean addToWatchlist(Geocache cache) { + @Override + public boolean addToWatchlist(Geocache cache) { final boolean added = GCParser.addToWatchlist(cache); if (added) { cgData.saveChangedCache(cache); @@ -161,7 +180,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, return added; } - public static boolean removeFromWatchlist(Geocache cache) { + @Override + public boolean removeFromWatchlist(Geocache cache) { final boolean removed = GCParser.removeFromWatchlist(cache); if (removed) { cgData.saveChangedCache(cache); @@ -244,6 +264,6 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, @Override public boolean isActivated() { - return true; + return Settings.isGCConnectorActive(); } } diff --git a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java new file mode 100644 index 0000000..0fbd718 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java @@ -0,0 +1,132 @@ +package cgeo.geocaching.connector.gc; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.VisitCacheActivity; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.ImageResult; +import cgeo.geocaching.connector.LogResult; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.loaders.UrlLoader; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import android.app.Activity; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; + +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +public class GCLoggingManager implements ILoggingManager, LoaderManager.LoaderCallbacks<String> { + + private final VisitCacheActivity activity; + private final Geocache cache; + + private String[] viewstates; + private List<TrackableLog> trackables; + private List<LogType> possibleLogTypes; + private boolean hasLoaderError = true; + + public GCLoggingManager(Activity activity, Geocache cache) { + this.activity = (VisitCacheActivity) activity; + this.cache = cache; + } + + @Override + public Loader<String> onCreateLoader(int arg0, Bundle arg1) { + if (!Settings.isLogin()) { // allow offline logging + ActivityMixin.showToast(activity, activity.getResources().getString(R.string.err_login)); + return null; + } + return new UrlLoader(activity.getBaseContext(), "http://www.geocaching.com/seek/log.aspx", new Parameters("ID", cache.getCacheId())); + } + + @Override + public void onLoadFinished(Loader<String> arg0, String page) { + + if (page == null) { + hasLoaderError = true; + } else { + + viewstates = Login.getViewstates(page); + trackables = GCParser.parseTrackableLog(page); + possibleLogTypes = GCParser.parseTypes(page); + + hasLoaderError = possibleLogTypes.isEmpty(); + } + + activity.onLoadFinished(); + } + + @Override + public void onLoaderReset(Loader<String> arg0) { + // nothing to do + } + + @Override + public void init() { + activity.getSupportLoaderManager().initLoader(0, null, this); + } + + @Override + public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) { + + try { + final ImmutablePair<StatusCode, String> postResult = GCParser.postLog(cache.getGeocode(), cache.getCacheId(), viewstates, logType, + date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), + log, trackableLogs); + + return new LogResult(postResult.left, postResult.right); + } catch (Exception e) { + Log.e("GCLoggingManager.postLog", e); + } + + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) { + + if (StringUtils.isNotBlank(imageUri.getPath())) { + + ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(logId, imageCaption, imageDescription, imageUri); + + return new ImageResult(imageResult.left, imageResult.right); + } + + return new ImageResult(StatusCode.LOGIMAGE_POST_ERROR, ""); + } + + @Override + public boolean hasLoaderError() { + return hasLoaderError; + } + + @Override + public List<TrackableLog> getTrackables() { + if (hasLoaderError) { + return Collections.emptyList(); + } + return trackables; + } + + @Override + public List<LogType> getPossibleLogTypes() { + if (hasLoaderError) { + return Collections.emptyList(); + } + return possibleLogTypes; + } + +} diff --git a/main/src/cgeo/geocaching/connector/oc/AttributeParser.java b/main/src/cgeo/geocaching/connector/oc/AttributeParser.java new file mode 100644 index 0000000..63bee77 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/AttributeParser.java @@ -0,0 +1,327 @@ +// This is a generated file, do not change manually! + +package cgeo.geocaching.connector.oc; + +import java.util.HashMap; +import java.util.Map; + +public class AttributeParser { + + private final static Map<String, Integer> attrMapDe; + private final static Map<String, Integer> attrMapPl; + + static { + attrMapDe = new HashMap<String, Integer>(); + attrMapPl = new HashMap<String, Integer>(); + + // last header line + attrMapDe.put("Listed at Opencaching only", 6); + attrMapDe.put("Dostępna tylko na Opencaching", 6); + attrMapDe.put("Nur bei Opencaching logbar", 6); + attrMapDe.put("Solo loggeable en Opencaching", 6); + attrMapDe.put("Loggabile solo su Opencaching", 6); + attrMapPl.put("Near a Survey Marker", 54); + attrMapPl.put("W pobliżu punktu geodezyjnego", 54); + attrMapPl.put("Whereigo Cache", 55); + attrMapPl.put("Whereigo Cache", 55); + attrMapPl.put("Whereigo Cache", 55); + attrMapDe.put("Letterbox Cache", 8); + attrMapPl.put("Letterbox Cache", 56); + attrMapDe.put("Skrzynka typu Letterbox", 8); + attrMapPl.put("Skrzynka typu Letterbox", 56); + attrMapDe.put("Letterbox (benötigt Stempel)", 8); + attrMapPl.put("Letterbox (benötigt Stempel)", 56); + attrMapDe.put("Letterbox (necesita un estampador)", 8); + attrMapPl.put("Letterbox (necesita un estampador)", 56); + attrMapDe.put("Letterbox (richiede un timbro)", 8); + attrMapPl.put("Letterbox (richiede un timbro)", 56); + attrMapPl.put("GeoHotel", 43); + attrMapPl.put("GeoHotel", 43); + attrMapPl.put("GeoHotel", 43); + attrMapPl.put("Magnetic cache", 49); + attrMapPl.put("Przyczepiona magnesem", 49); + attrMapPl.put("magnetischer Cache", 49); + attrMapPl.put("Description contains an audio file", 50); + attrMapPl.put("Opis zawiera plik audio", 50); + attrMapPl.put("Offset cache", 51); + attrMapPl.put("Offset cache", 51); + attrMapPl.put("Peilungscache", 51); + attrMapPl.put("Garmin's wireless beacon", 52); + attrMapPl.put("Beacon - Garmin Chirp", 52); + attrMapPl.put("Funksignal – Garmin Chirp", 52); + attrMapPl.put("Dead Drop USB cache", 53); + attrMapPl.put("Dead Drop USB skrzynka", 53); + attrMapDe.put("Has a moving target", 31); + attrMapDe.put("bewegliches Ziel", 31); + attrMapDe.put("Objetivo en movimiento", 31); + attrMapDe.put("Oggetto in movimento", 31); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Webcam Cache", 32); + attrMapDe.put("Other cache type", 57); + attrMapDe.put("sonstiger Cachetyp", 57); + attrMapDe.put("Otro tipo de cache", 57); + attrMapDe.put("Altro tipo di cache", 57); + attrMapDe.put("Investigation required", 54); + attrMapDe.put("Recherche", 54); + attrMapDe.put("Investigación", 54); + attrMapDe.put("Ricerca", 54); + attrMapDe.put("Puzzle / Mystery", 55); + attrMapDe.put("Rätsel", 55); + attrMapDe.put("Puzzle / Misterio", 55); + attrMapDe.put("Puzzle / Mystery", 55); + attrMapDe.put("Arithmetical problem", 56); + attrMapDe.put("Rechenaufgabe", 56); + attrMapDe.put("Problema matemático", 56); + attrMapDe.put("Problema matematico", 56); + attrMapDe.put("Ask owner for start conditions", 58); + attrMapDe.put("Startbedingungen beim Owner erfragen", 58); + attrMapDe.put("Ask owner for start conditions", 58); + attrMapDe.put("Ask owner for start conditions", 58); + attrMapPl.put("Wheelchair accessible", 44); + attrMapPl.put("Dostępna dla niepełnosprawnych", 44); + attrMapPl.put("rollstuhltauglich", 44); + attrMapDe.put("Near the parking area", 24); + attrMapDe.put("nahe beim Auto", 24); + attrMapDe.put("Cerca de un Parking", 24); + attrMapDe.put("Vicino all'area di parcheggio", 24); + attrMapPl.put("Access only by walk", 84); + attrMapPl.put("Dostępna tylko pieszo", 84); + attrMapDe.put("Long walk", 25); + attrMapDe.put("längere Wanderung", 25); + attrMapDe.put("Larga caminata", 25); + attrMapDe.put("Lunga camminata", 25); + attrMapDe.put("Swamp, marsh or wading", 26); + attrMapDe.put("sumpfig/matschiges Gelände / waten", 26); + attrMapDe.put("Pantano / terreno fangoso", 26); + attrMapDe.put("Palude o marcita", 26); + attrMapDe.put("Hilly area", 27); + attrMapDe.put("hügeliges Gelände", 27); + attrMapDe.put("Terreno montañoso", 27); + attrMapDe.put("Area collinare", 27); + attrMapDe.put("Some climbing (no gear needed)", 28); + attrMapDe.put("leichtes Klettern (ohne Ausrüstung)", 28); + attrMapDe.put("fácil de subir (sin equipo)", 28); + attrMapDe.put("Arrampicata (attrezzatura non necessaria)", 28); + attrMapDe.put("Swimming required", 29); + attrMapDe.put("Schwimmen erforderlich", 29); + attrMapDe.put("Requiere nadar", 29); + attrMapDe.put("Nuoto necessario", 29); + attrMapDe.put("Access or parking fee", 36); + attrMapDe.put("Zugangs- bzw. Parkentgelt", 36); + attrMapDe.put("Acceso o parking pagando", 36); + attrMapDe.put("Tassa di ingresso o di parcheggio", 36); + attrMapPl.put("Bikes allowed", 85); + attrMapPl.put("Dostępna rowerem", 85); + attrMapPl.put("Hidden in natural surroundings (forests, mountains, etc.)", 60); + attrMapPl.put("Umiejscowiona na łonie natury (lasy, góry, itp.)", 60); + attrMapPl.put("Historic site", 61); + attrMapPl.put("Miejsce historyczne", 61); + attrMapDe.put("Point of interest", 30); + attrMapDe.put("interessanter Ort", 30); + attrMapDe.put("Punto de interes", 30); + attrMapDe.put("Punto di interesse", 30); + attrMapDe.put("Hidden wihin enclosed rooms (caves, buildings etc.)", 33); + attrMapDe.put("in geschlossenen Räumen (Höhle, Gebäude, etc.)", 33); + attrMapDe.put("en espacios confinados (cuevas, edificios, etc)", 33); + attrMapDe.put("All'interno di stanze chiuse (caverne, edifici, ecc.)", 33); + attrMapDe.put("Hidden under water", 34); + attrMapDe.put("Im Wasser versteckt", 34); + attrMapDe.put("En el agua", 34); + attrMapDe.put("Nell'acqua", 34); + attrMapDe.put("Parking area nearby", 18); + attrMapDe.put("Parkplatz in der Nähe", 18); + attrMapDe.put("Parking cercano", 18); + attrMapDe.put("Parcheggio nei pressi", 18); + attrMapDe.put("Public transportation", 19); + attrMapDe.put("erreichbar mit ÖVM", 19); + attrMapDe.put("Transporte Público", 19); + attrMapDe.put("Trasporto pubblico", 19); + attrMapDe.put("Drinking water nearby", 20); + attrMapDe.put("Trinkwasser in der Nähe", 20); + attrMapDe.put("Agua potable en las cercanias", 20); + attrMapDe.put("Acqua potabile nei pressi", 20); + attrMapDe.put("Public restrooms nearby", 21); + attrMapDe.put("öffentliche Toilette in der Nähe", 21); + attrMapDe.put("Aseos públicos cercanos", 21); + attrMapDe.put("Bagni pubblici nei pressi", 21); + attrMapDe.put("Public phone nearby", 22); + attrMapDe.put("Telefon in der Nähe", 22); + attrMapDe.put("Teléfono Público en las cercanias", 22); + attrMapDe.put("Telefono pubblico nei pressi", 22); + attrMapDe.put("First aid available", 23); + attrMapDe.put("Erste Hilfe verfügbar", 23); + attrMapDe.put("Disponible socorro rapido", 23); + attrMapDe.put("Disponibile pronto soccorso", 23); + attrMapDe.put("Available 24/7", 38); + attrMapDe.put("rund um die Uhr machbar", 38); + attrMapDe.put("Disponible las 24 horas", 38); + attrMapDe.put("Disponibile 24 ore", 38); + attrMapDe.put("Not 24/7", 39); + attrMapPl.put("Not 24/7", 80); + attrMapDe.put("Dostępna w określonych godzinach", 39); + attrMapPl.put("Dostępna w określonych godzinach", 80); + attrMapDe.put("nur zu bestimmten Uhrzeiten", 39); + attrMapPl.put("nur zu bestimmten Uhrzeiten", 80); + attrMapDe.put("Sólo disponible a ciertas horas", 39); + attrMapPl.put("Sólo disponible a ciertas horas", 80); + attrMapDe.put("Disponibile solo in certi orari", 39); + attrMapPl.put("Disponibile solo in certi orari", 80); + attrMapDe.put("Not recommended at night", 40); + attrMapDe.put("nur tagüber", 40); + attrMapDe.put("solo por el día", 40); + attrMapDe.put("solo di giorno", 40); + attrMapPl.put("Recommended at night", 91); + attrMapPl.put("Zalecane szukanie nocą", 91); + attrMapPl.put("am besten nachts findbar", 91); + attrMapDe.put("Only at night", 1); + attrMapDe.put("nur bei Nacht", 1); + attrMapDe.put("Sólo por la noche", 1); + attrMapDe.put("Solo di notte", 1); + attrMapDe.put("All seasons", 42); + attrMapDe.put("ganzjähig zugänglich", 42); + attrMapDe.put("Todas las temporadas", 42); + attrMapDe.put("Tutte le stagioni", 42); + attrMapDe.put("Only available during specified seasons", 60); + attrMapDe.put("Nur zu bestimmten Zeiten im Jahr", 60); + attrMapDe.put("Sólo disponible durante las estaciones especificadas", 60); + attrMapDe.put("Disponibile solo in certe stagioni", 60); + attrMapDe.put("Breeding season / protected nature", 43); + attrMapDe.put("Brutsaison / Naturschutz", 43); + attrMapDe.put("Temporada de reproducción / protección de la naturaleza", 43); + attrMapDe.put("Stagione di riproduzione / natura protetta", 43); + attrMapDe.put("Available during winter", 44); + attrMapDe.put("schneesicheres Versteck", 44); + attrMapDe.put("Nieve en el escondite", 44); + attrMapDe.put("Luogo a prova di neve", 44); + attrMapDe.put("Not at high water level", 41); + attrMapDe.put("nicht bei Hochwasser oder Flut", 41); + attrMapDe.put("Compass required", 47); + attrMapPl.put("Compass required", 47); + attrMapDe.put("Potrzebny kompas", 47); + attrMapPl.put("Potrzebny kompas", 47); + attrMapDe.put("Kompass", 47); + attrMapPl.put("Kompass", 47); + attrMapDe.put("Brújula", 47); + attrMapPl.put("Brújula", 47); + attrMapDe.put("Bussola", 47); + attrMapPl.put("Bussola", 47); + attrMapPl.put("Take something to write", 48); + attrMapPl.put("Weź coś do pisania", 48); + attrMapPl.put("You may need a shovel", 81); + attrMapPl.put("Potrzebna łopatka", 81); + attrMapDe.put("Flashlight required", 48); + attrMapPl.put("Flashlight required", 82); + attrMapDe.put("Potrzebna latarka", 48); + attrMapPl.put("Potrzebna latarka", 82); + attrMapDe.put("Taschenlampe", 48); + attrMapPl.put("Taschenlampe", 82); + attrMapDe.put("Linterna", 48); + attrMapPl.put("Linterna", 82); + attrMapDe.put("Lampada tascabile", 48); + attrMapPl.put("Lampada tascabile", 82); + attrMapDe.put("Climbing gear required", 49); + attrMapDe.put("Kletterzeug", 49); + attrMapDe.put("Equipo de escalada", 49); + attrMapDe.put("Attrezzatura per arrampicata", 49); + attrMapDe.put("Cave equipment required", 50); + attrMapDe.put("Höhlenzeug", 50); + attrMapDe.put("Equipación para cuevas", 50); + attrMapDe.put("Attrezzatura per grotta", 50); + attrMapDe.put("Diving equipment required", 51); + attrMapDe.put("Taucherausrüstung", 51); + attrMapDe.put("Diving equipment", 51); + attrMapDe.put("Equipo de buceo", 51); + attrMapDe.put("Special tools required", 46); + attrMapPl.put("Special tools required", 83); + attrMapDe.put("Wymagany dodatkowy sprzęt", 46); + attrMapPl.put("Wymagany dodatkowy sprzęt", 83); + attrMapDe.put("spezielle Ausrüstung", 46); + attrMapPl.put("spezielle Ausrüstung", 83); + attrMapDe.put("Equipamiento especial", 46); + attrMapPl.put("Equipamiento especial", 83); + attrMapDe.put("Equipaggiamento speciale", 46); + attrMapPl.put("Equipaggiamento speciale", 83); + attrMapDe.put("Requires a boat", 52); + attrMapPl.put("Requires a boat", 86); + attrMapDe.put("Wymaga sprzętu pływającego", 52); + attrMapPl.put("Wymaga sprzętu pływającego", 86); + attrMapDe.put("Wasserfahrzeug", 52); + attrMapPl.put("Wasserfahrzeug", 86); + attrMapDe.put("Barca", 52); + attrMapPl.put("Barca", 86); + attrMapDe.put("Barca", 52); + attrMapPl.put("Barca", 86); + attrMapDe.put("No GPS required", 35); + attrMapDe.put("ohne GPS findbar", 35); + attrMapDe.put("Sin GPS", 35); + attrMapDe.put("Senza GPS", 35); + attrMapDe.put("Dangerous area", 9); + attrMapPl.put("Dangerous area", 90); + attrMapDe.put("Skrzynka niebezpieczna", 9); + attrMapPl.put("Skrzynka niebezpieczna", 90); + attrMapDe.put("gefährliches Gebiet", 9); + attrMapPl.put("gefährliches Gebiet", 90); + attrMapDe.put("Zona Peligrosa", 9); + attrMapPl.put("Zona Peligrosa", 90); + attrMapDe.put("Area pericolosa", 9); + attrMapPl.put("Area pericolosa", 90); + attrMapDe.put("Active railway nearby", 10); + attrMapDe.put("aktive Eisenbahnlinie in der Nähe", 10); + attrMapDe.put("Cerca del ferrocarril activo", 10); + attrMapDe.put("Ferrovia attiva nei pressi", 10); + attrMapDe.put("Cliff / Rocks", 11); + attrMapDe.put("Klippen / Felsen", 11); + attrMapDe.put("Acantilado / Rocas", 11); + attrMapDe.put("Scogliera / Rocce", 11); + attrMapDe.put("Hunting", 12); + attrMapDe.put("Jagdgebiet", 12); + attrMapDe.put("Zona de Caza", 12); + attrMapDe.put("Caccia", 12); + attrMapDe.put("Thorns", 13); + attrMapDe.put("Dornen", 13); + attrMapDe.put("Espinas", 13); + attrMapDe.put("Spine", 13); + attrMapDe.put("Ticks", 14); + attrMapDe.put("Zecken", 14); + attrMapDe.put("Garrapatas", 14); + attrMapDe.put("Zecche", 14); + attrMapDe.put("Abandoned mines", 15); + attrMapDe.put("Folgen des Bergbaus", 15); + attrMapDe.put("Mina abandonada", 15); + attrMapDe.put("Miniere abbandonate", 15); + attrMapDe.put("Poisonous plants", 16); + attrMapDe.put("giftige Pflanzen", 16); + attrMapDe.put("Planta venenosa", 16); + attrMapDe.put("Piante velenose", 16); + attrMapDe.put("Dangerous animals", 17); + attrMapDe.put("giftige/gefährliche Tiere", 17); + attrMapDe.put("Animales Peligrosos", 17); + attrMapDe.put("Animali pericolosi", 17); + attrMapPl.put("Quick cache", 40); + attrMapPl.put("Szybka skrzynka", 40); + attrMapDe.put("Overnight stay necessary", 37); + attrMapDe.put("Übernachtung erforderlich", 37); + attrMapDe.put("Necesario pernoctar", 37); + attrMapDe.put("Necessario pernottamento", 37); + attrMapPl.put("Take your children", 41); + attrMapPl.put("Można zabrać dzieci", 41); + attrMapDe.put("Suited for children (10-12 yo)", 59); + attrMapDe.put("kindgerecht (10-12 Jahre)", 59); + attrMapDe.put("Apto para niños (10-12 años)", 59); + attrMapDe.put("Suited for children (10-12 anni)", 59); + // first trailer line + + } + + public static int getOcDeId(final String name) { + + int result = 0; + + if (attrMapDe.containsKey(name)) { + result = attrMapDe.get(name); + } + return result; + } +} diff --git a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java b/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java deleted file mode 100644 index d03062f..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java +++ /dev/null @@ -1,762 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.Geocache; -import cgeo.geocaching.Image; -import cgeo.geocaching.LogEntry; -import cgeo.geocaching.R; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgeoapplication; -import cgeo.geocaching.connector.ConnectorFactory; -import cgeo.geocaching.connector.IConnector; -import cgeo.geocaching.connector.gc.GCConnector; -import cgeo.geocaching.enumerations.CacheAttribute; -import cgeo.geocaching.enumerations.CacheSize; -import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.LogType; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.utils.Log; - -import org.apache.commons.lang3.StringUtils; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; - -import android.content.res.Resources; -import android.sax.Element; -import android.sax.EndElementListener; -import android.sax.EndTextElementListener; -import android.sax.RootElement; -import android.sax.StartElementListener; -import android.util.Xml; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class OC11XMLParser { - - private static final String[] MARKUP = new String[] { "p", "span" }; - private static Pattern STRIP_DATE = Pattern.compile("\\+0([0-9]){1}\\:00"); - private static Pattern LOCAL_URL = Pattern.compile("href=\"(.*)\""); - private static final int CACHE_PARSE_LIMIT = 250; - private static final Resources res = cgeoapplication.getInstance().getResources(); - private static final Pattern WHITESPACE = Pattern.compile("<p>(\\s| )*</p>"); - - - private static ImageHolder imageHolder = null; - - private static class CacheHolder { - public Geocache cache; - public String latitude; - public String longitude; - } - - private static class CacheLog { - public String id; - public String cacheId; - public LogEntry logEntry; - } - - private static class CacheDescription { - public String cacheId; - public String shortDesc; - public String desc; - public String hint; - } - - private static class ImageHolder { - public String url; - public String objectId; - protected String title; - protected boolean isSpoiler = false; - } - - private static Date parseFullDate(final String date) { - final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); - ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); - final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100"); - try { - return ISO8601DATEFORMAT.parse(strippedDate); - } catch (ParseException e) { - Log.e("OC11XMLParser.parseFullDate", e); - } - return null; - } - - private static Date parseDayDate(final String date) { - final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US); - ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); - final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100"); - try { - return ISO8601DATEFORMAT.parse(strippedDate); - } catch (ParseException e) { - Log.e("OC11XMLParser.parseDayDate", e); - } - return null; - } - - private static CacheSize getCacheSize(final String sizeId) { - try { - int size = Integer.parseInt(sizeId); - - switch (size) { - case 1: - return CacheSize.OTHER; - case 2: - return CacheSize.MICRO; - case 3: - return CacheSize.SMALL; - case 4: - return CacheSize.REGULAR; - case 5: - case 6: - return CacheSize.LARGE; - case 8: - return CacheSize.VIRTUAL; - default: - break; - } - } catch (NumberFormatException e) { - Log.e("OC11XMLParser.getCacheSize", e); - } - return CacheSize.NOT_CHOSEN; - } - - private static CacheType getCacheType(final String typeId) { - try { - int type = Integer.parseInt(typeId); - switch (type) { - case 1: // Other/unbekannter Cachetyp - return CacheType.UNKNOWN; - case 2: // Trad./normaler Cache - return CacheType.TRADITIONAL; - case 3: // Multi/Multicache - return CacheType.MULTI; - case 4: // Virt./virtueller Cache - return CacheType.VIRTUAL; - case 5: // ICam./Webcam-Cache - return CacheType.WEBCAM; - case 6: // Event/Event-Cache - return CacheType.EVENT; - case 7: // Quiz/Rätselcache - return CacheType.MYSTERY; - case 8: // Math/Mathe-/Physikcache - return CacheType.MYSTERY; - case 9: // Moving/beweglicher Cache - return CacheType.VIRTUAL; - case 10: // Driv./Drive-In - return CacheType.TRADITIONAL; - default: - return CacheType.UNKNOWN; - } - } catch (NumberFormatException e) { - Log.e("OC11XMLParser.getCacheType", e); - } - return CacheType.UNKNOWN; - } - - private static LogType getLogType(final int typeId) { - switch (typeId) { - case 1: - return LogType.FOUND_IT; - case 2: - return LogType.DIDNT_FIND_IT; - case 3: - return LogType.NOTE; - case 7: - return LogType.ATTENDED; - case 8: - return LogType.WILL_ATTEND; - default: - return LogType.UNKNOWN; - } - } - - private static void setCacheStatus(final int statusId, final Geocache cache) { - switch (statusId) { - case 1: - cache.setArchived(false); - cache.setDisabled(false); - break; - case 2: - cache.setArchived(false); - cache.setDisabled(true); - break; - default: - cache.setArchived(true); - cache.setDisabled(false); - break; - } - } - - private static void resetCache(final CacheHolder cacheHolder) { - cacheHolder.cache = new Geocache(null); - cacheHolder.cache.setReliableLatLon(true); - cacheHolder.cache.setDescription(StringUtils.EMPTY); - cacheHolder.latitude = "0.0"; - cacheHolder.longitude = "0.0"; - } - - private static void resetLog(final CacheLog log) { - log.cacheId = StringUtils.EMPTY; - log.logEntry = new LogEntry("", 0, LogType.UNKNOWN, ""); - } - - private static void resetDesc(final CacheDescription desc) { - desc.cacheId = StringUtils.EMPTY; - desc.shortDesc = StringUtils.EMPTY; - desc.desc = StringUtils.EMPTY; - desc.hint = StringUtils.EMPTY; - } - - private static int attributeId; - - public static Collection<Geocache> parseCaches(final InputStream stream) throws IOException { - // parse and return caches without filtering - return parseCaches(stream, true); - } - - public static Collection<Geocache> parseCachesFiltered(final InputStream stream) throws IOException { - // parse caches and filter result - return parseCaches(stream, false); - } - - private static Collection<Geocache> parseCaches(final InputStream stream, boolean ignoreFiltersIn) throws IOException { - - final Map<String, Geocache> caches = new HashMap<String, Geocache>(); - final Map<String, LogEntry> logs = new HashMap<String, LogEntry>(); - - final CacheHolder cacheHolder = new CacheHolder(); - final CacheLog logHolder = new CacheLog(); - final CacheDescription descHolder = new CacheDescription(); - - final RootElement root = new RootElement("oc11xml"); - final Element cacheNode = root.getChild("cache"); - - final boolean ignoreFilters = ignoreFiltersIn; - - // cache - cacheNode.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - resetCache(cacheHolder); - } - - }); - - cacheNode.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - Geocache cache = cacheHolder.cache; - Geopoint coords = new Geopoint(cacheHolder.latitude, cacheHolder.longitude); - cache.setCoords(coords); - if (caches.size() < CACHE_PARSE_LIMIT && isValid(cache) && (ignoreFilters || !isExcluded(cache))) { - cache.setDetailedUpdatedNow(); - caches.put(cache.getCacheId(), cache); - } - } - - private boolean isExcluded(Geocache cache) { - if (cache.isArchived()) { - return true; - } - if (cache.isDisabled() && Settings.isExcludeDisabledCaches()) { - return true; - } - if ((cache.isFound() || cache.isOwner()) && Settings.isExcludeMyCaches()) { - return true; - } - return !Settings.getCacheType().contains(cache); - } - - private boolean isValid(Geocache cache) { - return StringUtils.isNotBlank(cache.getGeocode()) && !cache.getCoords().equals(Geopoint.ZERO); - } - }); - - // cache.id - cacheNode.getChild("id").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - cacheHolder.cache.setCacheId(body); - } - }); - - // cache.longitude - cacheNode.getChild("longitude").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - String longitude = body.trim(); - if (StringUtils.isNotBlank(longitude)) { - cacheHolder.longitude = longitude; - } - } - }); - - // cache.latitude - cacheNode.getChild("latitude").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - String latitude = body.trim(); - if (StringUtils.isNotBlank(latitude)) { - cacheHolder.latitude = latitude; - } - } - }); - - // cache.name - cacheNode.getChild("name").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - cacheHolder.cache.setName(content); - } - }); - - // cache.waypoints[oc] - cacheNode.getChild("waypoints").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("oc") > -1) { - cacheHolder.cache.setGeocode(attrs.getValue("oc")); - } - if (attrs.getIndex("gccom") > -1) { - String gccode = attrs.getValue("gccom"); - if (!StringUtils.isBlank(gccode)) { - cacheHolder.cache.setDescription(res.getString(R.string.cache_listed_on, GCConnector.getInstance().getName()) + ": <a href=\"http://coord.info/" + gccode + "\">" + gccode + "</a><br /><br />"); - } - } - } - }); - - // cache.type[id] - cacheNode.getChild("type").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - final String typeId = attrs.getValue("id"); - cacheHolder.cache.setType(getCacheType(typeId)); - } - } - }); - - // cache.status[id] - cacheNode.getChild("status").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - try { - final int statusId = Integer.parseInt(attrs.getValue("id")); - setCacheStatus(statusId, cacheHolder.cache); - } catch (NumberFormatException e) { - Log.w(String.format("Failed to parse status of cache '%s'.", cacheHolder.cache.getGeocode())); - } - } - } - }); - - // cache.size[id] - cacheNode.getChild("size").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - final String typeId = attrs.getValue("id"); - cacheHolder.cache.setSize(getCacheSize(typeId)); - } - } - }); - - // cache.difficulty - cacheNode.getChild("difficulty").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - try { - cacheHolder.cache.setDifficulty(Float.valueOf(content)); - } catch (NumberFormatException e) { - Log.e("OC11XMLParser: unknown difficulty " + content, e); - } - } - }); - - // cache.terrain - cacheNode.getChild("terrain").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - try { - cacheHolder.cache.setTerrain(Float.valueOf(content)); - } catch (NumberFormatException e) { - Log.e("OC11XMLParser: unknown terrain " + content, e); - } - } - }); - - // cache.datehidden - cacheNode.getChild("datehidden").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - cacheHolder.cache.setHidden(parseFullDate(content)); - } - }); - - // cache.userid - final Element useridNode = cacheNode.getChild("userid"); - - useridNode.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - if (attributes.getIndex("id") > -1) { - cacheHolder.cache.setOwnerUserId(attributes.getValue("id")); - } - } - }); - - useridNode.setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - cacheHolder.cache.setOwnerDisplayName(body); - } - }); - - // cache.attributes.attribute - final Element attributeNode = cacheNode.getChild("attributes").getChild("attribute"); - - attributeNode.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - if (attributes.getIndex("id") > -1) { - try { - attributeId = Integer.parseInt(attributes.getValue("id")); - } catch (NumberFormatException e) { - Log.w(String.format("Failed to parse attribute id of cache '%s'.", cacheHolder.cache.getGeocode())); - } - } - } - }); - - attributeNode.setEndTextElementListener(new EndTextElementListener() { - @Override - public void end(String body) { - CacheAttribute attribute = CacheAttribute.getByOcId(attributeId); - if (attribute != null) { - // semantic of attributes on opencaching is always "yes" - cacheHolder.cache.getAttributes().add(attribute.getAttributeName(true)); - } - else { - if (StringUtils.isNotBlank(body)) { - cacheHolder.cache.getAttributes().add(body.trim()); - } - } - } - }); - - // cachedesc - final Element cacheDesc = root.getChild("cachedesc"); - - cacheDesc.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - resetDesc(descHolder); - } - }); - - cacheDesc.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - final Geocache cache = caches.get(descHolder.cacheId); - if (cache != null) { - cache.setShortDescription(descHolder.shortDesc); - cache.setDescription(cache.getDescription() + descHolder.desc); - cache.setHint(descHolder.hint); - } - } - }); - - // cachedesc.cacheid - cacheDesc.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - descHolder.cacheId = body; - } - }); - - // cachedesc.desc - cacheDesc.getChild("shortdesc").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - descHolder.shortDesc = linkify(stripEmptyText(content)); - } - }); - - // cachedesc.desc - cacheDesc.getChild("desc").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - descHolder.desc = linkify(stripEmptyText(content)); - } - }); - - // cachedesc.hint - cacheDesc.getChild("hint").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - descHolder.hint = body.trim(); - } - }); - - // cachelog - final Element cacheLog = root.getChild("cachelog"); - - cacheLog.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - resetLog(logHolder); - } - }); - - cacheLog.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - final Geocache cache = caches.get(logHolder.cacheId); - if (cache != null && logHolder.logEntry.type != LogType.UNKNOWN) { - logs.put(logHolder.id, logHolder.logEntry); - cache.getLogs().add(0, logHolder.logEntry); - if ((logHolder.logEntry.type == LogType.FOUND_IT || logHolder.logEntry.type == LogType.ATTENDED) - && StringUtils.equalsIgnoreCase(logHolder.logEntry.author, Settings.getOCConnectorUserName())) { - cache.setFound(true); - cache.setVisitedDate(logHolder.logEntry.date); - } - } - } - }); - - // cachelog.id - cacheLog.getChild("id").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - logHolder.id = StringUtils.trim(body); - } - }); - - // cachelog.cacheid - cacheLog.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - logHolder.cacheId = body; - } - }); - - // cachelog.date - cacheLog.getChild("date").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - try { - logHolder.logEntry.date = parseDayDate(body).getTime(); - } catch (NullPointerException e) { - Log.w("Failed to parse log date", e); - } - } - }); - - // cachelog.logtype - cacheLog.getChild("logtype").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - final String id = attrs.getValue("id"); - try { - final int typeId = Integer.parseInt(id); - logHolder.logEntry.type = getLogType(typeId); - } catch (NumberFormatException e) { - Log.e("OC11XMLParser, unknown logtype " + id, e); - } - } - } - }); - - // cachelog.userid - cacheLog.getChild("userid").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String finderName) { - logHolder.logEntry.author = finderName; - } - }); - - // cachelog.text - cacheLog.getChild("text").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String logText) { - logHolder.logEntry.log = stripEmptyText(logText); - } - }); - - // pictures - final Element picture = root.getChild("picture"); - - picture.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - imageHolder = new ImageHolder(); - } - }); - - picture.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - if (imageHolder.isSpoiler) { - final Geocache cache = caches.get(imageHolder.objectId); - if (cache != null) { - Image spoiler = new Image(imageHolder.url, imageHolder.title); - cache.addSpoiler(spoiler); - } - } - else { - final LogEntry log = logs.get(imageHolder.objectId); - if (log != null) { - log.addLogImage(new Image(imageHolder.url, imageHolder.title)); - } - } - } - }); - - // picture.object - picture.getChild("object").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - imageHolder.objectId = StringUtils.trim(body); - } - }); - - // picture.title - picture.getChild("title").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - imageHolder.title = StringUtils.trim(body); - } - }); - - // picture.url - picture.getChild("url").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - imageHolder.url = StringUtils.trim(body); - } - }); - - // picture.attributes - picture.getChild("attributes").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - if (attributes.getIndex("spoiler") > -1) { - String spoiler = attributes.getValue("spoiler"); - imageHolder.isSpoiler = ("1".equals(spoiler)); - } - } - }); - - try { - Xml.parse(stream, Xml.Encoding.UTF_8, root.getContentHandler()); - return caches.values(); - } catch (SAXException e) { - Log.e("Cannot parse .gpx file as oc11xml: could not parse XML", e); - return null; - } - } - - /** - * Converts local links to absolute links targeting the OC website. - */ - private static String linkify(String input) { - String result = input; - Matcher matcher = LOCAL_URL.matcher(result); - while (matcher.find()) { - String url = matcher.group(1); - if (!url.contains(":/")) { - IConnector ocConnector = ConnectorFactory.getConnector("OCXXX"); - String prefix = "http://" + ocConnector.getHost() + "/"; - result = StringUtils.replace(result, url, prefix + url); - matcher = LOCAL_URL.matcher(result); - } - } - return result; - } - - /** - * Removes some unneeded markup and whitespace. Log texts are typically encapsulated in paragraph tags which lead to - * more empty space on rendering. - */ - protected static String stripEmptyText(String input) { - final Matcher matcher = WHITESPACE.matcher(input); - String result = matcher.replaceAll("").trim(); - if (!StringUtils.startsWith(result, "<")) { - return result; - } - return stripMarkup(result); - } - - private static String stripMarkup(final String input) { - String result = input; - for (String tagName : MARKUP) { - final String startTag = "<" + tagName + ">"; - if (StringUtils.startsWith(result, startTag)) { - final String endTag = "</" + tagName + ">"; - if (StringUtils.endsWith(result, endTag)) { - String inner = result.substring(startTag.length(), result.length() - endTag.length()).trim(); - String nested = stripMarkup(inner); - if (!nested.contains(startTag)) { - result = nested; - } - } - } - } - return result; - } -}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java index 69cf8a4..3780c4d 100644 --- a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java +++ b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java @@ -23,7 +23,7 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode { @Override public String getLicenseText(final Geocache cache) { // NOT TO BE TRANSLATED - return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons BY-SA 3.0 License"; + return "© " + cache.getOwnerDisplayName() + ", <a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a>, CC-BY-NC-ND, alle Logeinträge © jeweiliger Autor"; } @Override @@ -40,4 +40,8 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode { // currently always active, but only for details download return true; } + + public String getCK() { + return CryptUtils.rot13(cK); + } } diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java new file mode 100644 index 0000000..4e57831 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java @@ -0,0 +1,82 @@ +package cgeo.geocaching.connector.oc; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.cgData; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.capability.ISearchByCenter; +import cgeo.geocaching.connector.capability.ISearchByViewPort; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; +import cgeo.geocaching.utils.CryptUtils; + +import android.app.Activity; + +public class OCApiLiveConnector extends OCApiConnector implements ISearchByCenter, ISearchByViewPort { + + private String cS; + + public OCApiLiveConnector(String name, String host, String prefix, int cKResId, int cSResId) { + super(name, host, prefix, CryptUtils.rot13(cgeoapplication.getInstance().getResources().getString(cKResId))); + + cS = CryptUtils.rot13(cgeoapplication.getInstance().getResources().getString(cSResId)); + } + + @Override + public SearchResult searchByViewport(Viewport viewport, String[] tokens) { + return new SearchResult(OkapiClient.getCachesBBox(viewport, this)); + } + + @Override + public SearchResult searchByCenter(Geopoint center) { + + return new SearchResult(OkapiClient.getCachesAround(center, this)); + } + + public String getCS() { + return CryptUtils.rot13(cS); + } + + @Override + public boolean supportsWatchList() { + return true; + } + + @Override + public boolean addToWatchlist(Geocache cache) { + final boolean added = OkapiClient.setWatchState(cache, true, this); + + if (added) { + cgData.saveChangedCache(cache); + } + + return added; + } + + @Override + public boolean removeFromWatchlist(Geocache cache) { + final boolean removed = OkapiClient.setWatchState(cache, false, this); + + if (removed) { + cgData.saveChangedCache(cache); + } + + return removed; + } + + @Override + public boolean supportsLogging() { + return true; + } + + @Override + public ILoggingManager getLoggingManager(Activity activity, Geocache cache) { + return new OkapiLoggingManager(activity, this, cache); + } + + @Override + public boolean canLog(Geocache cache) { + return true; + } +} diff --git a/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java new file mode 100644 index 0000000..779c1c5 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java @@ -0,0 +1,109 @@ +package cgeo.geocaching.connector.oc; + +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.network.OAuthAuthorizationActivity; + +import org.apache.commons.lang3.tuple.ImmutablePair; + +public class OCAuthorizationActivity extends OAuthAuthorizationActivity { + + private final int siteResId = R.string.auth_ocde; + + public OCAuthorizationActivity() { + super("www.opencaching.de", + "/okapi/services/oauth/request_token", + "/okapi/services/oauth/authorize", + "/okapi/services/oauth/access_token", + false, + cgeoapplication.getInstance().getResources().getString(R.string.oc_de_okapi_consumer_key), + cgeoapplication.getInstance().getResources().getString(R.string.oc_de_okapi_consumer_secret)); + } + + @Override + protected ImmutablePair<String, String> getTempToken() { + return Settings.getTempOCDEToken(); + } + + @Override + protected void setTempTokens(String tokenPublic, String tokenSecret) { + Settings.setOCDETempTokens(tokenPublic, tokenSecret); + } + + @Override + protected void setTokens(String tokenPublic, String tokenSecret, boolean enable) { + Settings.setOCDETokens(tokenPublic, tokenSecret, enable); + } + + @Override + protected String getAuthTitle() { + return res.getString(siteResId); + } + + @Override + protected String getAuthAgain() { + return res.getString(R.string.auth_again_oc); + } + + @Override + protected String getErrAuthInitialize() { + return res.getString(R.string.err_auth_initialize); + } + + @Override + protected String getAuthStart() { + return res.getString(R.string.auth_start_oc); + } + + @Override + protected String getAuthDialogCompleted() { + return res.getString(R.string.auth_dialog_completed_oc, getAuthTitle()); + } + + @Override + protected String getErrAuthProcess() { + return res.getString(R.string.err_auth_process); + } + + @Override + protected String getAuthDialogWait() { + return res.getString(R.string.auth_dialog_wait_oc, getAuthTitle()); + } + + @Override + protected String getAuthDialogPinTitle() { + return res.getString(R.string.auth_dialog_pin_title_oc); + } + + @Override + protected String getAuthDialogPinMessage() { + return res.getString(R.string.auth_dialog_pin_message_oc, getAuthTitle()); + } + + @Override + protected String getAboutAuth1() { + return res.getString(R.string.about_auth_1_oc, getAuthTitle()); + } + + @Override + protected String getAboutAuth2() { + return res.getString(R.string.about_auth_2_oc, getAuthTitle(), getAuthTitle()); + } + + @Override + protected String getAuthAuthorize() { + return res.getString(R.string.auth_authorize_oc); + } + + @Override + protected String getAuthPinHint() { + return res.getString(R.string.auth_pin_hint_oc, getAuthTitle()); + } + + @Override + protected String getAuthFinish() { + return res.getString(R.string.auth_finish_oc); + } + +} diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java deleted file mode 100644 index 43fdcfc..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java +++ /dev/null @@ -1,67 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.Geocache; -import cgeo.geocaching.ICache; -import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; -import cgeo.geocaching.connector.capability.ISearchByCenter; -import cgeo.geocaching.connector.capability.ISearchByGeocode; -import cgeo.geocaching.connector.capability.ISearchByViewPort; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.ui.Formatter; -import cgeo.geocaching.utils.CancellableHandler; - -import org.apache.commons.lang3.StringUtils; - -public class OCXMLApiConnector extends OCConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort { - - private final static double SEARCH_DISTANCE_LIMIT = 15.0; - private final static double NEARBY_SEARCH_DISTANCE = 5.0; - - public OCXMLApiConnector(String name, String host, String prefix) { - super(name, host, prefix); - } - - @Override - public SearchResult searchByGeocode(final String geocode, final String guid, CancellableHandler handler) { - final Geocache cache = OCXMLClient.getCache(geocode); - if (cache == null) { - return null; - } - return new SearchResult(cache); - } - - @Override - public SearchResult searchByCenter(final Geopoint center) { - return new SearchResult(OCXMLClient.getCachesAround(center, NEARBY_SEARCH_DISTANCE)); - } - - @Override - public SearchResult searchByViewport(final Viewport viewport, final String[] tokens) { - final Geopoint center = viewport.getCenter(); - double distance = center.distanceTo(viewport.bottomLeft) * 1.15; - if (distance > SEARCH_DISTANCE_LIMIT) { - distance = SEARCH_DISTANCE_LIMIT; - } - return new SearchResult(OCXMLClient.getCachesAround(center, distance)); - } - - @Override - public boolean isActivated() { - // currently only tested and working with oc.de - return Settings.isOCConnectorActive(); - } - - @Override - public boolean isOwner(ICache cache) { - return StringUtils.equalsIgnoreCase(cache.getOwnerDisplayName(), Settings.getOCConnectorUserName()); - } - - @Override - public String getLicenseText(Geocache cache) { - // not to be translated - return "© " + cache.getOwnerDisplayName() + ", " + "<a href=\"" + getCacheUrl(cache) + "\">www.opencaching.de</a>, CC-BY-NC-ND, Stand: " + Formatter.formatFullDate(cache.getUpdated()); - } - -} diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java b/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java deleted file mode 100644 index df75682..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java +++ /dev/null @@ -1,122 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.Geocache; -import cgeo.geocaching.cgData; -import cgeo.geocaching.connector.ConnectorFactory; -import cgeo.geocaching.connector.IConnector; -import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.network.Network; -import cgeo.geocaching.network.Parameters; -import cgeo.geocaching.utils.IOUtils; -import cgeo.geocaching.utils.Log; - -import ch.boye.httpclientandroidlib.HttpResponse; - -import org.apache.commons.lang3.StringUtils; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.Collections; -import java.util.Locale; -import java.util.zip.GZIPInputStream; - -public class OCXMLClient { - - private static final String SERVICE_CACHE = "/xml/ocxml11.php"; - - // Url for single cache requests - // http://www.opencaching.de/xml/ocxml11.php?modifiedsince=20060320000000&user=0&cache=1&cachedesc=1&cachelog=1&picture=1&removedobject=0&session=0&doctype=0&charset=utf-8&wp=OCC9BE - - public static Geocache getCache(final String geoCode) { - try { - final Parameters params = getOCXmlQueryParameters(true, true, true); - params.put("wp", geoCode); - final InputStream data = request(ConnectorFactory.getConnector(geoCode), SERVICE_CACHE, params); - - if (data == null) { - return null; - } - - final BufferedInputStream stream = new BufferedInputStream(new GZIPInputStream(data)); - Collection<Geocache> caches = OC11XMLParser.parseCaches(stream); - if (caches.iterator().hasNext()) { - Geocache cache = caches.iterator().next(); - cgData.saveCache(cache, LoadFlags.SAVE_ALL); - IOUtils.closeQuietly(stream); - return cache; - } - return null; - } catch (IOException e) { - Log.e("Error parsing cache '" + geoCode + "'", e); - return null; - } - } - - public static Collection<Geocache> getCachesAround(final Geopoint center, final double distance) { - try { - final Parameters params = getOCXmlQueryParameters(false, false, false); - params.put("lat", GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center)); - params.put("lon", GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center)); - params.put("distance", String.format(Locale.US, "%f", distance)); - final InputStream data = request(ConnectorFactory.getConnector("OCXXX"), SERVICE_CACHE, params); - - if (data == null) { - return Collections.emptyList(); - } - - final BufferedInputStream stream = new BufferedInputStream(new GZIPInputStream(data)); - final Collection<Geocache> result = OC11XMLParser.parseCachesFiltered(stream); - IOUtils.closeQuietly(stream); - return result; - } catch (IOException e) { - Log.e("Error parsing nearby search result", e); - return Collections.emptyList(); - } - } - - private static InputStream request(final IConnector connector, final String service, final Parameters params) { - if (connector == null) { - return null; - } - if (!(connector instanceof OCXMLApiConnector)) { - return null; - } - - final String host = connector.getHost(); - if (StringUtils.isBlank(host)) { - return null; - } - - final String uri = "http://" + host + service; - HttpResponse resp = Network.getRequest(uri, params); - if (resp != null) { - try { - return resp.getEntity().getContent(); - } catch (IllegalStateException e) { - // fall through and return null - } catch (IOException e) { - // fall through and return null - } - } - return null; - } - - private static Parameters getOCXmlQueryParameters(final boolean withDescription, final boolean withLogs, final boolean withImages) { - return new Parameters("modifiedsince", "20000101000000", - "user", "0", - "cache", "1", - "cachedesc", withDescription ? "1" : "0", - "cachelog", withLogs ? "1" : "0", - "picture", withImages ? "1" : "0", - "removedobject", "0", - "session", "0", - "doctype", "0", - "charset", "utf-8", - "zip", "gzip", - "picturefromcachelog", withImages ? "1" : "0"); - } -} diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java index 0673605..d8d92e1 100644 --- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java @@ -3,16 +3,27 @@ package cgeo.geocaching.connector.oc; import cgeo.geocaching.Geocache; import cgeo.geocaching.Image; import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.Waypoint; import cgeo.geocaching.cgData; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.LogResult; +import cgeo.geocaching.connector.gc.GCConnector; +import cgeo.geocaching.enumerations.CacheAttribute; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.OAuth; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.Log; @@ -22,17 +33,40 @@ import org.json.JSONException; import org.json.JSONObject; import android.net.Uri; -import android.text.Html; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.EnumSet; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; final public class OkapiClient { + + private static final SimpleDateFormat logDateFormat; + + static { + logDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.US); + logDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + private static final String CACHE_ATTRNAMES = "attrnames"; + private static final String WPT_LOCATION = "location"; + private static final String WPT_DESCRIPTION = "description"; + private static final String WPT_TYPE = "type"; + private static final String WPT_NAME = "name"; + private static final String CACHE_IS_WATCHED = "is_watched"; + private static final String CACHE_WPTS = "alt_wpts"; + private static final String CACHE_STATUS_ARCHIVED = "Archived"; + private static final String CACHE_STATUS_DISABLED = "Temporarily unavailable"; + private static final String CACHE_IS_FOUND = "is_found"; private static final String CACHE_SIZE = "size"; private static final String CACHE_VOTES = "rating_votes"; private static final String CACHE_NOTFOUNDS = "notfounds"; @@ -64,12 +98,22 @@ final public class OkapiClient { private static final String USER_USERNAME = "username"; private static final String SERVICE_CACHE = "/okapi/services/caches/geocache"; - private static final String SERVICE_CACHE_FIELDS = "code|name|location|type|status|owner|founds|notfounds|size|difficulty|terrain|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden"; - private static final String SERVICE_NEAREST = "/okapi/services/caches/search/nearest"; + private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|is_found"; + private static final String SERVICE_CACHE_FIELDS = SERVICE_CACHE_CORE_FIELDS + "|owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden|attribution_note|alt_wpts|is_watched|attrnames|gc_code"; + + private static final String SERVICE_SEARCH_AND_RETRIEVE = "/okapi/services/caches/shortcuts/search_and_retrieve"; + + private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest"; + private static final String METHOD_SEARCH_BBOX = "services/caches/search/bbox"; + private static final String METHOD_RETRIEVE_CACHES = "services/caches/geocaches"; + + private static final String SERVICE_MARK_CACHE = "/okapi/services/caches/mark"; + + private static final String SERVICE_SUBMIT_LOG = "/okapi/services/logs/submit"; public static Geocache getCache(final String geoCode) { - final Parameters params = new Parameters("cache_code", geoCode, "fields", SERVICE_CACHE_FIELDS); + final Parameters params = new Parameters("cache_code", geoCode, "fields", SERVICE_CACHE_FIELDS, "attribution_append", "none"); final JSONObject data = request(ConnectorFactory.getConnector(geoCode), SERVICE_CACHE, params); if (data == null) { @@ -81,30 +125,115 @@ final public class OkapiClient { public static List<Geocache> getCachesAround(final Geopoint center, IConnector connector) { String centerString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center) + "|" + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center); - final Parameters params = new Parameters("center", centerString); - final JSONObject data = request(connector, SERVICE_NEAREST, params); + final Parameters params = new Parameters("search_method", METHOD_SEARCH_NEAREST); + final Map<String, String> valueMap = new LinkedHashMap<String, String>(); + valueMap.put("center", centerString); + valueMap.put("limit", "20"); + + addFilterParams(valueMap); + + params.add("search_params", new JSONObject(valueMap).toString()); + + addRetrieveParams(params); + + final JSONObject data = request(connector, SERVICE_SEARCH_AND_RETRIEVE, params); if (data == null) { - return null; + return Collections.emptyList(); + } + + return parseCaches(data); + } + + public static List<Geocache> getCachesBBox(final Viewport viewport, IConnector connector) { + + if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) { + return Collections.emptyList(); + } + + String bboxString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, viewport.bottomLeft) + + "|" + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, viewport.bottomLeft) + + "|" + GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, viewport.topRight) + + "|" + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, viewport.topRight); + final Parameters params = new Parameters("search_method", METHOD_SEARCH_BBOX); + final Map<String, String> valueMap = new LinkedHashMap<String, String>(); + valueMap.put("bbox", bboxString); + + addFilterParams(valueMap); + + params.add("search_params", new JSONObject(valueMap).toString()); + + addRetrieveParams(params); + + final JSONObject data = request(connector, SERVICE_SEARCH_AND_RETRIEVE, params); + + if (data == null) { + return Collections.emptyList(); } return parseCaches(data); } + public static boolean setWatchState(final Geocache cache, final boolean watched, IConnector connector) { + final Parameters params = new Parameters("cache_code", cache.getGeocode()); + params.add("watched", watched ? "true" : "false"); + + final JSONObject data = request(connector, SERVICE_MARK_CACHE, params); + + if (data == null) { + return false; + } + + cache.setOnWatchlist(watched); + + return true; + } + + public static LogResult postLog(final Geocache cache, LogType logType, Calendar date, String log, IConnector connector) { + final Parameters params = new Parameters("cache_code", cache.getGeocode()); + params.add("logtype", logType.oc_type); + params.add("comment", log); + params.add("comment_format", "plaintext"); + params.add("when", logDateFormat.format(date.getTime())); + if (logType.equals(LogType.NEEDS_MAINTENANCE)) { + params.add("needs_maintenance", "true"); + } + + final JSONObject data = request(connector, SERVICE_SUBMIT_LOG, params); + + if (data == null) { + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + + try { + if (data.getBoolean("success")) { + return new LogResult(StatusCode.NO_ERROR, data.getString("log_uuid")); + } + + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } catch (JSONException e) { + Log.e("OkapiClient.postLog", e); + } + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + private static List<Geocache> parseCaches(final JSONObject response) { try { - final JSONArray cachesResponse = response.getJSONArray("results"); + // Check for empty result + final String result = response.getString("results"); + if (StringUtils.isBlank(result) || StringUtils.equals(result, "[]")) { + return Collections.emptyList(); + } + + // Get and iterate result list + final JSONObject cachesResponse = response.getJSONObject("results"); if (cachesResponse != null) { - ArrayList<String> geocodes = new ArrayList<String>(cachesResponse.length()); - for (int i = 0; i < cachesResponse.length(); i++) { - String geocode = cachesResponse.getString(i); - if (StringUtils.isNotBlank(geocode)) { - geocodes.add(geocode); - } - } - List<Geocache> caches = new ArrayList<Geocache>(geocodes.size()); - for (String geocode : geocodes) { - Geocache cache = getCache(geocode); + List<Geocache> caches = new ArrayList<Geocache>(cachesResponse.length()); + @SuppressWarnings("unchecked") + Iterator<String> keys = cachesResponse.keys(); + while (keys.hasNext()) { + String key = keys.next(); + Geocache cache = parseSmallCache(cachesResponse.getJSONObject(key)); if (cache != null) { caches.add(cache); } @@ -112,24 +241,31 @@ final public class OkapiClient { return caches; } } catch (JSONException e) { - Log.e("OkapiClient.parseCaches", e); + Log.e("OkapiClient.parseCachesResult", e); } - return null; + return Collections.emptyList(); + } + + private static Geocache parseSmallCache(final JSONObject response) { + final Geocache cache = new Geocache(); + cache.setReliableLatLon(true); + try { + + parseCoreCache(response, cache); + + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); + } catch (JSONException e) { + Log.e("OkapiClient.parseSmallCache", e); + } + return cache; } private static Geocache parseCache(final JSONObject response) { final Geocache cache = new Geocache(); cache.setReliableLatLon(true); try { - cache.setGeocode(response.getString(CACHE_CODE)); - cache.setName(response.getString(CACHE_NAME)); - // not used: names - setLocation(cache, response.getString(CACHE_LOCATION)); - cache.setType(getCacheType(response.getString(CACHE_TYPE))); - final String status = response.getString(CACHE_STATUS); - cache.setDisabled(status.equalsIgnoreCase("Temporarily unavailable")); - cache.setArchived(status.equalsIgnoreCase("Archived")); + parseCoreCache(response, cache); // not used: url final JSONObject owner = response.getJSONObject(CACHE_OWNER); @@ -137,9 +273,7 @@ final public class OkapiClient { cache.getLogCounts().put(LogType.FOUND_IT, response.getInt(CACHE_FOUNDS)); cache.getLogCounts().put(LogType.DIDNT_FIND_IT, response.getInt(CACHE_NOTFOUNDS)); - cache.setSize(getCacheSize(response)); - cache.setDifficulty((float) response.getDouble(CACHE_DIFFICULTY)); - cache.setTerrain((float) response.getDouble(CACHE_TERRAIN)); + if (!response.isNull(CACHE_RATING)) { cache.setRating((float) response.getDouble(CACHE_RATING)); } @@ -147,8 +281,22 @@ final public class OkapiClient { cache.setFavoritePoints(response.getInt(CACHE_RECOMMENDATIONS)); // not used: req_password - cache.setDescription(response.getString(CACHE_DESCRIPTION)); - cache.setHint(Html.fromHtml(response.getString(CACHE_HINT)).toString()); + // Prepend gc-link to description if available + StringBuilder description = new StringBuilder(500); + if (!response.isNull("gc_code")) { + String gccode = response.getString("gc_code"); + description.append(cgeoapplication.getInstance().getResources() + .getString(R.string.cache_listed_on, GCConnector.getInstance().getName())) + .append(": <a href=\"http://coord.info/") + .append(gccode) + .append("\">") + .append(gccode) + .append("</a><br /><br />"); + } + description.append(response.getString(CACHE_DESCRIPTION)); + cache.setDescription(description.toString()); + + cache.setHint(response.getString(CACHE_HINT)); // not used: hints final JSONArray images = response.getJSONArray(CACHE_IMAGES); @@ -163,9 +311,13 @@ final public class OkapiClient { } } - // not used: attrnames + cache.setAttributes(parseAttributes(response.getJSONArray(CACHE_ATTRNAMES))); cache.setLogs(parseLogs(response.getJSONArray(CACHE_LATEST_LOGS))); cache.setHidden(parseDate(response.getString(CACHE_HIDDEN))); + //TODO: Store license per cache + //cache.setLicense(response.getString("attribution_note")); + cache.setWaypoints(parseWaypoints(response.getJSONArray(CACHE_WPTS)), false); + cache.setOnWatchlist(response.getBoolean(CACHE_IS_WATCHED)); cache.setDetailedUpdatedNow(); // save full detailed caches @@ -176,6 +328,24 @@ final public class OkapiClient { return cache; } + private static void parseCoreCache(final JSONObject response, final Geocache cache) throws JSONException { + cache.setGeocode(response.getString(CACHE_CODE)); + cache.setName(response.getString(CACHE_NAME)); + // not used: names + setLocation(cache, response.getString(CACHE_LOCATION)); + cache.setType(getCacheType(response.getString(CACHE_TYPE))); + + final String status = response.getString(CACHE_STATUS); + cache.setDisabled(status.equalsIgnoreCase(CACHE_STATUS_DISABLED)); + cache.setArchived(status.equalsIgnoreCase(CACHE_STATUS_ARCHIVED)); + + cache.setSize(getCacheSize(response)); + cache.setDifficulty((float) response.getDouble(CACHE_DIFFICULTY)); + cache.setTerrain((float) response.getDouble(CACHE_TERRAIN)); + + cache.setFound(response.getBoolean(CACHE_IS_FOUND)); + } + private static String absoluteUrl(String url, String geocode) { final Uri uri = Uri.parse(url); @@ -214,6 +384,30 @@ final public class OkapiClient { return result; } + private static List<Waypoint> parseWaypoints(JSONArray wptsJson) { + List<Waypoint> result = null; + for (int i = 0; i < wptsJson.length(); i++) { + try { + JSONObject wptResponse = wptsJson.getJSONObject(i); + Waypoint wpt = new Waypoint(wptResponse.getString(WPT_NAME), + parseWptType(wptResponse.getString(WPT_TYPE)), + false); + wpt.setNote(wptResponse.getString(WPT_DESCRIPTION)); + Geopoint pt = parseCoords(wptResponse.getString(WPT_LOCATION)); + if (pt != null) { + wpt.setCoords(pt); + } + if (result == null) { + result = new ArrayList<Waypoint>(); + } + result.add(wpt); + } catch (JSONException e) { + Log.e("OkapiClient.parseWaypoints", e); + } + } + return result; + } + private static LogType parseLogType(String logType) { if ("Found it".equalsIgnoreCase(logType)) { return LogType.FOUND_IT; @@ -224,6 +418,31 @@ final public class OkapiClient { return LogType.NOTE; } + private static WaypointType parseWptType(String wptType) { + if ("parking".equalsIgnoreCase(wptType)) { + return WaypointType.PARKING; + } + if ("path".equalsIgnoreCase(wptType)) { + return WaypointType.TRAILHEAD; + } + if ("stage".equalsIgnoreCase(wptType)) { + return WaypointType.STAGE; + } + if ("physical-stage".equalsIgnoreCase(wptType)) { + return WaypointType.STAGE; + } + if ("virtual-stage".equalsIgnoreCase(wptType)) { + return WaypointType.PUZZLE; + } + if ("final".equalsIgnoreCase(wptType)) { + return WaypointType.FINAL; + } + if ("poi".equalsIgnoreCase(wptType)) { + return WaypointType.TRAILHEAD; + } + return WaypointType.WAYPOINT; + } + private static Date parseDate(final String date) { final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()); final String strippedDate = date.replaceAll("\\+0([0-9]){1}\\:00", "+0$100"); @@ -235,6 +454,36 @@ final public class OkapiClient { return null; } + private static Geopoint parseCoords(final String location) { + final String latitude = StringUtils.substringBefore(location, "|"); + final String longitude = StringUtils.substringAfter(location, "|"); + if (StringUtils.isNotBlank(latitude) && StringUtils.isNotBlank(longitude)) { + return new Geopoint(latitude, longitude); + } + + return null; + } + + private static List<String> parseAttributes(JSONArray nameList) { + + List<String> result = new ArrayList<String>(); + + for (int i = 0; i < nameList.length(); i++) { + try { + String name = nameList.getString(i); + CacheAttribute attr = CacheAttribute.getByOcId(AttributeParser.getOcDeId(name)); + + if (attr != null) { + result.add(attr.rawName); + } + } catch (JSONException e) { + Log.e("OkapiClient.parseAttributes", e); + } + } + + return result; + } + private static void setLocation(final Geocache cache, final String location) { final String latitude = StringUtils.substringBefore(location, "|"); final String longitude = StringUtils.substringAfter(location, "|"); @@ -281,6 +530,18 @@ final public class OkapiClient { if (cacheType.equalsIgnoreCase("Virtual")) { return CacheType.VIRTUAL; } + if (cacheType.equalsIgnoreCase("Event")) { + return CacheType.EVENT; + } + if (cacheType.equalsIgnoreCase("Webcam")) { + return CacheType.WEBCAM; + } + if (cacheType.equalsIgnoreCase("Math/Physics")) { + return CacheType.MYSTERY; + } + if (cacheType.equalsIgnoreCase("Drive-In")) { + return CacheType.TRADITIONAL; + } return CacheType.UNKNOWN; } @@ -297,9 +558,10 @@ final public class OkapiClient { return null; } - ((OCApiConnector) connector).addAuthentication(params); params.add("langpref", getPreferredLanguage()); + OAuth.signOAuth(host, service, "GET", false, params, Settings.getOCDETokenPublic(), Settings.getOCDETokenSecret(), ((OCApiLiveConnector) connector).getCK(), ((OCApiLiveConnector) connector).getCS()); + final String uri = "http://" + host + service; return Network.requestJSON(uri, params); } @@ -311,4 +573,43 @@ final public class OkapiClient { } return "en"; } + + private static void addFilterParams(final Map<String, String> valueMap) { + if (!Settings.isExcludeDisabledCaches()) { + valueMap.put("status", "Available|Temporarily unavailable"); + } + if (Settings.isExcludeMyCaches()) { + valueMap.put("exclude_my_own", "true"); + valueMap.put("found_status", "notfound_only"); + } + if (Settings.getCacheType() != CacheType.ALL) { + valueMap.put("type", getFilterFromType(Settings.getCacheType())); + } + } + + private static void addRetrieveParams(final Parameters params) { + params.add("retr_method", METHOD_RETRIEVE_CACHES); + params.add("retr_params", "{\"fields\": \"" + SERVICE_CACHE_CORE_FIELDS + "\"}"); + params.add("wrap", "true"); + } + + private static String getFilterFromType(CacheType cacheType) { + switch (cacheType) { + case EVENT: + return "Event"; + case MULTI: + return "Multi"; + case MYSTERY: + return "Quiz"; + case TRADITIONAL: + return "Traditional"; + case VIRTUAL: + return "Virtual"; + case WEBCAM: + return "Webcam"; + default: + return ""; + } + } + } diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java new file mode 100644 index 0000000..24c6b79 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java @@ -0,0 +1,69 @@ +package cgeo.geocaching.connector.oc; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.VisitCacheActivity; +import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.ImageResult; +import cgeo.geocaching.connector.LogResult; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; + +import android.app.Activity; +import android.net.Uri; + +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +public class OkapiLoggingManager implements ILoggingManager { + + private final IConnector connector; + private final Geocache cache; + private VisitCacheActivity activity; + + private final static List<LogType> standardLogTypes = Arrays.asList(LogType.FOUND_IT, LogType.DIDNT_FIND_IT, LogType.NOTE, LogType.NEEDS_MAINTENANCE); + private final static List<LogType> eventLogTypes = Arrays.asList(LogType.WILL_ATTEND, LogType.ATTENDED, LogType.NOTE); + + public OkapiLoggingManager(Activity activity, IConnector connector, Geocache cache) { + this.connector = connector; + this.cache = cache; + this.activity = (VisitCacheActivity) activity; + } + + @Override + public void init() { + activity.onLoadFinished(); + } + + @Override + public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) { + return OkapiClient.postLog(cache, logType, date, log, connector); + } + + @Override + public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) { + return new ImageResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public boolean hasLoaderError() { + return false; + } + + @Override + public List<TrackableLog> getTrackables() { + return Collections.emptyList(); + } + + @Override + public List<LogType> getPossibleLogTypes() { + if (cache.isEventCache()) { + return eventLogTypes; + } + + return standardLogTypes; + } +} diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java index 71a5146..9902d3f 100644 --- a/main/src/cgeo/geocaching/enumerations/LogType.java +++ b/main/src/cgeo/geocaching/enumerations/LogType.java @@ -15,50 +15,52 @@ import java.util.Map; */ public enum LogType { - FOUND_IT(2, "2", "found it", R.string.log_found, R.drawable.mark_green), - DIDNT_FIND_IT(3, "3", "didn't find it", R.string.log_dnf, R.drawable.mark_red), - NOTE(4, "4", "write note", R.string.log_note), - PUBLISH_LISTING(1003, "24", "publish listing", R.string.log_published, R.drawable.mark_green_more), - ENABLE_LISTING(23, "23", "enable listing", R.string.log_enabled, R.drawable.mark_green_more), - ARCHIVE(5, "5", "archive", R.string.log_archived, R.drawable.mark_red_more), - UNARCHIVE(12, "12", "unarchive", R.string.log_unarchived, R.drawable.mark_green_more), - TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", R.string.log_disabled, R.drawable.mark_red_more), - NEEDS_ARCHIVE(7, "7", "needs archived", R.string.log_needs_archived, R.drawable.mark_red), - WILL_ATTEND(9, "9", "will attend", R.string.log_attend), - ATTENDED(10, "10", "attended", R.string.log_attended, R.drawable.mark_green), - RETRIEVED_IT(13, "13", "retrieved it", R.string.log_retrieved, R.drawable.mark_green_more), - PLACED_IT(14, "14", "placed it", R.string.log_placed, R.drawable.mark_green_more), - GRABBED_IT(19, "19", "grabbed it", R.string.log_grabbed, R.drawable.mark_green_more), - NEEDS_MAINTENANCE(45, "45", "needs maintenance", R.string.log_maintenance_needed, R.drawable.mark_red), - OWNER_MAINTENANCE(46, "46", "owner maintenance", R.string.log_maintained, R.drawable.mark_green_more), - UPDATE_COORDINATES(47, "47", "update coordinates", R.string.log_update), - DISCOVERED_IT(48, "48", "discovered it", R.string.log_discovered, R.drawable.mark_green), - POST_REVIEWER_NOTE(18, "68", "post reviewer note", R.string.log_reviewer), - VISIT(1001, "75", "visit", R.string.log_tb_visit, R.drawable.mark_green), - WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", R.string.log_webcam, R.drawable.mark_green), - ANNOUNCEMENT(74, "74", "announcement", R.string.log_announcement), - MOVE_COLLECTION(69, "69", "unused_collection", R.string.log_movecollection), - MOVE_INVENTORY(70, "70", "unused_inventory", R.string.log_moveinventory), - RETRACT(25, "25", "retract listing", R.string.log_retractlisting), - MARKED_MISSING(16, "16", "marked missing", R.string.log_marked_missing, R.drawable.mark_red), - UNKNOWN(0, "unknown", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet + FOUND_IT(2, "2", "found it", "Found it", R.string.log_found, R.drawable.mark_green), + DIDNT_FIND_IT(3, "3", "didn't find it", "Didn't find it", R.string.log_dnf, R.drawable.mark_red), + NOTE(4, "4", "write note", "Comment", R.string.log_note), + PUBLISH_LISTING(1003, "24", "publish listing", "", R.string.log_published, R.drawable.mark_green_more), + ENABLE_LISTING(23, "23", "enable listing", "", R.string.log_enabled, R.drawable.mark_green_more), + ARCHIVE(5, "5", "archive", "", R.string.log_archived, R.drawable.mark_red_more), + UNARCHIVE(12, "12", "unarchive", "", R.string.log_unarchived, R.drawable.mark_green_more), + TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", "", R.string.log_disabled, R.drawable.mark_red_more), + NEEDS_ARCHIVE(7, "7", "needs archived", "", R.string.log_needs_archived, R.drawable.mark_red), + WILL_ATTEND(9, "9", "will attend", "Will attend", R.string.log_attend), + ATTENDED(10, "10", "attended", "Attended", R.string.log_attended, R.drawable.mark_green), + RETRIEVED_IT(13, "13", "retrieved it", "", R.string.log_retrieved, R.drawable.mark_green_more), + PLACED_IT(14, "14", "placed it", "", R.string.log_placed, R.drawable.mark_green_more), + GRABBED_IT(19, "19", "grabbed it", "", R.string.log_grabbed, R.drawable.mark_green_more), + NEEDS_MAINTENANCE(45, "45", "needs maintenance", "Comment", R.string.log_maintenance_needed, R.drawable.mark_red), + OWNER_MAINTENANCE(46, "46", "owner maintenance", "", R.string.log_maintained, R.drawable.mark_green_more), + UPDATE_COORDINATES(47, "47", "update coordinates", "", R.string.log_update), + DISCOVERED_IT(48, "48", "discovered it", "", R.string.log_discovered, R.drawable.mark_green), + POST_REVIEWER_NOTE(18, "68", "post reviewer note", "", R.string.log_reviewer), + VISIT(1001, "75", "visit", "", R.string.log_tb_visit, R.drawable.mark_green), + WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", "", R.string.log_webcam, R.drawable.mark_green), + ANNOUNCEMENT(74, "74", "announcement", "", R.string.log_announcement), + MOVE_COLLECTION(69, "69", "unused_collection", "", R.string.log_movecollection), + MOVE_INVENTORY(70, "70", "unused_inventory", "", R.string.log_moveinventory), + RETRACT(25, "25", "retract listing", "", R.string.log_retractlisting), + MARKED_MISSING(16, "16", "marked missing", "", R.string.log_marked_missing, R.drawable.mark_red), + UNKNOWN(0, "unknown", "", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet public final int id; public final String iconName; public final String type; + public final String oc_type; private final int stringId; public final int markerId; - LogType(int id, String iconName, String type, int stringId, int markerId) { + LogType(int id, String iconName, String type, String oc_type, int stringId, int markerId) { this.id = id; this.iconName = iconName; this.type = type; + this.oc_type = oc_type; this.stringId = stringId; this.markerId = markerId; } - LogType(int id, String iconName, String type, int stringId) { - this(id, iconName, type, stringId, R.drawable.mark_gray); + LogType(int id, String iconName, String type, String oc_type, int stringId) { + this(id, iconName, type, oc_type, stringId, R.drawable.mark_gray); } private final static Map<String, LogType> FIND_BY_ICONNAME; diff --git a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java index ca2461c..09ea459 100644 --- a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java +++ b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java @@ -19,7 +19,11 @@ public class CoordsGeocacheListLoader extends AbstractSearchLoader { @Override public SearchResult runSearch() { - SearchResult search = GCParser.searchByCoords(coords, Settings.getCacheType(), Settings.isShowCaptcha(), this); + + SearchResult search = new SearchResult(); + if (Settings.isGCConnectorActive()) { + search = GCParser.searchByCoords(coords, Settings.getCacheType(), Settings.isShowCaptcha(), this); + } for (ISearchByCenter centerConn : ConnectorFactory.getSearchByCenterConnectors()) { if (centerConn.isActivated()) { diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index 0af0e6c..ea51375 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -1146,7 +1146,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto searchResult = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens); if (searchResult != null) { downloaded = true; - if (searchResult.getError() == StatusCode.NOT_LOGGED_IN) { + if (searchResult.getError() == StatusCode.NOT_LOGGED_IN && Settings.isGCConnectorActive()) { Login.login(); tokens = null; } else { diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java index 0b7a261..6740096 100644 --- a/main/src/cgeo/geocaching/network/OAuth.java +++ b/main/src/cgeo/geocaching/network/OAuth.java @@ -1,9 +1,9 @@ package cgeo.geocaching.network; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.CryptUtils; import ch.boye.httpclientandroidlib.NameValuePair; + import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; @@ -11,9 +11,17 @@ import java.util.Date; import java.util.List; public class OAuth { - public static void signOAuth(final String host, final String path, final String method, final boolean https, final Parameters params, final String token, final String tokenSecret) { + public static void signOAuth(final String host, + final String path, + final String method, + final boolean https, + final Parameters params, + final String token, + final String tokenSecret, + final String consumerKey, + final String consumerSecret) { params.put( - "oauth_consumer_key", Settings.getKeyConsumerPublic(), + "oauth_consumer_key", consumerKey, "oauth_nonce", CryptUtils.md5(Long.toString(System.currentTimeMillis())), "oauth_signature_method", "HMAC-SHA1", "oauth_timestamp", Long.toString(new Date().getTime() / 1000), @@ -26,7 +34,7 @@ public class OAuth { paramsEncoded.add(nameValue.getName() + "=" + Network.rfc3986URLEncode(nameValue.getValue())); } - final String keysPacked = Settings.getKeyConsumerSecret() + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them! + final String keysPacked = consumerSecret + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them! final String requestPacked = method + "&" + Network.rfc3986URLEncode((https ? "https" : "http") + "://" + host + path) + "&" + Network.rfc3986URLEncode(StringUtils.join(paramsEncoded.toArray(), '&')); params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked))); } diff --git a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java new file mode 100644 index 0000000..751443e --- /dev/null +++ b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java @@ -0,0 +1,326 @@ +package cgeo.geocaching.network; + +import cgeo.geocaching.R; +import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; + +import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity; +import ch.boye.httpclientandroidlib.util.EntityUtils; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import android.app.ProgressDialog; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import java.util.regex.Pattern; + +public abstract class OAuthAuthorizationActivity extends AbstractActivity { + + private String host; + private String pathRequest; + private String pathAuthorize; + private String pathAccess; + private boolean https; + private String consumerKey; + private String consumerSecret; + private String OAtoken = null; + private String OAtokenSecret = null; + private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)"); + private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_.]+)"); + private Button startButton = null; + private EditText pinEntry = null; + private Button pinEntryButton = null; + private ProgressDialog requestTokenDialog = null; + private ProgressDialog changeTokensDialog = null; + private Handler requestTokenHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + if (requestTokenDialog != null && requestTokenDialog.isShowing()) { + requestTokenDialog.dismiss(); + } + + startButton.setOnClickListener(new StartListener()); + startButton.setEnabled(true); + + if (msg.what == 1) { + startButton.setText(getAuthAgain()); + + pinEntry.setVisibility(View.VISIBLE); + pinEntryButton.setVisibility(View.VISIBLE); + pinEntryButton.setOnClickListener(new ConfirmPINListener()); + } else { + showToast(getErrAuthInitialize()); + startButton.setText(getAuthStart()); + } + } + + }; + private Handler changeTokensHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + if (changeTokensDialog != null && changeTokensDialog.isShowing()) { + changeTokensDialog.dismiss(); + } + + pinEntryButton.setOnClickListener(new ConfirmPINListener()); + pinEntryButton.setEnabled(true); + + if (msg.what == 1) { + showToast(getAuthDialogCompleted()); + + pinEntryButton.setVisibility(View.GONE); + + finish(); + } else { + showToast(getErrAuthProcess()); + + pinEntry.setVisibility(View.GONE); + pinEntryButton.setVisibility(View.GONE); + startButton.setText(getAuthStart()); + } + } + }; + + public OAuthAuthorizationActivity(String host, + String pathRequest, + String pathAuthorize, + String pathAccess, + boolean https, + String consumerKey, + String consumerSecret) { + this.host = host; + this.pathRequest = pathRequest; + this.pathAuthorize = pathAuthorize; + this.pathAccess = pathAccess; + this.https = https; + this.consumerKey = consumerKey; + this.consumerSecret = consumerSecret; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState, R.layout.authorization_activity); + + setTitle(getAuthTitle()); + + init(); + } + + private void init() { + startButton = (Button) findViewById(R.id.start); + pinEntry = (EditText) findViewById(R.id.pin); + pinEntryButton = (Button) findViewById(R.id.pin_button); + + TextView auth = (TextView) findViewById(R.id.auth_1); + auth.setText(getAboutAuth1()); + auth = (TextView) findViewById(R.id.auth_2); + auth.setText(getAboutAuth2()); + + ImmutablePair<String, String> tempToken = getTempToken(); + OAtoken = tempToken.left; + OAtokenSecret = tempToken.right; + + startButton.setText(getAuthAuthorize()); + pinEntryButton.setText(getAuthFinish()); + + startButton.setEnabled(true); + startButton.setOnClickListener(new StartListener()); + + if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { + // start authorization process + startButton.setText(getAuthStart()); + } else { + // already have temporary tokens, continue from pin + startButton.setText(getAuthAgain()); + + pinEntry.setHint(getAuthPinHint()); + pinEntry.setVisibility(View.VISIBLE); + pinEntryButton.setVisibility(View.VISIBLE); + pinEntryButton.setOnClickListener(new ConfirmPINListener()); + } + } + + private void requestToken() { + + int status = 0; + try { + final Parameters params = new Parameters(); + params.put("oauth_callback", "oob"); + final String method = "GET"; + OAuth.signOAuth(host, pathRequest, method, https, params, null, null, consumerKey, consumerSecret); + final String line = Network.getResponseData(Network.getRequest(getUrlPrefix() + host + pathRequest, params)); + + if (StringUtils.isNotBlank(line)) { + final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); + if (paramsMatcher1.find()) { + OAtoken = paramsMatcher1.group(1); + } + final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); + if (paramsMatcher2.find()) { + OAtokenSecret = paramsMatcher2.group(1); + } + + if (StringUtils.isNotBlank(OAtoken) && StringUtils.isNotBlank(OAtokenSecret)) { + setTempTokens(OAtoken, OAtokenSecret); + try { + final Parameters paramsBrowser = new Parameters(); + paramsBrowser.put("oauth_token", OAtoken); + final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser)); + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getUrlPrefix() + host + pathAuthorize + "?" + encodedParams))); + status = 1; + } catch (Exception e) { + Log.e("OAuthAuthorizationActivity.requestToken(2)", e); + } + } + } + } catch (Exception e) { + Log.e("OAuthAuthorizationActivity.requestToken(1)", e); + } + + requestTokenHandler.sendEmptyMessage(status); + } + + private void changeToken() { + + int status = 0; + + try { + final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString()); + + final String method = "POST"; + OAuth.signOAuth(host, pathAccess, method, https, params, OAtoken, OAtokenSecret, consumerKey, consumerSecret); + final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest(getUrlPrefix() + host + pathAccess, params))); + + OAtoken = ""; + OAtokenSecret = ""; + + final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); + if (paramsMatcher1.find()) { + OAtoken = paramsMatcher1.group(1); + } + final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); + if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) { + OAtokenSecret = paramsMatcher2.group(1); + } + + if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { + OAtoken = ""; + OAtokenSecret = ""; + setTokens(null, null, false); + } else { + setTokens(OAtoken, OAtokenSecret, true); + status = 1; + } + } catch (Exception e) { + Log.e("OAuthAuthorizationActivity.changeToken", e); + } + + changeTokensHandler.sendEmptyMessage(status); + } + + private String getUrlPrefix() { + return https ? "https://" : "http://"; + } + + private class StartListener implements View.OnClickListener { + + @Override + public void onClick(View arg0) { + if (requestTokenDialog == null) { + requestTokenDialog = new ProgressDialog(OAuthAuthorizationActivity.this); + requestTokenDialog.setCancelable(false); + requestTokenDialog.setMessage(getAuthDialogWait()); + } + requestTokenDialog.show(); + startButton.setEnabled(false); + startButton.setOnTouchListener(null); + startButton.setOnClickListener(null); + + setTempTokens(null, null); + (new Thread() { + + @Override + public void run() { + requestToken(); + } + }).start(); + } + } + + private class ConfirmPINListener implements View.OnClickListener { + + @Override + public void onClick(View arg0) { + if (StringUtils.isEmpty(((EditText) findViewById(R.id.pin)).getText().toString())) { + helpDialog(getAuthDialogPinTitle(), getAuthDialogPinMessage()); + return; + } + + if (changeTokensDialog == null) { + changeTokensDialog = new ProgressDialog(OAuthAuthorizationActivity.this); + changeTokensDialog.setCancelable(false); + changeTokensDialog.setMessage(getAuthDialogWait()); + } + changeTokensDialog.show(); + pinEntryButton.setEnabled(false); + pinEntryButton.setOnTouchListener(null); + pinEntryButton.setOnClickListener(null); + + (new Thread() { + + @Override + public void run() { + changeToken(); + } + }).start(); + } + } + + protected abstract ImmutablePair<String, String> getTempToken(); + + protected abstract void setTempTokens(String tokenPublic, String tokenSecret); + + protected abstract void setTokens(String tokenPublic, String tokenSecret, boolean enable); + + // get resources from derived class + + protected abstract String getAuthTitle(); + + protected abstract String getAuthAgain(); + + protected abstract String getErrAuthInitialize(); + + protected abstract String getAuthStart(); + + protected abstract String getAuthDialogCompleted(); + + protected abstract String getErrAuthProcess(); + + protected abstract String getAuthDialogWait(); + + protected abstract String getAuthDialogPinTitle(); + + protected abstract String getAuthDialogPinMessage(); + + protected abstract String getAboutAuth1(); + + protected abstract String getAboutAuth2(); + + protected abstract String getAuthAuthorize(); + + protected abstract String getAuthPinHint(); + + protected abstract String getAuthFinish(); +} diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java index e3d3f77..525b7f0 100644 --- a/main/src/cgeo/geocaching/twitter/Twitter.java +++ b/main/src/cgeo/geocaching/twitter/Twitter.java @@ -38,7 +38,7 @@ public final class Twitter { "display_coordinates", "true"); } - OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret()); + OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret(), Settings.getKeyConsumerPublic(), Settings.getKeyConsumerSecret()); final HttpResponse httpResponse = Network.postRequest("http://api.twitter.com/1/statuses/update.json", parameters); if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) { Log.i("Tweet posted"); diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java index 3bc1dec..7146a62 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -2,258 +2,105 @@ package cgeo.geocaching.twitter; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.activity.AbstractActivity; -import cgeo.geocaching.network.Network; -import cgeo.geocaching.network.OAuth; -import cgeo.geocaching.network.Parameters; -import cgeo.geocaching.utils.Log; -import cgeo.geocaching.utils.MatcherWrapper; +import cgeo.geocaching.network.OAuthAuthorizationActivity; -import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity; -import ch.boye.httpclientandroidlib.util.EntityUtils; - -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; - -import java.util.regex.Pattern; - -public class TwitterAuthorizationActivity extends AbstractActivity { - private String OAtoken = null; - private String OAtokenSecret = null; - private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)"); - private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_.]+)"); - private Button startButton = null; - private EditText pinEntry = null; - private Button pinEntryButton = null; - private ProgressDialog requestTokenDialog = null; - private ProgressDialog changeTokensDialog = null; - private Handler requestTokenHandler = new Handler() { - - @Override - public void handleMessage(Message msg) { - if (requestTokenDialog != null && requestTokenDialog.isShowing()) { - requestTokenDialog.dismiss(); - } - - startButton.setOnClickListener(new StartListener()); - startButton.setEnabled(true); - - if (msg.what == 1) { - startButton.setText(res.getString(R.string.auth_again)); - - pinEntry.setVisibility(View.VISIBLE); - pinEntryButton.setVisibility(View.VISIBLE); - pinEntryButton.setOnClickListener(new ConfirmPINListener()); - } else { - showToast(res.getString(R.string.err_auth_initialize)); - startButton.setText(res.getString(R.string.auth_start)); - } - } - }; - private Handler changeTokensHandler = new Handler() { +public class TwitterAuthorizationActivity extends OAuthAuthorizationActivity { - @Override - public void handleMessage(Message msg) { - if (changeTokensDialog != null && changeTokensDialog.isShowing()) { - changeTokensDialog.dismiss(); - } - - pinEntryButton.setOnClickListener(new ConfirmPINListener()); - pinEntryButton.setEnabled(true); - - if (msg.what == 1) { - showToast(res.getString(R.string.auth_dialog_completed)); - - pinEntryButton.setVisibility(View.GONE); - - finish(); - } else { - showToast(res.getString(R.string.err_auth_process)); - - pinEntry.setVisibility(View.GONE); - pinEntryButton.setVisibility(View.GONE); - startButton.setText(res.getString(R.string.auth_start)); - } - } - }; + public TwitterAuthorizationActivity() { + super("api.twitter.com", + "/oauth/request_token", + "/oauth/authorize", + "/oauth/access_token", + true, + Settings.getKeyConsumerPublic(), + Settings.getKeyConsumerSecret()); + } @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState, R.layout.twitter_authorization_activity); - - init(); + protected ImmutablePair<String, String> getTempToken() { + return Settings.getTempToken(); } - private void init() { - startButton = (Button) findViewById(R.id.start); - pinEntry = (EditText) findViewById(R.id.pin); - pinEntryButton = (Button) findViewById(R.id.pin_button); - - ImmutablePair<String, String> tempToken = Settings.getTempToken(); - OAtoken = tempToken.left; - OAtokenSecret = tempToken.right; - - startButton.setEnabled(true); - startButton.setOnClickListener(new StartListener()); - - if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { - // start authorization process - startButton.setText(res.getString(R.string.auth_start)); - } else { - // already have temporary tokens, continue from pin - startButton.setText(res.getString(R.string.auth_again)); - - pinEntry.setVisibility(View.VISIBLE); - pinEntryButton.setVisibility(View.VISIBLE); - pinEntryButton.setOnClickListener(new ConfirmPINListener()); - } + @Override + protected void setTempTokens(String tokenPublic, String tokenSecret) { + Settings.setTwitterTempTokens(tokenPublic, tokenSecret); } - private void requestToken() { - - int status = 0; - try { - final Parameters params = new Parameters(); - final String method = "GET"; - final String pathRequest = "/oauth/request_token"; - final String host = "api.twitter.com"; - OAuth.signOAuth(host, pathRequest, method, true, params, null, null); - final String line = Network.getResponseData(Network.getRequest("https://" + host + pathRequest, params)); - - - if (StringUtils.isNotBlank(line)) { - final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); - if (paramsMatcher1.find()) { - OAtoken = paramsMatcher1.group(1); - } - final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); - if (paramsMatcher2.find()) { - OAtokenSecret = paramsMatcher2.group(1); - } - - if (StringUtils.isNotBlank(OAtoken) && StringUtils.isNotBlank(OAtokenSecret)) { - Settings.setTwitterTempTokens(OAtoken, OAtokenSecret); - try { - final Parameters paramsBrowser = new Parameters(); - paramsBrowser.put("oauth_callback", "oob"); - final String pathAuthorize = "/oauth/authorize"; - OAuth.signOAuth(host, pathAuthorize, "GET", true, paramsBrowser, OAtoken, OAtokenSecret); - final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser)); - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + encodedParams))); - status = 1; - } catch (Exception e) { - Log.e("TwitterAuthorizationActivity.requestToken(2)", e); - } - } - } - } catch (Exception e) { - Log.e("TwitterAuthorizationActivity.requestToken(1)", e); - } - - requestTokenHandler.sendEmptyMessage(status); + @Override + protected void setTokens(String tokenPublic, String tokenSecret, boolean enable) { + Settings.setTwitterTokens(tokenPublic, tokenSecret, enable); } - private void changeToken() { - - int status = 0; - - try { - final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString()); - - final String method = "POST"; - final String path = "/oauth/access_token"; - final String host = "api.twitter.com"; - OAuth.signOAuth(host, path, method, true, params, OAtoken, OAtokenSecret); - final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest("https://" + host + path, params))); + @Override + protected String getAuthTitle() { + return res.getString(R.string.auth_twitter); + } - OAtoken = ""; - OAtokenSecret = ""; + @Override + protected String getAuthAgain() { + return res.getString(R.string.auth_again); + } - final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); - if (paramsMatcher1.find()) { - OAtoken = paramsMatcher1.group(1); - } - final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); - if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) { - OAtokenSecret = paramsMatcher2.group(1); - } + @Override + protected String getErrAuthInitialize() { + return res.getString(R.string.err_auth_initialize); + } - if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { - OAtoken = ""; - OAtokenSecret = ""; - Settings.setTwitterTokens(null, null, false); - } else { - Settings.setTwitterTokens(OAtoken, OAtokenSecret, true); - status = 1; - } - } catch (Exception e) { - Log.e("TwitterAuthorizationActivity.changeToken", e); - } + @Override + protected String getAuthStart() { + return res.getString(R.string.auth_start); + } - changeTokensHandler.sendEmptyMessage(status); + @Override + protected String getAuthDialogCompleted() { + return res.getString(R.string.auth_dialog_completed); } - private class StartListener implements View.OnClickListener { + @Override + protected String getErrAuthProcess() { + return res.getString(R.string.err_auth_process); + } - @Override - public void onClick(View arg0) { - if (requestTokenDialog == null) { - requestTokenDialog = new ProgressDialog(TwitterAuthorizationActivity.this); - requestTokenDialog.setCancelable(false); - requestTokenDialog.setMessage(res.getString(R.string.auth_dialog_wait)); - } - requestTokenDialog.show(); - startButton.setEnabled(false); - startButton.setOnTouchListener(null); - startButton.setOnClickListener(null); + @Override + protected String getAuthDialogWait() { + return res.getString(R.string.auth_dialog_wait); + } - Settings.setTwitterTempTokens(null, null); - (new Thread() { + @Override + protected String getAuthDialogPinTitle() { + return res.getString(R.string.auth_dialog_pin_title); + } - @Override - public void run() { - requestToken(); - } - }).start(); - } + @Override + protected String getAuthDialogPinMessage() { + return res.getString(R.string.auth_dialog_pin_message); } - private class ConfirmPINListener implements View.OnClickListener { + @Override + protected String getAboutAuth1() { + return res.getString(R.string.about_auth_1); + } - @Override - public void onClick(View arg0) { - if (StringUtils.isEmpty(((EditText) findViewById(R.id.pin)).getText().toString())) { - helpDialog(res.getString(R.string.auth_dialog_pin_title), res.getString(R.string.auth_dialog_pin_message)); - return; - } + @Override + protected String getAboutAuth2() { + return res.getString(R.string.about_auth_2); + } - if (changeTokensDialog == null) { - changeTokensDialog = new ProgressDialog(TwitterAuthorizationActivity.this); - changeTokensDialog.setCancelable(false); - changeTokensDialog.setMessage(res.getString(R.string.auth_dialog_wait)); - } - changeTokensDialog.show(); - pinEntryButton.setEnabled(false); - pinEntryButton.setOnTouchListener(null); - pinEntryButton.setOnClickListener(null); + @Override + protected String getAuthAuthorize() { + return res.getString(R.string.auth_authorize); + } - (new Thread() { + @Override + protected String getAuthPinHint() { + return res.getString(R.string.auth_pin_hint); + } - @Override - public void run() { - changeToken(); - } - }).start(); - } + @Override + protected String getAuthFinish() { + return res.getString(R.string.auth_finish); } + } diff --git a/main/templates/ocde_okapi.xml b/main/templates/ocde_okapi.xml new file mode 100644 index 0000000..9ca39b3 --- /dev/null +++ b/main/templates/ocde_okapi.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources> + <string name="oc_de_okapi_consumer_key" translatable="false">@ocde.okapi.consumer.key@</string> + <string name="oc_de_okapi_consumer_secret" translatable="false">@ocde.okapi.consumer.secret@</string> +</resources> diff --git a/main/templates/private.properties b/main/templates/private.properties index f29cb7c..13c424b 100644 --- a/main/templates/private.properties +++ b/main/templates/private.properties @@ -16,3 +16,10 @@ maps.api.key.market= #key.alias= #key.store.password= #key.alias.password= + +# These keys allow c:geo to be registered at openaching.de and +# to search and log caches in your name +# You can request your own at http://www.opencaching.de/okapi/signup.html + +ocde.okapi.consumer.key= +ocde.okapi.consumer.secret= |
