diff options
| -rw-r--r-- | main/res/layout/reset_cache_coords_dialog.xml | 35 | ||||
| -rw-r--r-- | main/res/layout/waypoint_new.xml | 85 | ||||
| -rw-r--r-- | main/res/values-cs/strings.xml | 15 | ||||
| -rw-r--r-- | main/res/values/strings.xml | 19 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/CacheDetailActivity.java | 173 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/EditWaypointActivity.java | 93 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgCache.java | 45 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgData.java | 11 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/AbstractConnector.java | 26 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/IConnector.java | 27 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCConnector.java | 23 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCParser.java | 49 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/enumerations/WaypointType.java | 10 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/GPXParser.java | 2 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/network/Network.java | 23 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/ui/Formatter.java | 2 | ||||
| -rw-r--r-- | tests/src/cgeo/geocaching/connector/gc/GCParserTest.java | 19 |
17 files changed, 587 insertions, 70 deletions
diff --git a/main/res/layout/reset_cache_coords_dialog.xml b/main/res/layout/reset_cache_coords_dialog.xml new file mode 100644 index 0000000..2773041 --- /dev/null +++ b/main/res/layout/reset_cache_coords_dialog.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="3dip" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/waypoint_reset_cache_coords_info" />
+
+ <CheckBox
+ android:id="@+id/local"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="@string/waypoint_localy_reset_cache_coords" />
+
+ <CheckBox
+ android:id="@+id/upload"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="false"
+ android:visibility="gone"
+ android:text="@string/waypoint_reset_cache_coords_on_website" />
+
+ <Button
+ android:id="@+id/reset"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="3dip"
+ android:text="@string/waypoint_reset" />
+
+</LinearLayout>
\ No newline at end of file diff --git a/main/res/layout/waypoint_new.xml b/main/res/layout/waypoint_new.xml index dfe79fc..d6d6463 100644 --- a/main/res/layout/waypoint_new.xml +++ b/main/res/layout/waypoint_new.xml @@ -51,45 +51,80 @@ android:hint="@string/waypoint_bearing" android:inputType="numberDecimal" /> - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" > - - <EditText - android:id="@+id/distance" - style="@style/edittext_full" - android:hint="@string/waypoint_distance" - android:inputType="numberDecimal" - android:layout_width="0dip" - android:layout_weight="1" /> - - <Spinner - android:id="@+id/distanceUnit" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:entries="@array/distance_units" /> - </LinearLayout> - - <AutoCompleteTextView + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <EditText + android:id="@+id/distance" + style="@style/edittext_full" + android:layout_width="0dip" + android:layout_weight="1" + android:hint="@string/waypoint_distance" + android:inputType="numberDecimal" /> + + <Spinner + android:id="@+id/distanceUnit" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:entries="@array/distance_units" /> + </LinearLayout> + + <AutoCompleteTextView android:id="@+id/name" style="@style/edittext_full" android:hint="@string/waypoint_name" /> - - <Spinner + + <Spinner android:id="@+id/type" android:layout_width="fill_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" /> <EditText android:id="@+id/note" style="@style/edittext_full" android:layout_height="wrap_content" - android:inputType="textMultiLine|textCapSentences" android:hint="@string/waypoint_note" + android:inputType="textMultiLine|textCapSentences" android:minLines="5" android:singleLine="false" /> + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <CheckBox + android:id="@+id/setAsCacheCoordsCheckBox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="@string/waypoint_set_as_cache_coords" + android:textColor="?text_color" /> + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <CheckBox + android:id="@+id/uploadCoordsToWebsiteCheckBox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="gone" /> + + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="@string/waypoint_modify_on_website" + android:textColor="?text_color" /> + </LinearLayout> + <Button android:id="@+id/add_waypoint" style="@style/button_full" diff --git a/main/res/values-cs/strings.xml b/main/res/values-cs/strings.xml index 40f724d..c89cf82 100644 --- a/main/res/values-cs/strings.xml +++ b/main/res/values-cs/strings.xml @@ -520,6 +520,21 @@ <string name="waypoint_note">Poznámka</string> <string name="waypoint_save">Uložit</string> <string name="waypoint_loading">Načítání bodu trasy…</string> + <string name="waypoint_set_as_cache_coords">Nastavit jako souřadnice keše</string> + <string name="waypoint_reset_cache_coords">Obnovit původní souřadnice keše</string> + <string name="waypoint_reset_cache_coords_on_website">Obnovit původní souřadnice keše na webu</string> + <string name="waypoint_coordinates_has_been_reset_on_website">Souřadnice keše byly obnoveny na webu.</string> + <string name="waypoint_coordinates_being_reset_on_website">Souřadnice keše se obnovují na webu.</string> + <string name="waypoint_reset_cache_coords_info">Možnosti obnovy</string> + <string name="waypoint_reset">Obnova</string> + <string name="waypoint_localy_reset_cache_coords">Obnovit souřadnice keše v zařízení</string> + <string name="waypoint_modify_on_website">Změnit souřadnice keše na webu</string> + <string name="waypoint_coordinates_couldnt_be_modified_on_website">Souřadnice keše nemohou být změněny na webu.</string> + <string name="waypoint_coordinates_upload_error">Při nahrávání souřadnic na web se vyskytla chyba.</string> + <string name="waypoint_coordinates_uploading_to_website">Nahrávám %s na web</string> + <string name="waypoint_coordinates_reseting_on_website">Obnovuji původní souřadnice keše na webu.</string> + <string name="waypoint_coordinates_has_been_modified_on_website">Souřadnice keše na webu byly změněny na %s.</string> + <string name="waypoint_coordinates_has_been_set_as_cache_coordinates">Souřadnice keše byly v zařízení změněny na: %s.</string> <!-- visit --> <string name="visit_tweet">informovat o nálezu na twitteru</string> diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 5bec200..94c2139 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -53,6 +53,7 @@ <string name="wp_pkg">Parking Area</string> <string name="wp_trailhead">Trailhead</string> <string name="wp_waypoint">Reference Point</string> + <string name="wp_original">Original Coordinates</string> <!-- logs --> <string name="log_found">Found it</string> @@ -551,6 +552,8 @@ <string name="cache_menu_visit_offline">Log Visit offline</string> <string name="cache_menu_spoilers">Spoiler images</string> <string name="cache_menu_around">Caches around</string> + <string name="cache_menu_set_as_cache_coords">Set as cache coords</string> + <string name="cache_menu_upload_wpt_to_gc_com">Set as cache coords and upload waypoint to Geocaching.com</string> <string name="cache_menu_event">Add to calendar</string> <string name="cache_menu_details">Details</string> <string name="cache_menu_share">Share cache</string> @@ -660,6 +663,22 @@ <string name="waypoint_note">Note</string> <string name="waypoint_save">Save</string> <string name="waypoint_loading">Loading waypoint…</string> + <string name="waypoint_unknown_coordinates">Coordinates unknown</string> + <string name="waypoint_set_as_cache_coords">Set as cache coordinates</string> + <string name="waypoint_reset_cache_coords">Reset cache coordinates</string> + <string name="waypoint_reset_cache_coords_on_website">Reset cache coordinates on website</string> + <string name="waypoint_coordinates_has_been_reset_on_website">Cache coordinates has been reset on website.</string> + <string name="waypoint_coordinates_being_reset_on_website">Cache coordinates being reset on website.</string> + <string name="waypoint_reset_cache_coords_info">Reset possibilities</string> + <string name="waypoint_reset">Reset</string> + <string name="waypoint_localy_reset_cache_coords">Reset coordinates locally</string> + <string name="waypoint_modify_on_website">Modify coordinates on website</string> + <string name="waypoint_coordinates_couldnt_be_modified_on_website">Cache coordinates couldn\'t be set on website.</string> + <string name="waypoint_coordinates_upload_error">Error occurred during uploading coordinates to website.</string> + <string name="waypoint_coordinates_uploading_to_website">Uploading %s to website.</string> + <string name="waypoint_coordinates_reseting_on_website">Reseting to original coordinates on website.</string> + <string name="waypoint_coordinates_has_been_modified_on_website">Cache coordinates has been modified on website to: %s.</string> + <string name="waypoint_coordinates_has_been_set_as_cache_coordinates">Cache coordinates has been localy modified to: %s.</string> <string name="waypoint_done">Done</string> <string name="waypoint_duplicate">Duplicate</string> <string name="waypoint_copy_of">Copy of</string> diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 9759684..b7ae292 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -13,6 +13,7 @@ import cgeo.geocaching.enumerations.CacheAttribute; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.Units; import cgeo.geocaching.network.HtmlImage; @@ -44,7 +45,9 @@ import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import android.R.color; +import android.app.Activity; import android.app.AlertDialog; +import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -85,6 +88,9 @@ import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -128,6 +134,7 @@ public class CacheDetailActivity extends AbstractActivity { private static final int CONTEXT_MENU_WAYPOINT_NAVIGATE = 1238; private static final int CONTEXT_MENU_WAYPOINT_CACHES_AROUND = 1239; private static final int CONTEXT_MENU_WAYPOINT_DEFAULT_NAVIGATION = 1240; + private static final int CONTEXT_MENU_WAYPOINT_RESET_ORIGINAL_CACHE_COORDINATES = 1241; private static final Pattern DARK_COLOR_PATTERN = Pattern.compile(Pattern.quote("color=\"#") + "(0[0-9]){3}" + "\""); @@ -429,10 +436,14 @@ public class CacheDetailActivity extends AbstractActivity { final cgWaypoint waypoint = sortedWaypoints.get(i); final int index = cache.getWaypoints().indexOf(waypoint); menu.setHeaderTitle(res.getString(R.string.waypoint)); - menu.add(CONTEXT_MENU_WAYPOINT_EDIT, index, 0, R.string.waypoint_edit); - menu.add(CONTEXT_MENU_WAYPOINT_DUPLICATE, index, 0, R.string.waypoint_duplicate); + if (waypoint.getWaypointType().equals(WaypointType.ORIGINAL)) { + menu.add(CONTEXT_MENU_WAYPOINT_RESET_ORIGINAL_CACHE_COORDINATES, index, 0, R.string.waypoint_reset_cache_coords); + } else { + menu.add(CONTEXT_MENU_WAYPOINT_EDIT, index, 0, R.string.waypoint_edit); + menu.add(CONTEXT_MENU_WAYPOINT_DUPLICATE, index, 0, R.string.waypoint_duplicate); + } contextMenuWPIndex = index; - if (waypoint.isUserDefined()) { + if (waypoint.isUserDefined() && !waypoint.getWaypointType().equals(WaypointType.ORIGINAL)) { menu.add(CONTEXT_MENU_WAYPOINT_DELETE, index, 0, R.string.waypoint_delete); } if (waypoint.getCoords() != null) { @@ -543,13 +554,16 @@ public class CacheDetailActivity extends AbstractActivity { cgeocaches.startActivityCoordinates(this, waypointAround.getCoords()); } break; - default: { + + case CONTEXT_MENU_WAYPOINT_RESET_ORIGINAL_CACHE_COORDINATES: + new ResetCacheCoordinatesDialog(cache, cache.getWaypoint(index), this).show(); + break; + + default: if (imagesList != null && imagesList.onContextItemSelected(item)) { return true; } - return onOptionsItemSelected(item); - } } return false; } @@ -585,7 +599,7 @@ public class CacheDetailActivity extends AbstractActivity { public boolean onOptionsItemSelected(MenuItem item) { final int menuItem = item.getItemId(); - switch(menuItem) { + switch (menuItem) { case 0: // no menu selected, but a new sub menu shown return false; @@ -1411,22 +1425,22 @@ public class CacheDetailActivity extends AbstractActivity { if (cache.getCoords() != null) { TextView valueView = details.add(R.string.cache_coordinates, cache.getCoords().toString()); valueView.setOnClickListener(new View.OnClickListener() { - private int position = 0; - private GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] { - GeopointFormatter.Format.LAT_LON_DECMINUTE, - GeopointFormatter.Format.LAT_LON_DECSECOND, - GeopointFormatter.Format.LAT_LON_DECDEGREE - }; - - // rotate coordinate formats on click - @Override - public void onClick(View view) { - position = (position + 1) % availableFormats.length; + private int position = 0; + private GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] { + GeopointFormatter.Format.LAT_LON_DECMINUTE, + GeopointFormatter.Format.LAT_LON_DECSECOND, + GeopointFormatter.Format.LAT_LON_DECDEGREE + }; + + // rotate coordinate formats on click + @Override + public void onClick(View view) { + position = (position + 1) % availableFormats.length; - final TextView valueView = (TextView) view.findViewById(R.id.value); - valueView.setText(cache.getCoords().format(availableFormats[position])); - } - }); + final TextView valueView = (TextView) view.findViewById(R.id.value); + valueView.setText(cache.getCoords().format(availableFormats[position])); + } + }); registerForContextMenu(valueView); } @@ -2223,7 +2237,7 @@ public class CacheDetailActivity extends AbstractActivity { holder.count.setVisibility(View.VISIBLE); if (log.found == -1) { holder.count.setVisibility(View.GONE); - } else { + } else { holder.count.setText(res.getQuantityString(R.plurals.cache_counts, log.found, log.found)); } @@ -2502,4 +2516,117 @@ public class CacheDetailActivity extends AbstractActivity { cacheIntent.putExtra("name", cacheName); context.startActivity(cacheIntent); } + + /** + * A dialog to allow the user to select reseting coordinates local/remote/both. + */ + private class ResetCacheCoordinatesDialog extends AlertDialog implements OnCheckedChangeListener { + + final CheckBox uploadOption; + final CheckBox resetLocalyOption; + + public ResetCacheCoordinatesDialog(final cgCache cache, final cgWaypoint wpt, final Activity activity) { + super(activity); + + View layout = activity.getLayoutInflater().inflate(R.layout.reset_cache_coords_dialog, null); + setView(layout); + + uploadOption = (CheckBox) layout.findViewById(R.id.upload); + resetLocalyOption = (CheckBox) layout.findViewById(R.id.local); + + if (ConnectorFactory.getConnector(cache).supportsOwnCoordinates()) { + uploadOption.setChecked(true); + uploadOption.setVisibility(View.VISIBLE); + } + + uploadOption.setOnCheckedChangeListener(this); + resetLocalyOption.setOnCheckedChangeListener(this); + + layout.findViewById(R.id.reset).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + final ProgressDialog p = ProgressDialog.show(CacheDetailActivity.this, res.getString(R.string.cache), res.getString(R.string.waypoint_reset), true); + Handler h = new Handler() { + @Override + public void handleMessage(Message msg) { + p.dismiss(); + notifyDataSetChanged(); + } + }; + new ResetCoordsThread(cache, h, wpt, resetLocalyOption.isChecked(), uploadOption.isChecked(), p).start(); + } + }); + } + + @Override + public void onCheckedChanged(CompoundButton arg0, boolean arg1) { + findViewById(R.id.reset).setEnabled( + (uploadOption.isChecked() || resetLocalyOption.isChecked())); + } + } + + private class ResetCoordsThread extends Thread { + + private final cgCache cache; + private final Handler handler; + private final boolean local; + private final boolean remote; + private final cgWaypoint wpt; + private ProgressDialog progress; + + public ResetCoordsThread(cgCache cache, Handler handler, final cgWaypoint wpt, boolean local, boolean remote, final ProgressDialog progress) { + this.cache = cache; + this.handler = handler; + this.local = local; + this.remote = remote; + this.wpt = wpt; + this.progress = progress; + } + + @Override + public void run() { + + if (local) { + runOnUiThread(new Runnable() { + @Override + public void run() { + progress.setMessage(res.getString(R.string.waypoint_reset_cache_coords)); + } + }); + cache.setCoords(wpt.getCoords()); + cache.setUserModifiedCoords(false); + cache.deleteWaypointForce(wpt); + cgData.saveChangedCache(cache); + } + + IConnector con = ConnectorFactory.getConnector(cache); + if (remote && con.supportsOwnCoordinates()) { + runOnUiThread(new Runnable() { + @Override + public void run() { + progress.setMessage(res.getString(R.string.waypoint_coordinates_being_reset_on_website)); + } + }); + + final boolean result = con.deleteModifiedCoordinates(cache); + + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (result) { + showToast(getString(R.string.waypoint_coordinates_has_been_reset_on_website)); + } else { + showToast(getString(R.string.waypoint_coordinates_upload_error)); + } + handler.sendMessage(Message.obtain()); + notifyDataSetChanged(); + } + + }); + + } + } + } } diff --git a/main/src/cgeo/geocaching/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java index 819cb03..5646794 100644 --- a/main/src/cgeo/geocaching/EditWaypointActivity.java +++ b/main/src/cgeo/geocaching/EditWaypointActivity.java @@ -2,6 +2,8 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.connector.ConnectorFactory; +import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.WaypointType; @@ -27,6 +29,7 @@ import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Button; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.Spinner; @@ -77,6 +80,8 @@ public class EditWaypointActivity extends AbstractActivity { else { ((EditText) findViewById(R.id.note)).setText(StringUtils.trimToEmpty(waypoint.getNote())); } + + setUploadingCheckBoxVisibleByConnector(ConnectorFactory.getConnector(geocode)); } if (own) { @@ -133,7 +138,7 @@ public class EditWaypointActivity extends AbstractActivity { addWaypoint.setOnClickListener(new coordsListener()); List<String> wayPointNames = new ArrayList<String>(); - for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN) { + for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) { wayPointNames.add(wpt.getL10n()); } AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.name); @@ -152,11 +157,23 @@ public class EditWaypointActivity extends AbstractActivity { initializeWaypointTypeSelector(); } + IConnector con; + if (geocode != null) { + con = ConnectorFactory.getConnector(geocode); + setUploadingCheckBoxVisibleByConnector(con); + } + initializeDistanceUnitSelector(); disableSuggestions((EditText) findViewById(R.id.distance)); } + private void setUploadingCheckBoxVisibleByConnector(IConnector con) { + if (con.supportsOwnCoordinates()) { + findViewById(R.id.uploadCoordsToWebsiteCheckBox).setVisibility(View.VISIBLE); + } + } + @Override public void onResume() { super.onResume(); @@ -193,7 +210,7 @@ public class EditWaypointActivity extends AbstractActivity { Spinner waypointTypeSelector = (Spinner) findViewById(R.id.type); - wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN); + wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL); ArrayAdapter<WaypointType> wpAdapter = new ArrayAdapter<WaypointType>(this, android.R.layout.simple_spinner_item, wpTypes.toArray(new WaypointType[wpTypes.size()])); wpAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); waypointTypeSelector.setAdapter(wpAdapter); @@ -335,12 +352,14 @@ public class EditWaypointActivity extends AbstractActivity { @Override public void onClick(View arg0) { + // TODO Show progress across whole function, it is performing very long time on slower devices final String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString(); // combine distance from EditText and distanceUnit saved from Spinner final String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString() + distanceUnit; final String latText = ((Button) findViewById(R.id.buttonLatitude)).getText().toString(); final String lonText = ((Button) findViewById(R.id.buttonLongitude)).getText().toString(); - + final CheckBox setAsCacheCoordsCheckBox = (CheckBox) findViewById(R.id.setAsCacheCoordsCheckBox); + final CheckBox uploadCoordsToWebsiteCheckBox = (CheckBox) findViewById(R.id.uploadCoordsToWebsiteCheckBox); if (StringUtils.isBlank(bearingText) && StringUtils.isBlank(distanceText) && StringUtils.isBlank(latText) && StringUtils.isBlank(lonText)) { helpDialog(res.getString(R.string.err_point_no_position_given_title), res.getString(R.string.err_point_no_position_given)); @@ -408,13 +427,79 @@ public class EditWaypointActivity extends AbstractActivity { if (Settings.isStoreOfflineWpMaps()) { StaticMapsProvider.storeWaypointStaticMap(cache, waypoint, false); } - finish(); + if (setAsCacheCoordsCheckBox.isChecked()) { + if (!cache.hasUserModifiedCoords()) { + final cgWaypoint origWaypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.ORIGINAL, false); + origWaypoint.setCoords(cache.getCoords()); + cache.addOrChangeWaypoint(origWaypoint, false); + cache.setUserModifiedCoords(true); + } + cache.setCoords(waypoint.getCoords()); + cgData.saveChangedCache(cache); + } + if (uploadCoordsToWebsiteCheckBox.isChecked() && waypoint != null && waypoint.getCoords() != null) { + if (cache.supportsOwnCoordinates()) { + final ProgressDialog progress = ProgressDialog.show(EditWaypointActivity.this, getString(R.string.cache), getString(R.string.waypoint_coordinates_uploading_to_website, waypoint.getCoords()), true); + Handler finishHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + progress.dismiss(); + finish(); + } + }; + new UploadModifiedCoordsThread(cache, waypoint.getCoords(), progress, finishHandler).start(); + } else { + showToast(getString(R.string.waypoint_coordinates_couldnt_be_modified_on_website)); + } + } else { + finish(); + } } else { showToast(res.getString(R.string.err_waypoint_add_failed)); } } } + private class UploadModifiedCoordsThread extends Thread { + + private final Geopoint waypoint_uploaded; + private final ProgressDialog progress; + private final cgCache cache; + private final Handler handler; + + public UploadModifiedCoordsThread(cgCache cache, Geopoint wpt, ProgressDialog progress, Handler finishHandler) { + this.cache = cache; + this.waypoint_uploaded = wpt; + this.progress = progress; + this.handler = finishHandler; + } + + @Override + public void run() { + boolean result = false; + IConnector con = ConnectorFactory.getConnector(cache); + if (con.supportsOwnCoordinates()) { + result = con.uploadModifiedCoordinates(cache, waypoint_uploaded); + } + final boolean res = result; + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (res) { + showToast(getString(R.string.waypoint_coordinates_has_been_modified_on_website, waypoint_uploaded.getCoords().toString())); + } else { + showToast(getString(R.string.waypoint_coordinates_upload_error)); + } + if (progress != null) { + progress.dismiss(); + } + handler.sendMessage(Message.obtain()); + } + }); + } + } + @Override public void goManual(View view) { if (id >= 0) { diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index 6978bfa..685cbe0 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -313,9 +313,18 @@ public class cgCache implements ICache, IWaypoint { if (logCounts.size() == 0) { logCounts = other.logCounts; } - if (!userModifiedCoords) { - userModifiedCoords = other.userModifiedCoords; + + // if cache has ORIGINAL type waypoint ... it is considered that it has modified coordinates, otherwise not + userModifiedCoords = false; + if (waypoints != null) { + for (cgWaypoint wpt : waypoints) { + if (wpt.getWaypointType() == WaypointType.ORIGINAL) { + userModifiedCoords = true; + break; + } + } } + if (!reliableLatLon) { reliableLatLon = other.reliableLatLon; } @@ -335,7 +344,8 @@ public class cgCache implements ICache, IWaypoint { /** * Compare two caches quickly. For map and list fields only the references are compared ! * - * @param other the other cache to compare this one to + * @param other + * the other cache to compare this one to * @return true if both caches have the same content */ private boolean isEqualTo(final cgCache other) { @@ -531,6 +541,10 @@ public class cgCache implements ICache, IWaypoint { return getConnector().supportsLogging(); } + public boolean supportsOwnCoordinates() { + return getConnector().supportsOwnCoordinates(); + } + @Override public float getDifficulty() { return difficulty; @@ -693,7 +707,6 @@ public class cgCache implements ICache, IWaypoint { this.favorite = favourite; } - @Override public boolean isWatchlist() { return onWatchlist; @@ -1184,12 +1197,12 @@ public class cgCache implements ICache, IWaypoint { } public void setUserModifiedCoords(boolean coordsChanged) { - this.userModifiedCoords = coordsChanged; + userModifiedCoords = coordsChanged; } /** * Duplicate a waypoint. - * + * * @param original * the waypoint to duplicate * @return <code>true</code> if the waypoint was duplicated, <code>false</code> otherwise (invalid index) @@ -1235,6 +1248,20 @@ public class cgCache implements ICache, IWaypoint { } /** + * deletes any waypoint + * + * @param waypoint + */ + + public void deleteWaypointForce(cgWaypoint waypoint) { + final int index = getWaypointIndex(waypoint); + waypoints.remove(index); + cgData.deleteWaypoint(waypoint.getId()); + cgData.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); + resetFinalDefined(); + } + + /** * Find index of given <code>waypoint</code> in cache's <code>waypoints</code> list * * @param waypoint @@ -1254,7 +1281,8 @@ public class cgCache implements ICache, IWaypoint { /** * Retrieve a given waypoint. * - * @param index the index of the waypoint + * @param index + * the index of the waypoint * @return waypoint or <code>null</code> if index is out of range */ public cgWaypoint getWaypoint(final int index) { @@ -1264,7 +1292,8 @@ public class cgCache implements ICache, IWaypoint { /** * Lookup a waypoint by its id. * - * @param id the id of the waypoint to look for + * @param id + * the id of the waypoint to look for * @return waypoint or <code>null</code> */ public cgWaypoint getWaypointById(final int id) { diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java index c163c57..8d767e4 100644 --- a/main/src/cgeo/geocaching/cgData.java +++ b/main/src/cgeo/geocaching/cgData.java @@ -77,7 +77,7 @@ public class cgData { private static int[] cacheColumnIndex; private static CacheCache cacheCache = new CacheCache(); private static SQLiteDatabase database = null; - private static final int dbVersion = 64; + private static final int dbVersion = 65; public static final int customListIdOffset = 10; private static final String dbName = "data"; private static final String dbTableCaches = "cg_caches"; @@ -646,6 +646,15 @@ public class cgData { Log.e("Failed to upgrade to ver. 64", e); } } + + if (oldVersion < 65) { + try { + // Set all waypoints where name is Original coordinates to type ORIGINAL + db.execSQL("update " + dbTableWaypoints + " set type='original', own=0 where name='Original Coordinates'"); + } catch (Exception e) { + Log.e("Failed to upgrade to ver. 65:", e); + } + } } db.setTransactionSuccessful(); diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java index 112d6cf..d2e8a22 100644 --- a/main/src/cgeo/geocaching/connector/AbstractConnector.java +++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java @@ -2,6 +2,7 @@ package cgeo.geocaching.connector; import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Viewport; import org.apache.commons.lang3.StringUtils; @@ -19,6 +20,31 @@ public abstract class AbstractConnector implements IConnector { } @Override + public boolean supportsOwnCoordinates() { + return false; + } + + /** + * Uploading modified coordinates to website + * + * @param cache + * @param wpt + * @return success + */ + @Override + public boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt) { + throw new UnsupportedOperationException(); + } + + /** + * {@link IConnector} + */ + @Override + public boolean deleteModifiedCoordinates(cgCache cache) { + throw new UnsupportedOperationException(); + } + + @Override public boolean supportsFavoritePoints() { return false; } diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java index d6ac2ff..69cc7d1 100644 --- a/main/src/cgeo/geocaching/connector/IConnector.java +++ b/main/src/cgeo/geocaching/connector/IConnector.java @@ -2,6 +2,7 @@ package cgeo.geocaching.connector; import cgeo.geocaching.SearchResult; import cgeo.geocaching.cgCache; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Viewport; public interface IConnector { @@ -106,10 +107,34 @@ public interface IConnector { /** * extract a geocode from the given URL, if this connector can handle that URL somehow - * + * * @param url * @return */ public String getGeocodeFromUrl(final String url); + /** + * enable/disable uploading modified coordinates to website + * + * @return true, when uploading is possible + */ + public boolean supportsOwnCoordinates(); + + /** + * Uploading modified coordinates to website + * + * @param cache + * @param wpt + * @return success + */ + public boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt); + + /** + * Reseting of modified coordinates on website to details + * + * @param cache + * @return success + */ + public boolean deleteModifiedCoordinates(cgCache cache); + } diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index 8a8c686..d8d6a06 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -50,6 +50,11 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, } @Override + public boolean supportsOwnCoordinates() { + return true; + } + + @Override public boolean supportsWatchList() { return true; } @@ -158,6 +163,24 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, } @Override + public boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt) { + final boolean uploaded = GCParser.uploadModifiedCoordinates(cache, wpt); + if (uploaded) { + cgData.saveChangedCache(cache); + } + return uploaded; + } + + @Override + public boolean deleteModifiedCoordinates(cgCache cache) { + final boolean deleted = GCParser.deleteModifiedCoordinates(cache); + if (deleted) { + cgData.saveChangedCache(cache); + } + return deleted; + } + + @Override public SearchResult searchByCenter(Geopoint center) { // TODO make search by coordinate use this method. currently it is just a marker that this connector supports search by center return null; diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index f2a86d9..68f4149 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCParser.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -373,6 +373,8 @@ public abstract class GCParser { cache.setOwn(StringUtils.equalsIgnoreCase(cache.getOwnerUserId(), Settings.getUsername())); + cache.setUserModifiedCoords(false); + String tableInside = page; int pos = tableInside.indexOf(GCConstants.STRING_CACHEDETAILS); @@ -606,7 +608,7 @@ public abstract class GCParser { final String originalCoords = BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON_ORIG, false, null); if (null != originalCoords) { - final cgWaypoint waypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.WAYPOINT, false); + final cgWaypoint waypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.ORIGINAL, false); waypoint.setCoords(new Geopoint(originalCoords)); cache.addOrChangeWaypoint(waypoint, false); cache.setUserModifiedCoords(true); @@ -1659,4 +1661,49 @@ public abstract class GCParser { } } + public static boolean uploadModifiedCoordinates(cgCache cache, Geopoint wpt) { + return editModifiedCoordinates(cache, wpt); + } + + public static boolean deleteModifiedCoordinates(cgCache cache) { + return editModifiedCoordinates(cache, null); + } + + public static boolean editModifiedCoordinates(cgCache cache, Geopoint wpt) { + final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0"); + final String userToken = BaseUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, ""); + if (StringUtils.isEmpty(userToken)) { + return false; + } + final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/"; + + JSONObject jo; + try { + if (wpt != null) { + jo = new JSONObject().put("dto", (new JSONObject().put("ut", userToken) + .put("data", new JSONObject() + .put("lat", wpt.getLatitudeE6() / 1E6) + .put("lng", wpt.getLongitudeE6() / 1E6)))); + } else { + jo = new JSONObject().put("dto", (new JSONObject().put("ut", userToken))); + } + + final String uriSuffix = wpt != null ? "SetUserCoordinate" : "ResetUserCoordinate"; + + HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo); + Log.i("Sending to " + uriPrefix + uriSuffix + " :" + jo.toString()); + + if (response != null && response.getStatusLine().getStatusCode() == 200) { + Log.i("GCParser.editModifiedCoordinates - edited on GC.com"); + return true; + } + + } catch (JSONException e) { + Log.e("Unknown exception with json wrap code"); + e.printStackTrace(); + } + Log.e("GCParser.deleteModifiedCoordinates - cannot delete modified coords"); + return false; + } + } diff --git a/main/src/cgeo/geocaching/enumerations/WaypointType.java b/main/src/cgeo/geocaching/enumerations/WaypointType.java index 52eb318..1e4fc1e 100644 --- a/main/src/cgeo/geocaching/enumerations/WaypointType.java +++ b/main/src/cgeo/geocaching/enumerations/WaypointType.java @@ -19,7 +19,8 @@ public enum WaypointType { PUZZLE("puzzle", R.string.wp_puzzle, R.drawable.waypoint_puzzle), STAGE("stage", R.string.wp_stage, R.drawable.waypoint_stage), TRAILHEAD("trailhead", R.string.wp_trailhead, R.drawable.waypoint_trailhead), - WAYPOINT("waypoint", R.string.wp_waypoint, R.drawable.waypoint_waypoint); + WAYPOINT("waypoint", R.string.wp_waypoint, R.drawable.waypoint_waypoint), + ORIGINAL("original", R.string.wp_original, R.drawable.waypoint_waypoint); public final String id; public final int stringId; @@ -36,13 +37,13 @@ public enum WaypointType { * non public so that <code>null</code> handling can be handled centrally in the enum type itself */ private static final Map<String, WaypointType> FIND_BY_ID; - public static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN = new HashSet<WaypointType>(); + public static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL = new HashSet<WaypointType>(); static { final HashMap<String, WaypointType> mapping = new HashMap<String, WaypointType>(); for (WaypointType wt : values()) { mapping.put(wt.id, wt); - if (wt != WaypointType.OWN) { - ALL_TYPES_EXCEPT_OWN.add(wt); + if (wt != WaypointType.OWN && wt != WaypointType.ORIGINAL) { + ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL.add(wt); } } FIND_BY_ID = Collections.unmodifiableMap(mapping); @@ -67,7 +68,6 @@ public enum WaypointType { return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - @Override public final String toString() { return getL10n(); diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java index 60ebd69..72ff8e5 100644 --- a/main/src/cgeo/geocaching/files/GPXParser.java +++ b/main/src/cgeo/geocaching/files/GPXParser.java @@ -816,7 +816,7 @@ public abstract class GPXParser extends FileParser { return WaypointType.FINAL; } // this is not fully correct, but lets also look for localized waypoint types - for (WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN) { + for (WaypointType waypointType : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) { final String localized = waypointType.getL10n(); if (StringUtils.isNotEmpty(localized)) { if (localized.equalsIgnoreCase(sym)) { diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java index ed921b2..9abc751 100644 --- a/main/src/cgeo/geocaching/network/Network.java +++ b/main/src/cgeo/geocaching/network/Network.java @@ -22,6 +22,7 @@ import ch.boye.httpclientandroidlib.client.methods.HttpGet; import ch.boye.httpclientandroidlib.client.methods.HttpPost; import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase; import ch.boye.httpclientandroidlib.client.params.ClientPNames; +import ch.boye.httpclientandroidlib.entity.StringEntity; import ch.boye.httpclientandroidlib.entity.mime.MultipartEntity; import ch.boye.httpclientandroidlib.entity.mime.content.FileBody; import ch.boye.httpclientandroidlib.entity.mime.content.StringBody; @@ -156,6 +157,28 @@ public abstract class Network { } /** + * POST HTTP request with Json POST DATA + * + * @param uri the URI to request + * @param json the json object to add to the POST request + * @return the HTTP response, or null in case of an encoding error params + */ + public static HttpResponse postJsonRequest(final String uri, final JSONObject json) { + HttpPost request; + request = new HttpPost(uri); + request.addHeader("Content-Type", "application/json; charset=utf-8"); + if (json != null) { + try { + request.setEntity(new StringEntity(json.toString())); + } catch (UnsupportedEncodingException e) { + Log.e("postJsonRequest:JSON Entity: UnsupportedEncodingException"); + return null; + } + } + return doRepeatedRequests(request); + } + + /** * Multipart POST HTTP request * * @param uri the URI to request diff --git a/main/src/cgeo/geocaching/ui/Formatter.java b/main/src/cgeo/geocaching/ui/Formatter.java index 53a7276..e006d57 100644 --- a/main/src/cgeo/geocaching/ui/Formatter.java +++ b/main/src/cgeo/geocaching/ui/Formatter.java @@ -153,7 +153,7 @@ public abstract class Formatter { public static String formatWaypointInfo(cgWaypoint waypoint) { final List<String> infos = new ArrayList<String>(3); - if (WaypointType.ALL_TYPES_EXCEPT_OWN.contains(waypoint.getWaypointType())) { + if (WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL.contains(waypoint.getWaypointType())) { infos.add(waypoint.getWaypointType().getL10n()); } if (cgWaypoint.PREFIX_OWN.equalsIgnoreCase(waypoint.getPrefix())) { diff --git a/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java b/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java index c8cb8fb..03f3eee 100644 --- a/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java +++ b/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java @@ -121,6 +121,25 @@ public class GCParserTest extends AbstractResourceInstrumentationTestCase { "Station3: N51 21.444 / E07 02.600\r\nStation4: N51 21.789 / E07 02.800\r\nStation5: N51 21.667 / E07 02.800\r\nStation6: N51 21.444 / E07 02.706\r\nStation7: N51 21.321 / E07 02.700\r\nStation8: N51 21.123 / E07 02.477\r\nStation9: N51 21.734 / E07 02.500\r\nStation10: N51 21.733 / E07 02.378\r\nFinal: N51 21.544 / E07 02.566"); } + @MediumTest + public static void testEditModifiedCoordinates() { + cgCache cache = new cgCache(); + cache.setGeocode("GC2ZN4G"); + // upload coordinates + GCParser.editModifiedCoordinates(cache, new Geopoint("N51 21.544", "E07 02.566")); + cache.drop(null); + String page = GCParser.requestHtmlPage(cache.getGeocode(), null, "n", "0"); + cgCache cache2 = GCParser.parseCacheFromText(page, null).getFirstCacheFromResult(LoadFlags.LOAD_CACHE_ONLY); + assertTrue(cache2.hasUserModifiedCoords()); + assertEquals(new Geopoint("N51 21.544", "E07 02.566"), cache2.getCoords()); + // delete coordinates + GCParser.deleteModifiedCoordinates(cache2); + cache2.drop(null); + String page2 = GCParser.requestHtmlPage(cache.getGeocode(), null, "n", "0"); + cgCache cache3 = GCParser.parseCacheFromText(page2, null).getFirstCacheFromResult(LoadFlags.LOAD_CACHE_ONLY); + assertFalse(cache3.hasUserModifiedCoords()); + } + private static void assertWaypointsFromNote(final cgCache cache, Geopoint[] expected, String note) { cache.setPersonalNote(note); cache.setWaypoints(new ArrayList<cgWaypoint>(), false); |
