aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/Geocache.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/Geocache.java')
-rw-r--r--main/src/cgeo/geocaching/Geocache.java394
1 files changed, 181 insertions, 213 deletions
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index d9b2856..033196c 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -12,22 +12,20 @@ import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCConstants;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.connector.gc.UncertainProperty;
-import cgeo.geocaching.enumerations.CacheAttribute;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.enumerations.LoadFlags.LoadFlag;
import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.files.GPXParser;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.network.HtmlImage;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.CalendarUtils;
import cgeo.geocaching.utils.CancellableHandler;
-import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.LazyInitializedList;
import cgeo.geocaching.utils.Log;
@@ -40,7 +38,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
-import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@@ -50,18 +47,17 @@ import org.eclipse.jdt.annotation.Nullable;
import rx.Scheduler;
import rx.Subscription;
import rx.functions.Action0;
+import rx.schedulers.Schedulers;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.text.Html;
-import android.text.Html.ImageGetter;
import java.io.File;
import java.util.ArrayList;
@@ -69,10 +65,9 @@ import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.EnumMap;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -80,16 +75,18 @@ import java.util.Set;
import java.util.regex.Pattern;
/**
- * Internal c:geo representation of a "cache"
+ * Internal representation of a "cache"
*/
-public class Geocache implements ICache, IWaypoint {
+public class Geocache implements IWaypoint {
private static final int OWN_WP_PREFIX_OFFSET = 17;
private long updated = 0;
private long detailedUpdate = 0;
private long visitedDate = 0;
- private int listId = StoredList.TEMPORARY_LIST_ID;
+ private int listId = StoredList.TEMPORARY_LIST.id;
private boolean detailed = false;
+
+ @NonNull
private String geocode = "";
private String cacheId = "";
private String guid = "";
@@ -102,7 +99,7 @@ public class Geocache implements ICache, IWaypoint {
* lazy initialized
*/
private String hint = null;
- private CacheSize size = CacheSize.UNKNOWN;
+ @NonNull private CacheSize size = CacheSize.UNKNOWN;
private float difficulty = 0;
private float terrain = 0;
private Float direction = null;
@@ -137,19 +134,19 @@ public class Geocache implements ICache, IWaypoint {
private final LazyInitializedList<String> attributes = new LazyInitializedList<String>() {
@Override
public List<String> call() {
- return DataStore.loadAttributes(geocode);
+ return inDatabase() ? DataStore.loadAttributes(geocode) : new LinkedList<String>();
}
};
private final LazyInitializedList<Waypoint> waypoints = new LazyInitializedList<Waypoint>() {
@Override
public List<Waypoint> call() {
- return DataStore.loadWaypoints(geocode);
+ return inDatabase() ? DataStore.loadWaypoints(geocode) : new LinkedList<Waypoint>();
}
};
private List<Image> spoilers = null;
private List<Trackable> inventory = null;
- private Map<LogType, Integer> logCounts = new HashMap<>();
+ private Map<LogType, Integer> logCounts = new EnumMap<>(LogType.class);
private boolean userModifiedCoords = false;
// temporary values
private boolean statusChecked = false;
@@ -163,10 +160,6 @@ public class Geocache implements ICache, IWaypoint {
private Handler changeNotificationHandler = null;
- // Images whose URL contains one of those patterns will not be available on the Images tab
- // for opening into an external application.
- private final String[] NO_EXTERNAL = new String[]{"geocheck.org"};
-
/**
* Create a new cache. To be used everywhere except for the GPX parser
*/
@@ -178,7 +171,7 @@ public class Geocache implements ICache, IWaypoint {
* Cache constructor to be used by the GPX parser only. This constructor explicitly sets several members to empty
* lists.
*
- * @param gpxParser
+ * @param gpxParser ignored parameter allowing to select this constructor
*/
public Geocache(final GPXParser gpxParser) {
setReliableLatLon(true);
@@ -220,7 +213,7 @@ public class Geocache implements ICache, IWaypoint {
// if parsed cache is not yet detailed and stored is, the information of
// the parsed cache will be overwritten
if (!detailed && other.detailed) {
- detailed = other.detailed;
+ detailed = true;
detailedUpdate = other.detailedUpdate;
// boolean values must be enumerated here. Other types are assigned outside this if-statement
reliableLatLon = other.reliableLatLon;
@@ -251,7 +244,7 @@ public class Geocache implements ICache, IWaypoint {
if (visitedDate == 0) {
visitedDate = other.visitedDate;
}
- if (listId == StoredList.TEMPORARY_LIST_ID) {
+ if (listId == StoredList.TEMPORARY_LIST.id) {
listId = other.listId;
}
if (StringUtils.isBlank(geocode)) {
@@ -279,7 +272,7 @@ public class Geocache implements ICache, IWaypoint {
if (!detailed && StringUtils.isBlank(getHint())) {
hint = other.getHint();
}
- if (size == null || CacheSize.UNKNOWN == size) {
+ if (size == CacheSize.UNKNOWN) {
size = other.size;
}
if (difficulty == 0) {
@@ -455,11 +448,7 @@ public class Geocache implements ICache, IWaypoint {
ActivityMixin.showToast(fromActivity, fromActivity.getResources().getString(R.string.err_cannot_log_visit));
return;
}
- final Intent logVisitIntent = new Intent(fromActivity, LogCacheActivity.class);
- logVisitIntent.putExtra(LogCacheActivity.EXTRAS_ID, cacheId);
- logVisitIntent.putExtra(LogCacheActivity.EXTRAS_GEOCODE, geocode);
-
- fromActivity.startActivity(logVisitIntent);
+ fromActivity.startActivity(LogCacheActivity.getLogCacheIntent(fromActivity, cacheId, geocode));
}
public void logOffline(final Activity fromActivity, final LogType logType) {
@@ -491,11 +480,15 @@ public class Geocache implements ICache, IWaypoint {
notifyChange();
}
+ @NonNull
public List<LogType> getPossibleLogTypes() {
return getConnector().getPossibleLogTypes(this);
}
public void openInBrowser(final Activity fromActivity) {
+ if (getUrl() == null) {
+ return;
+ }
final Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getLongUrl()));
// Check if cgeo is the default, show the chooser to let the user choose a browser
@@ -514,19 +507,11 @@ public class Geocache implements ICache, IWaypoint {
}
}
-
- private String getCacheUrl() {
- return getConnector().getCacheUrl(this);
- }
-
+ @NonNull
private IConnector getConnector() {
return ConnectorFactory.getConnector(this);
}
- public boolean canOpenInBrowser() {
- return getCacheUrl() != null;
- }
-
public boolean supportsRefresh() {
return getConnector() instanceof ISearchByGeocode;
}
@@ -551,11 +536,11 @@ public class Geocache implements ICache, IWaypoint {
return getConnector().supportsOwnCoordinates();
}
+ @NonNull
public ILoggingManager getLoggingManager(final LogCacheActivity activity) {
return getConnector().getLoggingManager(activity, this);
}
- @Override
public float getDifficulty() {
return difficulty;
}
@@ -565,35 +550,30 @@ public class Geocache implements ICache, IWaypoint {
return geocode;
}
- @Override
+ /**
+ * @return displayed owner, might differ from the real owner
+ */
public String getOwnerDisplayName() {
return ownerDisplayName;
}
- @Override
+ @NonNull
public CacheSize getSize() {
- if (size == null) {
- return CacheSize.UNKNOWN;
- }
return size;
}
- @Override
public float getTerrain() {
return terrain;
}
- @Override
public boolean isArchived() {
return BooleanUtils.isTrue(archived);
}
- @Override
public boolean isDisabled() {
return BooleanUtils.isTrue(disabled);
}
- @Override
public boolean isPremiumMembersOnly() {
return BooleanUtils.isTrue(premiumMembersOnly);
}
@@ -602,20 +582,27 @@ public class Geocache implements ICache, IWaypoint {
this.premiumMembersOnly = members;
}
- @Override
+ /**
+ *
+ * @return {@code true} if the user is the owner of the cache, {@code false} otherwise
+ */
public boolean isOwner() {
return getConnector().isOwner(this);
}
- @Override
+ /**
+ * @return GC username of the (actual) owner, might differ from the owner. Never empty.
+ */
+ @NonNull
public String getOwnerUserId() {
return ownerUserId;
}
/**
* Attention, calling this method may trigger a database access for the cache!
+ *
+ * @return the decrypted hint
*/
- @Override
public String getHint() {
initializeCacheTexts();
assertTextNotNull(hint, "Hint");
@@ -635,7 +622,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Attention, calling this method may trigger a database access for the cache!
*/
- @Override
public String getDescription() {
initializeCacheTexts();
assertTextNotNull(description, "Description");
@@ -647,18 +633,25 @@ public class Geocache implements ICache, IWaypoint {
*/
private void initializeCacheTexts() {
if (description == null || shortdesc == null || hint == null || location == null) {
- final Geocache partial = DataStore.loadCacheTexts(this.getGeocode());
- if (description == null) {
- setDescription(partial.getDescription());
- }
- if (shortdesc == null) {
- setShortDescription(partial.getShortDescription());
- }
- if (hint == null) {
- setHint(partial.getHint());
- }
- if (location == null) {
- setLocation(partial.getLocation());
+ if (inDatabase()) {
+ final Geocache partial = DataStore.loadCacheTexts(this.getGeocode());
+ if (description == null) {
+ setDescription(partial.getDescription());
+ }
+ if (shortdesc == null) {
+ setShortDescription(partial.getShortDescription());
+ }
+ if (hint == null) {
+ setHint(partial.getHint());
+ }
+ if (location == null) {
+ setLocation(partial.getLocation());
+ }
+ } else {
+ description = StringUtils.defaultString(description);
+ shortdesc = StringUtils.defaultString(shortdesc);
+ hint = StringUtils.defaultString(hint);
+ location = StringUtils.defaultString(location);
}
}
}
@@ -666,7 +659,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Attention, calling this method may trigger a database access for the cache!
*/
- @Override
public String getShortDescription() {
initializeCacheTexts();
assertTextNotNull(shortdesc, "Short description");
@@ -678,7 +670,6 @@ public class Geocache implements ICache, IWaypoint {
return name;
}
- @Override
public String getCacheId() {
if (StringUtils.isBlank(cacheId) && getConnector().equals(GCConnector.getInstance())) {
return String.valueOf(GCConstants.gccodeToGCId(geocode));
@@ -687,7 +678,6 @@ public class Geocache implements ICache, IWaypoint {
return cacheId;
}
- @Override
public String getGuid() {
return guid;
}
@@ -695,14 +685,12 @@ public class Geocache implements ICache, IWaypoint {
/**
* Attention, calling this method may trigger a database access for the cache!
*/
- @Override
public String getLocation() {
initializeCacheTexts();
assertTextNotNull(location, "Location");
return location;
}
- @Override
public String getPersonalNote() {
// non premium members have no personal notes, premium members have an empty string by default.
// map both to null, so other code doesn't need to differentiate
@@ -713,15 +701,13 @@ public class Geocache implements ICache, IWaypoint {
return getConnector() instanceof ISearchByCenter;
}
- public void shareCache(final Activity fromActivity, final Resources res) {
- if (geocode == null) {
- return;
- }
-
+ public void shareCache(@NonNull final Activity fromActivity, final Resources res) {
final Intent intent = getShareIntent();
fromActivity.startActivity(Intent.createChooser(intent, res.getText(R.string.cache_menu_share)));
}
+
+ @NonNull
public Intent getShareIntent() {
final StringBuilder subject = new StringBuilder("Geocache ");
subject.append(geocode);
@@ -732,20 +718,25 @@ public class Geocache implements ICache, IWaypoint {
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject.toString());
- intent.putExtra(Intent.EXTRA_TEXT, getUrl());
+ intent.putExtra(Intent.EXTRA_TEXT, StringUtils.defaultString(getUrl()));
return intent;
}
+ @Nullable
public String getUrl() {
return getConnector().getCacheUrl(this);
}
+ @Nullable
public String getLongUrl() {
return getConnector().getLongCacheUrl(this);
}
- public String getCgeoUrl() { return getConnector().getCacheUrl(this); }
+ @Nullable
+ public String getCgeoUrl() {
+ return getConnector().getCacheUrl(this);
+ }
public boolean supportsGCVote() {
return StringUtils.startsWithIgnoreCase(geocode, "GC");
@@ -755,12 +746,14 @@ public class Geocache implements ICache, IWaypoint {
this.description = description;
}
- @Override
public boolean isFound() {
return BooleanUtils.isTrue(found);
}
- @Override
+ /**
+ *
+ * @return {@code true} if the user has put a favorite point onto this cache
+ */
public boolean isFavorite() {
return BooleanUtils.isTrue(favorite);
}
@@ -769,18 +762,16 @@ public class Geocache implements ICache, IWaypoint {
this.favorite = favorite;
}
- @Override
@Nullable
public Date getHiddenDate() {
return hidden;
}
- @Override
+ @NonNull
public List<String> getAttributes() {
return attributes.getUnderlyingList();
}
- @Override
public List<Trackable> getInventory() {
return inventory;
}
@@ -792,22 +783,25 @@ public class Geocache implements ICache, IWaypoint {
spoilers.add(spoiler);
}
- @Override
+ @NonNull
public List<Image> getSpoilers() {
return ListUtils.unmodifiableList(ListUtils.emptyIfNull(spoilers));
}
- @Override
+ /**
+ * @return a statistic how often the caches has been found, disabled, archived etc.
+ */
public Map<LogType, Integer> getLogCounts() {
return logCounts;
}
- @Override
public int getFavoritePoints() {
return favoritePoints;
}
- @Override
+ /**
+ * @return the normalized cached name to be used for sorting, taking into account the numerical parts in the name
+ */
public String getNameForSorting() {
if (null == nameForSorting) {
nameForSorting = name;
@@ -908,8 +902,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Set reliable coordinates
- *
- * @param coords
*/
public void setCoords(final Geopoint coords) {
this.coords = new UncertainProperty<>(coords);
@@ -917,9 +909,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Set unreliable coordinates from a certain map zoom level
- *
- * @param coords
- * @param zoomlevel
*/
public void setCoords(final Geopoint coords, final int zoomlevel) {
this.coords = new UncertainProperty<>(coords, zoomlevel);
@@ -976,7 +965,9 @@ public class Geocache implements ICache, IWaypoint {
this.inventoryItems = inventoryItems;
}
- @Override
+ /**
+ * @return {@code true} if the cache is on the user's watchlist, {@code false} otherwise
+ */
public boolean isOnWatchlist() {
return BooleanUtils.isTrue(onWatchlist);
}
@@ -990,6 +981,7 @@ public class Geocache implements ICache, IWaypoint {
*
* @return always non <code>null</code>
*/
+ @NonNull
public List<Waypoint> getWaypoints() {
return waypoints.getUnderlyingList();
}
@@ -1028,7 +1020,7 @@ public class Geocache implements ICache, IWaypoint {
*/
@NonNull
public List<LogEntry> getLogs() {
- return DataStore.loadLogs(geocode);
+ return inDatabase() ? DataStore.loadLogs(geocode) : Collections.<LogEntry>emptyList();
}
/**
@@ -1069,7 +1061,7 @@ public class Geocache implements ICache, IWaypoint {
this.directionImg = directionImg;
}
- public void setGeocode(final String geocode) {
+ public void setGeocode(@NonNull final String geocode) {
this.geocode = StringUtils.upperCase(geocode);
}
@@ -1097,13 +1089,8 @@ public class Geocache implements ICache, IWaypoint {
this.hint = hint;
}
- public void setSize(final CacheSize size) {
- if (size == null) {
- this.size = CacheSize.UNKNOWN;
- }
- else {
- this.size = size;
- }
+ public void setSize(@NonNull final CacheSize size) {
+ this.size = size;
}
public void setDifficulty(final float difficulty) {
@@ -1160,7 +1147,6 @@ public class Geocache implements ICache, IWaypoint {
*
* @returns Never null
*/
- @Override
public CacheType getType() {
return cacheType.getValue();
}
@@ -1203,6 +1189,13 @@ public class Geocache implements ICache, IWaypoint {
}
/**
+ * Check if this cache instance comes from or has been stored into the database.
+ */
+ public boolean inDatabase() {
+ return storageLocation.contains(StorageLocation.DATABASE);
+ }
+
+ /**
* @param waypoint
* Waypoint to add to the cache
* @param saveToDatabase
@@ -1214,7 +1207,9 @@ public class Geocache implements ICache, IWaypoint {
waypoint.setGeocode(geocode);
if (waypoint.getId() < 0) { // this is a new waypoint
- assignUniquePrefix(waypoint);
+ if (StringUtils.isBlank(waypoint.getPrefix())) {
+ assignUniquePrefix(waypoint);
+ }
waypoints.add(waypoint);
if (waypoint.isFinalWithCoords()) {
finalDefined = true;
@@ -1249,13 +1244,14 @@ public class Geocache implements ICache, IWaypoint {
}
for (int i = OWN_WP_PREFIX_OFFSET; i < 100; i++) {
- final String prefixCandidate = StringUtils.leftPad(String.valueOf(i), 2, '0');
+ final String prefixCandidate = String.valueOf(i);
if (!assignedPrefixes.contains(prefixCandidate)) {
waypoint.setPrefix(prefixCandidate);
- break;
+ return;
}
}
+ throw new IllegalStateException("too many waypoints, unable to assign unique prefix");
}
public boolean hasWaypoints() {
@@ -1341,8 +1337,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* deletes any waypoint
- *
- * @param waypoint
*/
public void deleteWaypointForce(final Waypoint waypoint) {
@@ -1389,12 +1383,15 @@ public class Geocache implements ICache, IWaypoint {
/**
* Detect coordinates in the personal note and convert them to user defined waypoints. Works by rule of thumb.
*/
- public void parseWaypointsFromNote() {
+ public boolean parseWaypointsFromNote() {
+ boolean changed = false;
for (final Waypoint waypoint : Waypoint.parseWaypointsFromNote(StringUtils.defaultString(getPersonalNote()))) {
if (!hasIdenticalWaypoint(waypoint.getCoords())) {
addOrChangeWaypoint(waypoint, false);
+ changed = true;
}
}
+ return changed;
}
private boolean hasIdenticalWaypoint(final Geopoint point) {
@@ -1432,7 +1429,7 @@ public class Geocache implements ICache, IWaypoint {
}
public void store(final CancellableHandler handler) {
- store(StoredList.TEMPORARY_LIST_ID, handler);
+ store(StoredList.TEMPORARY_LIST.id, handler);
}
public void store(final int listId, final CancellableHandler handler) {
@@ -1457,8 +1454,8 @@ public class Geocache implements ICache, IWaypoint {
return "cache";
}
- public Subscription drop(final Handler handler, final Scheduler scheduler) {
- return scheduler.createWorker().schedule(new Action0() {
+ public Subscription drop(final Handler handler) {
+ return Schedulers.io().createWorker().schedule(new Action0() {
@Override
public void call() {
try {
@@ -1476,54 +1473,37 @@ public class Geocache implements ICache, IWaypoint {
DataStore.removeCache(getGeocode(), EnumSet.of(RemoveFlag.CACHE));
}
- public void checkFields() {
- if (StringUtils.isBlank(getGeocode())) {
- Log.w("geo code not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getName())) {
- Log.w("name not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getGuid())) {
- Log.w("guid not parsed correctly for " + geocode);
- }
- if (getTerrain() == 0.0) {
- Log.w("terrain not parsed correctly for " + geocode);
- }
- if (getDifficulty() == 0.0) {
- Log.w("difficulty not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getOwnerDisplayName())) {
- Log.w("owner display name not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getOwnerUserId())) {
- Log.w("owner user id real not parsed correctly for " + geocode);
- }
- if (getHiddenDate() == null) {
- Log.w("hidden not parsed correctly for " + geocode);
- }
- if (getFavoritePoints() < 0) {
- Log.w("favoriteCount not parsed correctly for " + geocode);
- }
- if (getSize() == null) {
- Log.w("size not parsed correctly for " + geocode);
- }
- if (getType() == null || getType() == CacheType.UNKNOWN) {
- Log.w("type not parsed correctly for " + geocode);
- }
- if (getCoords() == null) {
- Log.w("coordinates not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getLocation())) {
- Log.w("location not parsed correctly for " + geocode);
+ private void warnIncorrectParsingIf(final boolean incorrect, final String field) {
+ if (incorrect) {
+ Log.w(field + " not parsed correctly for " + geocode);
}
}
+ private void warnIncorrectParsingIfBlank(final String str, final String field) {
+ warnIncorrectParsingIf(StringUtils.isBlank(str), field);
+ }
+
+ public void checkFields() {
+ warnIncorrectParsingIfBlank(getGeocode(), "geo");
+ warnIncorrectParsingIfBlank(getName(), "name");
+ warnIncorrectParsingIfBlank(getGuid(), "guid");
+ warnIncorrectParsingIf(getTerrain() == 0.0, "terrain");
+ warnIncorrectParsingIf(getDifficulty() == 0.0, "difficulty");
+ warnIncorrectParsingIfBlank(getOwnerDisplayName(), "owner");
+ warnIncorrectParsingIfBlank(getOwnerUserId(), "owner");
+ warnIncorrectParsingIf(getHiddenDate() == null, "hidden");
+ warnIncorrectParsingIf(getFavoritePoints() < 0, "favoriteCount");
+ warnIncorrectParsingIf(getSize() == CacheSize.UNKNOWN, "size");
+ warnIncorrectParsingIf(getType() == null || getType() == CacheType.UNKNOWN, "type");
+ warnIncorrectParsingIf(getCoords() == null, "coordinates");
+ warnIncorrectParsingIfBlank(getLocation(), "location");
+ }
+
public Subscription refresh(final CancellableHandler handler, final Scheduler scheduler) {
return scheduler.createWorker().schedule(new Action0() {
@Override
public void call() {
refreshSynchronous(handler);
- handler.sendEmptyMessage(CancellableHandler.DONE);
}
});
}
@@ -1614,7 +1594,7 @@ public class Geocache implements ICache, IWaypoint {
RxUtils.waitForCompletion(StaticMapsProvider.downloadMaps(cache), imgGetter.waitForEndObservable(handler));
if (handler != null) {
- handler.sendMessage(Message.obtain());
+ handler.sendEmptyMessage(CancellableHandler.DONE);
}
} catch (final Exception e) {
Log.e("Geocache.storeCache", e);
@@ -1627,7 +1607,7 @@ public class Geocache implements ICache, IWaypoint {
return null;
}
- if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (DataStore.isOffline(geocode, guid) || DataStore.isThere(geocode, guid, true, true))) {
+ if (!forceReload && listId == StoredList.TEMPORARY_LIST.id && (DataStore.isOffline(geocode, guid) || DataStore.isThere(geocode, guid, true, true))) {
final SearchResult search = new SearchResult();
final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : DataStore.getGeocodeForGuid(guid);
search.addGeocode(realGeocode);
@@ -1635,7 +1615,7 @@ public class Geocache implements ICache, IWaypoint {
}
// if we have no geocode, we can't dynamically select the handler, but must explicitly use GC
- if (geocode == null && guid != null) {
+ if (geocode == null) {
return GCConnector.getInstance().searchByGeocode(null, guid, handler);
}
@@ -1655,9 +1635,9 @@ public class Geocache implements ICache, IWaypoint {
*
* @return start time in minutes after midnight
*/
- public String guessEventTimeMinutes() {
+ public int guessEventTimeMinutes() {
if (!isEventCache()) {
- return null;
+ return -1;
}
final String hourLocalized = CgeoApplication.getInstance().getString(R.string.cache_time_full_hours);
@@ -1669,7 +1649,7 @@ public class Geocache implements ICache, IWaypoint {
// 17 - 20 o'clock
patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?" + "\\s*(?:-|[a-z]+)\\s*" + "(?:\\d{1,2})(?:\\.00)?" + "\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
// 12 o'clock, 12.00 o'clock
- patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
+ patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.(00|15|30|45))?\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
}
final String searchText = getShortDescription() + ' ' + getDescription();
@@ -1679,64 +1659,25 @@ public class Geocache implements ICache, IWaypoint {
try {
final int hours = Integer.parseInt(matcher.group(1));
int minutes = 0;
- if (matcher.groupCount() >= 2) {
+ if (matcher.groupCount() >= 2 && !StringUtils.isEmpty(matcher.group(2))) {
minutes = Integer.parseInt(matcher.group(2));
}
if (hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60) {
- return String.valueOf(hours * 60 + minutes);
+ return hours * 60 + minutes;
}
- } catch (final NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
// cannot happen, but static code analysis doesn't know
}
}
}
- return null;
- }
-
- /**
- * check whether the cache has a given attribute
- *
- * @param attribute
- * @param yes
- * true if we are looking for the attribute_yes version, false for the attribute_no version
- * @return
- */
- public boolean hasAttribute(final CacheAttribute attribute, final boolean yes) {
- Geocache fullCache = DataStore.loadCache(getGeocode(), EnumSet.of(LoadFlag.ATTRIBUTES));
- if (fullCache == null) {
- fullCache = this;
- }
- return fullCache.getAttributes().contains(attribute.getAttributeName(yes));
+ return -1;
}
public boolean hasStaticMap() {
return StaticMapsProvider.hasStaticMap(this);
}
- public static final Predicate<Geocache> hasStaticMap = new Predicate<Geocache>() {
- @Override
- public boolean evaluate(final Geocache cache) {
- return cache.hasStaticMap();
- }
- };
-
- private void addDescriptionImagesUrls(final Collection<Image> images) {
- final Set<String> urls = new LinkedHashSet<>();
- for (final Image image : images) {
- urls.add(image.getUrl());
- }
- Html.fromHtml(getDescription(), new ImageGetter() {
- @Override
- public Drawable getDrawable(final String source) {
- if (!urls.contains(source) && !ImageUtils.containsPattern(source, NO_EXTERNAL)) {
- images.add(new Image(source, geocode));
- urls.add(source);
- }
- return null;
- }
- }, null);
- }
-
+ @NonNull
public Collection<Image> getImages() {
final LinkedList<Image> result = new LinkedList<>();
result.addAll(getSpoilers());
@@ -1744,22 +1685,23 @@ public class Geocache implements ICache, IWaypoint {
for (final LogEntry log : getLogs()) {
result.addAll(log.getLogImages());
}
- final Set<String> urls = new HashSet<>(result.size());
- for (final Image image : result) {
- urls.add(image.getUrl());
- }
- addDescriptionImagesUrls(result);
+ ImageUtils.addImagesFromHtml(result, geocode, getShortDescription(), getDescription());
return result;
}
- // Add spoilers stored locally in /sdcard/GeocachePhotos
+ /**
+ * Add spoilers stored locally in <tt>/sdcard/GeocachePhotos</tt>. If a cache is named GC123ABC, the
+ * directory will be <tt>/sdcard/GeocachePhotos/C/B/GC123ABC/</tt>.
+ *
+ * @param spoilers the list to add to
+ */
private void addLocalSpoilersTo(final List<Image> spoilers) {
if (StringUtils.length(geocode) >= 2) {
final String suffix = StringUtils.right(geocode, 2);
- final File baseDir = new File(Environment.getExternalStorageDirectory().toString(), "GeocachePhotos");
+ final File baseDir = new File(Environment.getExternalStorageDirectory(), "GeocachePhotos");
final File lastCharDir = new File(baseDir, suffix.substring(1));
final File secondToLastCharDir = new File(lastCharDir, suffix.substring(0, 1));
- final File finalDir = new File(secondToLastCharDir, getGeocode());
+ final File finalDir = new File(secondToLastCharDir, geocode);
final File[] files = finalDir.listFiles();
if (files != null) {
for (final File image : files) {
@@ -1805,18 +1747,17 @@ public class Geocache implements ICache, IWaypoint {
return getConnector().getWaypointGpxId(prefix, geocode);
}
+ @NonNull
public String getWaypointPrefix(final String name) {
return getConnector().getWaypointPrefix(name);
}
/**
* Get number of overall finds for a cache, or 0 if the number of finds is not known.
- *
- * @return
*/
public int getFindsCount() {
if (getLogCounts().isEmpty()) {
- setLogCounts(DataStore.loadLogCounts(getGeocode()));
+ setLogCounts(inDatabase() ? DataStore.loadLogCounts(getGeocode()) : Collections.<LogType, Integer>emptyMap());
}
final Integer logged = getLogCounts().get(LogType.FOUND_IT);
if (logged != null) {
@@ -1829,12 +1770,13 @@ public class Geocache implements ICache, IWaypoint {
return (getType().applyDistanceRule() || hasUserModifiedCoords()) && getConnector() == GCConnector.getInstance();
}
+ @NonNull
public LogType getDefaultLogType() {
if (isEventCache()) {
final Date eventDate = getHiddenDate();
- final boolean expired = DateUtils.isPastEvent(this);
+ final boolean expired = CalendarUtils.isPastEvent(this);
- if (hasOwnLog(LogType.WILL_ATTEND) || expired || (eventDate != null && DateUtils.daysSince(eventDate.getTime()) == 0)) {
+ if (hasOwnLog(LogType.WILL_ATTEND) || expired || (eventDate != null && CalendarUtils.daysSince(eventDate.getTime()) == 0)) {
return hasOwnLog(LogType.ATTENDED) ? LogType.NOTE : LogType.ATTENDED;
}
return LogType.WILL_ATTEND;
@@ -1848,4 +1790,30 @@ public class Geocache implements ICache, IWaypoint {
return LogType.FOUND_IT;
}
+ /**
+ * Get the geocodes of a collection of caches.
+ *
+ * @param caches a collection of caches
+ * @return the non-blank geocodes of the caches
+ */
+ @NonNull
+ public static Set<String> getGeocodes(@NonNull final Collection<Geocache> caches) {
+ final Set<String> geocodes = new HashSet<>(caches.size());
+ for (final Geocache cache : caches) {
+ final String geocode = cache.getGeocode();
+ if (StringUtils.isNotBlank(geocode)) {
+ geocodes.add(geocode);
+ }
+ }
+ return geocodes;
+ }
+
+ /**
+ * Show the hint as toast message. If no hint is available, a default "no hint available" will be shown instead.
+ */
+ public void showHintToast(final Activity activity) {
+ final String hint = getHint();
+ ActivityMixin.showToast(activity, StringUtils.defaultIfBlank(hint, activity.getString(R.string.cache_hint_not_available)));
+ }
+
}