diff options
| -rw-r--r-- | main/res/layout/cacheview_details.xml | 45 | ||||
| -rw-r--r-- | main/res/values-de/strings.xml | 5 | ||||
| -rw-r--r-- | main/res/values/strings.xml | 8 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/CacheDetailActivity.java | 55 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgCache.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/AbstractConnector.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/IConnector.java | 7 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCConnector.java | 32 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCConstants.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCParser.java | 104 |
10 files changed, 239 insertions, 30 deletions
diff --git a/main/res/layout/cacheview_details.xml b/main/res/layout/cacheview_details.xml index 4baf5c2..2598fdd 100644 --- a/main/res/layout/cacheview_details.xml +++ b/main/res/layout/cacheview_details.xml @@ -135,7 +135,52 @@ android:visibility="gone" />
</RelativeLayout>
</LinearLayout>
+
+ <!-- Favorite points box -->
+ <LinearLayout
+ android:id="@+id/favpoint_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <View
+ style="@style/separator_horizontal"
+ android:layout_marginBottom="9dp"
+ android:layout_marginTop="9dp" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/favpoint_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="130dip"
+ android:paddingRight="3dip"
+ android:textColor="?text_color"
+ android:textSize="14dip" />
+
+ <Button
+ android:id="@+id/add_to_favpoint"
+ style="@style/button_small"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_favpoint_add"
+ android:visibility="gone" />
+
+ <Button
+ android:id="@+id/remove_from_favpoint"
+ style="@style/button_small"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_favpoint_remove"
+ android:visibility="gone" />
+ </RelativeLayout>
+ </LinearLayout>
+
<!-- License Box -->
<LinearLayout
diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml index 1b5582c..6270083 100644 --- a/main/res/values-de/strings.xml +++ b/main/res/values-de/strings.xml @@ -488,6 +488,11 @@ <string name="cache_watchlist_not_on">Dieser Cache ist nicht auf deiner Watchlist.</string> <string name="cache_watchlist_add">Hinzufügen</string> <string name="cache_watchlist_remove">Entfernen</string> + <string name="cache_favpoint_on">Dieser Cacher ist einer deiner Favoriten.</string> + <string name="cache_favpoint_not_on">Dieser Cacher ist keiner deiner Favoriten.</string> + <string name="cache_favpoint_add">Hinzufügen zu Favoriten</string> + <string name="cache_favpoint_remove">Entfernen aus Favoriten</string> + <string name="cache_waypoints">Wegpunkte</string> <plurals name="waypoints"> <item quantity="one">1 Wegpunkt</item> diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 0b11c71..f9bcace 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -501,6 +501,11 @@ <string name="cache_watchlist_not_on">This cache is not on your watchlist.</string> <string name="cache_watchlist_add">Add to Watchlist</string> <string name="cache_watchlist_remove">Remove from Watchlist</string> + <string name="cache_favpoint_on">This cache is one of your favorites.</string> + <string name="cache_favpoint_not_on">This cache is not one of your favorites.</string> + <string name="cache_favpoint_add">Add to Favorites</string> + <string name="cache_favpoint_remove">Remove from Favorites</string> + <string name="cache_waypoints">Waypoints</string> <plurals name="waypoints"> <item quantity="one">1 Waypoint</item> @@ -983,7 +988,7 @@ · 0xErnie (localization DE)\n · <a href="mailto:bazsy@freemail.hu">Balazs Szabo (Bazsy1983)</a> (loc. HU)\n · Bananeweizen (code, loc. DE)\n - · blafoo (code)\n + · blafoo (code, localization DE)\n · Bonemaro (tester)\n · BudBundi (localization DE, tester)\n · campbeb (code)\n @@ -1034,6 +1039,7 @@ <string name="changelog">\n <b>Next release</b>\n\n <b>New Features/Functions:</b>\n + · Add/remove cache to/from Favorites #676 · Export caches as GPX file\n · Filter for D/T in lists\n · Allow close of popup by click on map\n diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 62f946a..a9b6bf7 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -1425,6 +1425,26 @@ public class CacheDetailActivity extends AbstractActivity { buttonWatchlistRemove.setOnClickListener(new RemoveFromWatchlistClickListener()); updateWatchlistBox(); + // favorite points + Button buttonFavPointAdd = (Button) view.findViewById(R.id.add_to_favpoint); + Button buttonFavPointRemove = (Button) view.findViewById(R.id.remove_from_favpoint); + buttonFavPointAdd.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + GCConnector.addToFavorites(cache); + updateFavPointBox(); + } + }); + buttonFavPointRemove.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + GCConnector.removeFromFavorites(cache); + updateFavPointBox(); + } + }); + + updateFavPointBox(); + // data license IConnector connector = ConnectorFactory.getConnector(cache); if (connector != null) { @@ -1689,6 +1709,41 @@ public class CacheDetailActivity extends AbstractActivity { } /** + * shows/hides buttons, sets text in watchlist box + */ + private void updateFavPointBox() { + boolean userIsOwner = StringUtils.equals(cache.getOwnerReal(), Settings.getUsername()); + + LinearLayout layout = (LinearLayout) view.findViewById(R.id.favpoint_box); + boolean supportsFavoritePoints = cache.supportsFavoritePoints(); + layout.setVisibility(supportsFavoritePoints ? View.VISIBLE : View.GONE); + if (!supportsFavoritePoints || userIsOwner || !Settings.isPremiumMember()) { + return; + } + Button buttonAdd = (Button) view.findViewById(R.id.add_to_favpoint); + Button buttonRemove = (Button) view.findViewById(R.id.remove_from_favpoint); + TextView text = (TextView) view.findViewById(R.id.favpoint_text); + + if (cache.isFavorite()) { + buttonAdd.setVisibility(View.GONE); + buttonRemove.setVisibility(View.VISIBLE); + text.setText(R.string.cache_favpoint_on); + } else { + buttonAdd.setVisibility(View.VISIBLE); + buttonRemove.setVisibility(View.GONE); + text.setText(R.string.cache_favpoint_not_on); + } + + // Add/remove to Favorites is only possible if the cache has been found + if (!cache.isFound()) { + buttonAdd.setEnabled(false); + buttonAdd.setVisibility(View.GONE); + buttonRemove.setEnabled(false); + buttonRemove.setVisibility(View.GONE); + } + } + + /** * Handler, called when watchlist add or remove is done */ private class WatchlistHandler extends Handler { diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index 957ddb2..b662a1b 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -489,6 +489,10 @@ public class cgCache implements ICache, IWaypoint { return getConnector().supportsWatchList(); } + public boolean supportsFavoritePoints() { + return getConnector().supportsFavoritePoints(); + } + public boolean supportsLogging() { return getConnector().supportsLogging(); } diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java index f1d00fa..6abc3bc 100644 --- a/main/src/cgeo/geocaching/connector/AbstractConnector.java +++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java @@ -17,6 +17,11 @@ public abstract class AbstractConnector implements IConnector { } @Override + public boolean supportsFavoritePoints() { + return false; + } + + @Override public boolean supportsLogging() { return false; } diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java index 4bc63fc..9111955 100644 --- a/main/src/cgeo/geocaching/connector/IConnector.java +++ b/main/src/cgeo/geocaching/connector/IConnector.java @@ -36,6 +36,13 @@ public interface IConnector { public boolean supportsWatchList(); /** + * enable/disable favorite points controls in cache details + * + * @return + */ + public boolean supportsFavoritePoints(); + + /** * enable/disable logging controls in cache details * * @return diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index e30ce44..6ee0b09 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -11,7 +11,6 @@ import cgeo.geocaching.connector.capability.ISearchByGeocode; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; @@ -77,18 +76,10 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, @Override public SearchResult searchByGeocode(final String geocode, final String guid, final CancellableHandler handler) { - final Parameters params = new Parameters("decrypt", "y"); - if (StringUtils.isNotBlank(geocode)) { - params.put("wp", geocode); - } else if (StringUtils.isNotBlank(guid)) { - params.put("guid", guid); - } - params.put("log", "y"); - params.put("numlogs", String.valueOf(GCConstants.NUMBER_OF_LOGS)); CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage); - final String page = Login.getRequestLogged("http://www.geocaching.com/seek/cache_details.aspx", params); + final String page = GCParser.requestHtmlPage(geocode, guid, "y", String.valueOf(GCConstants.NUMBER_OF_LOGS)); if (StringUtils.isEmpty(page)) { final SearchResult search = new SearchResult(); @@ -150,10 +141,31 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, return removed; } + public static boolean addToFavorites(cgCache cache) { + final boolean added = GCParser.addToFavorites(cache); + if (added) { + cgeoapplication.getInstance().updateCache(cache); + } + return added; + } + + public static boolean removeFromFavorites(cgCache cache) { + final boolean removed = GCParser.removeFromFavorites(cache); + if (removed) { + cgeoapplication.getInstance().updateCache(cache); + } + return removed; + } + @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; } + @Override + public boolean supportsFavoritePoints() { + return true; + } + } diff --git a/main/src/cgeo/geocaching/connector/gc/GCConstants.java b/main/src/cgeo/geocaching/connector/gc/GCConstants.java index ac38972..7edeec5 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConstants.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConstants.java @@ -46,7 +46,7 @@ public final class GCConstants { public final static Pattern PATTERN_TYPE = Pattern.compile("<img src=\"[^\"]*/WptTypes/\\d+\\.gif\" alt=\"([^\"]+?)\" title=\"[^\"]+\" width=\"32\" height=\"32\""); public final static Pattern PATTERN_HIDDEN = Pattern.compile("<span class=\"minorCacheDetails\">\\W*Hidden[\\s:]*([^<]+?)</span>"); public final static Pattern PATTERN_HIDDENEVENT = Pattern.compile("Event\\s*Date\\s*:\\s*([^<]+)</span>", Pattern.DOTALL); - public final static Pattern PATTERN_FAVORITE = Pattern.compile("<img src=\"/images/icons/icon_favDelete.png\" alt=\"Remove from your Favorites\" title=\"Remove from your Favorites\" />"); + public final static Pattern PATTERN_FAVORITE = Pattern.compile("<div id=\"pnlFavoriteCache\">"); // without 'class="hideMe"' inside the tag ! public final static Pattern PATTERN_FAVORITECOUNT = Pattern.compile("<a id=\"uxFavContainerLink\"[^>]+>[^<]*<div[^<]*<span class=\"favorite-value\">\\D*([0-9]+?)</span>"); public final static Pattern PATTERN_COUNTLOGS = Pattern.compile("<span id=\"ctl00_ContentBody_lblFindCounts\"><p(.+?)</p></span>"); public final static Pattern PATTERN_LOGBOOK = Pattern.compile("initalLogs = (\\{.+\\});"); @@ -144,7 +144,7 @@ public final class GCConstants { public final static Pattern PATTERN_OK2 = Pattern.compile("<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE); public final static Pattern PATTERN_VIEWSTATEFIELDCOUNT = Pattern.compile("id=\"__VIEWSTATEFIELDCOUNT\"[^(value)]+value=\"(\\d+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); public final static Pattern PATTERN_VIEWSTATES = Pattern.compile("id=\"__VIEWSTATE(\\d*)\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); - public final static Pattern PATTERN_USERTOKEN2 = Pattern.compile("userToken\\s*=\\s*'([^']+)'"); + public final static Pattern PATTERN_USERTOKEN = Pattern.compile("userToken\\s*=\\s*'([^']+)'"); /** * Patterns for GC and TB codes diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index ed5a5a6..936ce6c 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCParser.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -288,7 +288,7 @@ public abstract class GCParser { LocParser.parseLoc(searchResult, coordinates); } catch (Exception e) { - Log.e("cgBase.parseSearch.CIDs: " + e.toString()); + Log.e("GCParser.parseSearch.CIDs: " + e.toString()); } } @@ -840,7 +840,7 @@ public abstract class GCParser { boolean my = false; if (userName.equalsIgnoreCase(Settings.getLogin().left)) { my = true; - Log.i("cgBase.searchByUsername: Overriding users choice, downloading all caches."); + Log.i("GCParser.searchByUsername: Overriding users choice, downloading all caches."); } return searchByAny(cacheType, my, showCaptcha, params); @@ -1099,7 +1099,7 @@ public abstract class GCParser { /** * Adds the cache to the watchlist of the user. - * + * * @param cache * the cache to add * @return <code>false</code> if an error occurred, <code>true</code> otherwise @@ -1109,23 +1109,23 @@ public abstract class GCParser { String page = Login.postRequestLogged(uri, null); if (StringUtils.isBlank(page)) { - Log.e("cgBase.addToWatchlist: No data from server"); + Log.e("GCParser.addToWatchlist: No data from server"); return false; // error } boolean guidOnPage = cache.isGuidContainedInPage(page); if (guidOnPage) { - Log.i("cgBase.addToWatchlist: cache is on watchlist"); + Log.i("GCParser.addToWatchlist: cache is on watchlist"); cache.setOnWatchlist(true); } else { - Log.e("cgBase.addToWatchlist: cache is not on watchlist"); + Log.e("GCParser.addToWatchlist: cache is not on watchlist"); } return guidOnPage; // on watchlist (=added) / else: error } /** * Removes the cache from the watchlist - * + * * @param cache * the cache to remove * @return <code>false</code> if an error occurred, <code>true</code> otherwise @@ -1135,7 +1135,7 @@ public abstract class GCParser { String page = Login.postRequestLogged(uri, null); if (StringUtils.isBlank(page)) { - Log.e("cgBase.removeFromWatchlist: No data from server"); + Log.e("GCParser.removeFromWatchlist: No data from server"); return false; // error } @@ -1149,14 +1149,84 @@ public abstract class GCParser { page = Network.getResponseData(Network.postRequest(uri, params)); boolean guidOnPage = cache.isGuidContainedInPage(page); if (!guidOnPage) { - Log.i("cgBase.removeFromWatchlist: cache removed from watchlist"); + Log.i("GCParser.removeFromWatchlist: cache removed from watchlist"); cache.setOnWatchlist(false); } else { - Log.e("cgBase.removeFromWatchlist: cache not removed from watchlist"); + Log.e("GCParser.removeFromWatchlist: cache not removed from watchlist"); } return !guidOnPage; // on watchlist (=error) / not on watchlist } + static String requestHtmlPage(final String geocode, final String guid, final String log, final String numlogs) { + final Parameters params = new Parameters("decrypt", "y"); + if (StringUtils.isNotBlank(geocode)) { + params.put("wp", geocode); + } else if (StringUtils.isNotBlank(guid)) { + params.put("guid", guid); + } + params.put("log", log); + params.put("numlogs", numlogs); + + return Login.getRequestLogged("http://www.geocaching.com/seek/cache_details.aspx", params); + } + + /** + * Adds the cache to the favorites of the user. + * + * @param cache + * the cache to add + * @return <code>false</code> if an error occurred, <code>true</code> otherwise + */ + static boolean addToFavorites(final cgCache cache) { + + 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 uri = "http://www.geocaching.com/datastore/favorites.svc/update?u=" + userToken + "&f=true"; + + HttpResponse response = Network.postRequest(uri, null); + + if (response != null && response.getStatusLine().getStatusCode() == 200) { + Log.i("GCParser.addToFavorites: cache added to favorites"); + cache.setFavorite(true); + cache.setFavoritePoints(cache.getFavoritePoints() + 1); + return true; + } + Log.e("GCParser.addToFavorites: cache not added to favorites"); + return false; + } + + /** + * Removes the cache from the Favorites + * + * @param cache + * the cache to remove + * @return <code>false</code> if an error occurred, <code>true</code> otherwise + */ + static boolean removeFromFavorites(final cgCache cache) { + 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 uri = "http://www.geocaching.com/datastore/favorites.svc/update?u=" + userToken + "&f=false"; + + HttpResponse response = Network.postRequest(uri, null); + + if (response != null && response.getStatusLine().getStatusCode() == 200) { + Log.i("GCParser.removeFromFavorites: cache removed from favorites"); + cache.setFavorite(false); + cache.setFavoritePoints(cache.getFavoritePoints() - 1); + return true; + } + Log.e("GCParser.removeFromFavorites: cache not removed from favorites"); + return false; + } + /** * Parse a trackable HTML description into a cgTrackable object * @@ -1349,9 +1419,9 @@ public abstract class GCParser { String rawResponse; if (!getDataFromPage) { - final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN2.matcher(page); + final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN.matcher(page); if (!userTokenMatcher.find()) { - Log.e("cgBase.loadLogsFromDetails: unable to extract userToken"); + Log.e("GCParser.loadLogsFromDetails: unable to extract userToken"); return null; } @@ -1366,17 +1436,17 @@ public abstract class GCParser { final HttpResponse response = Network.getRequest("http://www.geocaching.com/seek/geocache.logbook", params); if (response == null) { - Log.e("cgBase.loadLogsFromDetails: cannot log logs, response is null"); + Log.e("GCParser.loadLogsFromDetails: cannot log logs, response is null"); return null; } final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != 200) { - Log.e("cgBase.loadLogsFromDetails: error " + statusCode + " when requesting log information"); + Log.e("GCParser.loadLogsFromDetails: error " + statusCode + " when requesting log information"); return null; } rawResponse = Network.getResponseData(response); if (rawResponse == null) { - Log.e("cgBase.loadLogsFromDetails: unable to read whole response"); + Log.e("GCParser.loadLogsFromDetails: unable to read whole response"); return null; } } else { @@ -1389,7 +1459,7 @@ public abstract class GCParser { try { final JSONObject resp = new JSONObject(rawResponse); if (!resp.getString("status").equals("success")) { - Log.e("cgBase.loadLogsFromDetails: status is " + resp.getString("status")); + Log.e("GCParser.loadLogsFromDetails: status is " + resp.getString("status")); return null; } @@ -1430,7 +1500,7 @@ public abstract class GCParser { } } catch (JSONException e) { // failed to parse logs - Log.w("cgBase.loadLogsFromDetails: Failed to parse cache logs", e); + Log.w("GCParser.loadLogsFromDetails: Failed to parse cache logs", e); } return logs; |
