diff options
Diffstat (limited to 'main/src/cgeo/geocaching/Geocache.java')
-rw-r--r-- | main/src/cgeo/geocaching/Geocache.java | 394 |
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))); + } + } |