diff options
Diffstat (limited to 'main/src')
26 files changed, 444 insertions, 227 deletions
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index ac9b156..45a1dd2 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -121,8 +121,7 @@ import java.util.regex.Pattern; * * e.g. details, description, logs, waypoints, inventory... */ -public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page> - implements EditNoteDialogListener { +public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page> { private static final int MENU_FIELD_COPY = 1; private static final int MENU_FIELD_TRANSLATE = 2; @@ -142,6 +141,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc 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 int MESSAGE_FAILED = -1; + private static final int MESSAGE_SUCCEEDED = 1; + private static final Pattern[] DARK_COLOR_PATTERNS = { Pattern.compile("((?<!bg)color)=\"#" + "(0[0-9]){3}" + "\"", Pattern.CASE_INSENSITIVE), Pattern.compile("((?<!bg)color)=\"" + "black" + "\"", Pattern.CASE_INSENSITIVE), @@ -156,8 +158,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc private SearchResult search; - private EditNoteDialogListener editNoteDialogListener; - private final GeoDirHandler locationUpdater = new GeoDirHandler() { @Override public void updateGeoData(final IGeoData geo) { @@ -1061,7 +1061,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc private LinearLayout detailsList; // TODO Do we need this thread-references? - private StoreCacheThread storeThread; private RefreshCacheThread refreshThread; private Thread watchlistThread; @@ -1208,26 +1207,14 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc new RunnableWithArgument<Integer>() { @Override public void run(final Integer selectedListId) { - storeCache(selectedListId); + storeCache(selectedListId, new StoreCacheHandler(CacheDetailActivity.this, progress)); } }, true, StoredList.TEMPORARY_LIST_ID); } else { - storeCache(StoredList.TEMPORARY_LIST_ID); + storeCache(StoredList.TEMPORARY_LIST_ID, new StoreCacheHandler(CacheDetailActivity.this, progress)); } } - protected void storeCache(int listId) { - final StoreCacheHandler storeCacheHandler = new StoreCacheHandler(CacheDetailActivity.this, progress); - - progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true, storeCacheHandler.cancelMessage()); - - if (storeThread != null) { - storeThread.interrupt(); - } - - storeThread = new StoreCacheThread(listId, storeCacheHandler); - storeThread.start(); - } } private class RefreshCacheClickListener implements View.OnClickListener { @@ -1256,22 +1243,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } } - private class StoreCacheThread extends Thread { - final private int listId; - final private CancellableHandler handler; - - public StoreCacheThread(final int listId, final CancellableHandler handler) { - this.listId = listId; - this.handler = handler; - } - - @Override - public void run() { - cache.store(listId, handler); - storeThread = null; - } - } - private class RefreshCacheThread extends Thread { final private CancellableHandler handler; @@ -1342,7 +1313,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc public void onClick(View arg0) { doExecute(R.string.cache_dialog_watchlist_add_title, R.string.cache_dialog_watchlist_add_message, - new WatchlistAddThread(new WatchlistHandler(CacheDetailActivity.this, progress))); + new WatchlistAddThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress))); } } @@ -1354,7 +1325,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc public void onClick(View arg0) { doExecute(R.string.cache_dialog_watchlist_remove_title, R.string.cache_dialog_watchlist_remove_message, - new WatchlistRemoveThread(new WatchlistHandler(CacheDetailActivity.this, progress))); + new WatchlistRemoveThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress))); } } @@ -1369,7 +1340,16 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { watchlistThread = null; - handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).addToWatchlist(cache) ? 1 : -1); + Message msg; + if (ConnectorFactory.getConnector(cache).addToWatchlist(cache)) { + msg = Message.obtain(handler, MESSAGE_SUCCEEDED); + } else { + msg = Message.obtain(handler, MESSAGE_FAILED); + Bundle bundle = new Bundle(); + bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_watchlist_failed)); + msg.setData(bundle); + } + handler.sendMessage(msg); } } @@ -1384,7 +1364,16 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { watchlistThread = null; - handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).removeFromWatchlist(cache) ? 1 : -1); + Message msg; + if (ConnectorFactory.getConnector(cache).removeFromWatchlist(cache)) { + msg = Message.obtain(handler, MESSAGE_SUCCEEDED); + } else { + msg = Message.obtain(handler, MESSAGE_FAILED); + Bundle bundle = new Bundle(); + bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_watchlist_failed)); + msg.setData(bundle); + } + handler.sendMessage(msg); } } @@ -1399,7 +1388,16 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { watchlistThread = null; - handler.sendEmptyMessage(GCConnector.addToFavorites(cache) ? 1 : -1); + Message msg; + if (GCConnector.addToFavorites(cache)) { + msg = Message.obtain(handler, MESSAGE_SUCCEEDED); + } else { + msg = Message.obtain(handler, MESSAGE_FAILED); + Bundle bundle = new Bundle(); + bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_favorite_failed)); + msg.setData(bundle); + } + handler.sendMessage(msg); } } @@ -1414,7 +1412,16 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { watchlistThread = null; - handler.sendEmptyMessage(GCConnector.removeFromFavorites(cache) ? 1 : -1); + Message msg; + if (GCConnector.removeFromFavorites(cache)) { + msg = Message.obtain(handler, MESSAGE_SUCCEEDED); + } else { + msg = Message.obtain(handler, MESSAGE_FAILED); + Bundle bundle = new Bundle(); + bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_favorite_failed)); + msg.setData(bundle); + } + handler.sendMessage(msg); } } @@ -1426,7 +1433,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc public void onClick(View arg0) { doExecute(R.string.cache_dialog_favorite_add_title, R.string.cache_dialog_favorite_add_message, - new FavoriteAddThread(new FavoriteUpdateHandler(CacheDetailActivity.this, progress))); + new FavoriteAddThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress))); } } @@ -1438,7 +1445,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc public void onClick(View arg0) { doExecute(R.string.cache_dialog_favorite_remove_title, R.string.cache_dialog_favorite_remove_message, - new FavoriteRemoveThread(new FavoriteUpdateHandler(CacheDetailActivity.this, progress))); + new FavoriteRemoveThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress))); } } @@ -1649,7 +1656,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } // cache personal note - setPersonalNote(); + setPersonalNote(personalNoteView, cache.getPersonalNote()); personalNoteView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); registerForContextMenu(personalNoteView); final Button personalNoteEdit = (Button) view.findViewById(R.id.edit_personalnote); @@ -1657,7 +1664,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void onClick(View v) { if (cache.isOffline()) { - editPersonalNote(); + editPersonalNote(cache, CacheDetailActivity.this); } else { warnPersonalNoteNeedsStoring(); } @@ -1727,24 +1734,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc return view; } - private void editPersonalNote() { - if (cache.isOffline()) { - editNoteDialogListener = new EditNoteDialogListener() { - @Override - public void onFinishEditNoteDialog(final String note) { - cache.setPersonalNote(note); - cache.parseWaypointsFromNote(); - setPersonalNote(); - cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); - CacheDetailActivity.this.notifyDataSetChanged(); - } - }; - final FragmentManager fm = getSupportFragmentManager(); - final EditNoteDialog dialog = EditNoteDialog.newInstance(cache.getPersonalNote()); - dialog.show(fm, "fragment_edit_note"); - } - } - Thread currentThread; private void uploadPersonalNote() { @@ -1760,16 +1749,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc currentThread.start(); } - private void setPersonalNote() { - final String personalNote = cache.getPersonalNote(); - personalNoteView.setText(personalNote, TextView.BufferType.SPANNABLE); - if (StringUtils.isNotBlank(personalNote)) { - personalNoteView.setVisibility(View.VISIBLE); - } else { - personalNoteView.setVisibility(View.GONE); - } - } - private void loadLongDescription() { final Button showDesc = (Button) view.findViewById(R.id.show_description); showDesc.setVisibility(View.GONE); @@ -1796,8 +1775,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); - cache.store(null); - editPersonalNote(); + storeCache(StoredList.STANDARD_LIST_ID, new StoreCachePersonalNoteHandler(CacheDetailActivity.this, progress)); } }); @@ -1808,11 +1786,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } - @Override - public void onFinishEditNoteDialog(final String note) { - editNoteDialogListener.onFinishEditNoteDialog(note); - } - /** * Loads the description in background. <br /> * <br /> @@ -2271,7 +2244,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } Message msg = Message.obtain(); Bundle bundle = new Bundle(); - bundle.putString(SimpleCancellableHandler.SUCCESS_TEXT, res.getString(R.string.cache_personal_note_upload_done)); + bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.cache_personal_note_upload_done)); msg.setData(bundle); handler.sendMessage(msg); } @@ -2389,7 +2362,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc return search; } - private static final class StoreCacheHandler extends SimpleCancellableHandler { + private static class StoreCacheHandler extends SimpleCancellableHandler { public StoreCacheHandler(CacheDetailActivity activity, Progress progress) { super(activity, progress); @@ -2433,47 +2406,103 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } } - private static final class FavoriteUpdateHandler extends SimpleHandler { + private static final class SimpleUpdateHandler extends SimpleHandler { - public FavoriteUpdateHandler(CacheDetailActivity activity, Progress progress) { + public SimpleUpdateHandler(CacheDetailActivity activity, Progress progress) { super(activity, progress); } @Override public void handleMessage(Message msg) { - if (msg.what == -1) { - dismissProgress(); - showToast(R.string.err_favorite_failed); + if (msg.what == MESSAGE_FAILED) { + super.handleMessage(msg); } else { notifyDatasetChanged(activityRef); } } } - /** - * Handler, called when watchlist add or remove is done - */ - private static final class WatchlistHandler extends SimpleHandler { + private static void notifyDatasetChanged(WeakReference<AbstractActivity> activityRef) { + CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get()); + if (activity != null) { + activity.notifyDataSetChanged(); + } + } + + private StoreCacheThread storeThread; + + private class StoreCacheThread extends Thread { + final private int listId; + final private CancellableHandler handler; - public WatchlistHandler(CacheDetailActivity activity, Progress progress) { + public StoreCacheThread(final int listId, final CancellableHandler handler) { + this.listId = listId; + this.handler = handler; + } + + @Override + public void run() { + cache.store(listId, handler); + storeThread = null; + } + } + + protected void storeCache(final int listId, final StoreCacheHandler storeCacheHandler) { + progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true, storeCacheHandler.cancelMessage()); + + if (storeThread != null) { + storeThread.interrupt(); + } + + storeThread = new StoreCacheThread(listId, storeCacheHandler); + storeThread.start(); + } + + private static final class StoreCachePersonalNoteHandler extends StoreCacheHandler { + + public StoreCachePersonalNoteHandler(CacheDetailActivity activity, Progress progress) { super(activity, progress); } @Override - public void handleMessage(Message msg) { - if (msg.what == -1) { - dismissProgress(); - showToast(R.string.err_watchlist_failed); + public void handleRegularMessage(Message msg) { + if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { + updateStatusMsg(R.string.cache_dialog_offline_save_message, (String) msg.obj); } else { - notifyDatasetChanged(activityRef); + dismissProgress(); + CacheDetailActivity activity = (CacheDetailActivity) activityRef.get(); + if (activity != null) { + editPersonalNote(activity.getCache(), activity); + } } } } - private static void notifyDatasetChanged(WeakReference<AbstractActivity> activityRef) { - CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get()); - if (activity != null) { - activity.notifyDataSetChanged(); + public static void editPersonalNote(final Geocache cache, final CacheDetailActivity activity) { + if (cache.isOffline()) { + EditNoteDialogListener editNoteDialogListener = new EditNoteDialogListener() { + @Override + public void onFinishEditNoteDialog(final String note) { + cache.setPersonalNote(note); + cache.parseWaypointsFromNote(); + TextView personalNoteView = (TextView) activity.findViewById(R.id.personalnote); + setPersonalNote(personalNoteView, note); + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + activity.notifyDataSetChanged(); + } + }; + final FragmentManager fm = activity.getSupportFragmentManager(); + final EditNoteDialog dialog = EditNoteDialog.newInstance(cache.getPersonalNote(), editNoteDialogListener); + dialog.show(fm, "fragment_edit_note"); + } + } + + private static void setPersonalNote(final TextView personalNoteView, final String personalNote) { + personalNoteView.setText(personalNote, TextView.BufferType.SPANNABLE); + if (StringUtils.isNotBlank(personalNote)) { + personalNoteView.setVisibility(View.VISIBLE); + } else { + personalNoteView.setVisibility(View.GONE); } } } diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java index 3c69197..f229af8 100644 --- a/main/src/cgeo/geocaching/Geocache.java +++ b/main/src/cgeo/geocaching/Geocache.java @@ -32,6 +32,7 @@ import cgeo.geocaching.utils.LogTemplateProvider.LogContext; import cgeo.geocaching.utils.MatcherWrapper; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import android.app.Activity; @@ -95,17 +96,18 @@ public class Geocache implements ICache, IWaypoint { * lazy initialized */ private String description = null; - private boolean disabled = false; - private boolean archived = false; - private boolean premiumMembersOnly = false; - private boolean found = false; - private boolean favorite = false; + private Boolean disabled = null; + private Boolean archived = null; + private Boolean premiumMembersOnly = null; + private Boolean found = null; + private Boolean favorite = null; + private Boolean onWatchlist = null; + private Boolean logOffline = null; private int favoritePoints = 0; private float rating = 0; // valid ratings are larger than zero private int votes = 0; private float myVote = 0; // valid ratings are larger than zero private int inventoryItems = 0; - private boolean onWatchlist = false; private final List<String> attributes = new LazyInitializedList<String>() { @Override public List<String> call() { @@ -127,7 +129,6 @@ public class Geocache implements ICache, IWaypoint { }; private List<Trackable> inventory = null; private Map<LogType, Integer> logCounts = new HashMap<LogType, Integer>(); - private boolean logOffline = false; private boolean userModifiedCoords = false; // temporary values private boolean statusChecked = false; @@ -136,7 +137,7 @@ public class Geocache implements ICache, IWaypoint { private final EnumSet<StorageLocation> storageLocation = EnumSet.of(StorageLocation.HEAP); private boolean finalDefined = false; private boolean logPasswordRequired = false; - private int zoomlevel = Tile.ZOOMLEVEL_MAX + 1; + private int zoomlevel = Tile.ZOOMLEVEL_MIN - 1; private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); @@ -196,34 +197,37 @@ public class Geocache implements ICache, IWaypoint { detailed = other.detailed; detailedUpdate = other.detailedUpdate; coords = other.coords; - cacheType = other.cacheType; + // merge cache type only if really available from other + if (null != other.cacheType && CacheType.UNKNOWN != other.cacheType) { + cacheType = other.cacheType; + } zoomlevel = other.zoomlevel; // boolean values must be enumerated here. Other types are assigned outside this if-statement - // TODO: check whether a search or a live map systematically returns those, in which case - // we want to keep the most recent one instead of getting information from the previously - // stored data. This is the case for "archived" for example which has been taken out of this - // list. - premiumMembersOnly = other.premiumMembersOnly; reliableLatLon = other.reliableLatLon; + finalDefined = other.finalDefined; + } + + if (premiumMembersOnly == null) { + premiumMembersOnly = other.premiumMembersOnly; + } + if (found == null) { found = other.found; + } + if (disabled == null) { disabled = other.disabled; + } + if (favorite == null) { favorite = other.favorite; + } + if (archived == null) { + archived = other.archived; + } + if (onWatchlist == null) { onWatchlist = other.onWatchlist; + } + if (logOffline == null) { logOffline = other.logOffline; - finalDefined = other.finalDefined; - archived = other.archived; } - - /* - * No gathering for boolean members if other cache is not-detailed - * and does not have information with higher reliability (denoted by zoomlevel) - * - found - * - own - * - disabled - * - favorite - * - onWatchlist - * - logOffline - */ if (visitedDate == 0) { visitedDate = other.visitedDate; } @@ -374,14 +378,14 @@ public class Geocache implements ICache, IWaypoint { StringUtils.equalsIgnoreCase(name, other.name) && cacheType == other.cacheType && size == other.size && - found == other.found && - premiumMembersOnly == other.premiumMembersOnly && + ObjectUtils.equals(found, other.found) && + ObjectUtils.equals(premiumMembersOnly, other.premiumMembersOnly) && difficulty == other.difficulty && terrain == other.terrain && (coords != null ? coords.equals(other.coords) : null == other.coords) && reliableLatLon == other.reliableLatLon && - disabled == other.disabled && - archived == other.archived && + ObjectUtils.equals(disabled, other.disabled) && + ObjectUtils.equals(archived, other.archived) && listId == other.listId && StringUtils.equalsIgnoreCase(ownerDisplayName, other.ownerDisplayName) && StringUtils.equalsIgnoreCase(ownerUserId, other.ownerUserId) && @@ -389,9 +393,9 @@ public class Geocache implements ICache, IWaypoint { StringUtils.equalsIgnoreCase(personalNote, other.personalNote) && StringUtils.equalsIgnoreCase(getShortDescription(), other.getShortDescription()) && StringUtils.equalsIgnoreCase(getLocation(), other.getLocation()) && - favorite == other.favorite && + ObjectUtils.equals(favorite, other.favorite) && favoritePoints == other.favoritePoints && - onWatchlist == other.onWatchlist && + ObjectUtils.equals(onWatchlist, other.onWatchlist) && (hidden != null ? hidden.equals(other.hidden) : null == other.hidden) && StringUtils.equalsIgnoreCase(guid, other.guid) && StringUtils.equalsIgnoreCase(getHint(), other.getHint()) && @@ -408,7 +412,7 @@ public class Geocache implements ICache, IWaypoint { logs == other.logs && inventory == other.inventory && logCounts == other.logCounts && - logOffline == other.logOffline && + ObjectUtils.equals(logOffline, other.logOffline) && finalDefined == other.finalDefined; } @@ -483,7 +487,7 @@ public class Geocache implements ICache, IWaypoint { if (status) { ActivityMixin.showToast(fromActivity, res.getString(R.string.info_log_saved)); cgData.saveVisitDate(geocode); - logOffline = true; + logOffline = Boolean.TRUE; notifyChange(); } else { @@ -610,21 +614,21 @@ public class Geocache implements ICache, IWaypoint { @Override public boolean isArchived() { - return archived; + return (archived != null && archived.booleanValue()); } @Override public boolean isDisabled() { - return disabled; + return (disabled != null && disabled.booleanValue()); } @Override public boolean isPremiumMembersOnly() { - return premiumMembersOnly; + return (premiumMembersOnly != null && premiumMembersOnly.booleanValue()); } public void setPremiumMembersOnly(boolean members) { - this.premiumMembersOnly = members; + this.premiumMembersOnly = Boolean.valueOf(members); } @Override @@ -775,16 +779,16 @@ public class Geocache implements ICache, IWaypoint { @Override public boolean isFound() { - return found; + return (found != null && found.booleanValue()); } @Override public boolean isFavorite() { - return favorite; + return (favorite != null && favorite.booleanValue()); } public void setFavorite(boolean favorite) { - this.favorite = favorite; + this.favorite = Boolean.valueOf(favorite); } @Override @@ -830,12 +834,15 @@ public class Geocache implements ICache, IWaypoint { @Override public String getNameForSorting() { if (null == nameForSorting) { - final MatcherWrapper matcher = new MatcherWrapper(NUMBER_PATTERN, name); - if (matcher.find()) { - nameForSorting = name.replace(matcher.group(), StringUtils.leftPad(matcher.group(), 6, '0')); - } - else { - nameForSorting = name; + nameForSorting = name; + // pad each number part to a fixed size of 6 digits, so that numerical sorting becomes equivalent to string sorting + MatcherWrapper matcher = new MatcherWrapper(NUMBER_PATTERN, nameForSorting); + int start = 0; + while (matcher.find(start)) { + final String number = matcher.group(); + nameForSorting = StringUtils.substring(nameForSorting, 0, matcher.start()) + StringUtils.leftPad(number, 6, '0') + StringUtils.substring(nameForSorting, matcher.start() + number.length()); + start = matcher.start() + Math.max(6, number.length()); + matcher = new MatcherWrapper(NUMBER_PATTERN, nameForSorting); } } return nameForSorting; @@ -919,8 +926,25 @@ public class Geocache implements ICache, IWaypoint { return coords; } + /** + * Set reliable coordinates + * + * @param coords + */ public void setCoords(Geopoint coords) { this.coords = coords; + this.zoomlevel = Tile.ZOOMLEVEL_MAX + 1; + } + + /** + * Set unreliable coordinates from a certain map zoom level + * + * @param coords + * @param zoomlevel + */ + public void setCoords(Geopoint coords, int zoomlevel) { + this.coords = coords; + this.zoomlevel = zoomlevel; } /** @@ -976,11 +1000,11 @@ public class Geocache implements ICache, IWaypoint { @Override public boolean isOnWatchlist() { - return onWatchlist; + return (onWatchlist != null && onWatchlist.booleanValue()); } public void setOnWatchlist(boolean onWatchlist) { - this.onWatchlist = onWatchlist; + this.onWatchlist = Boolean.valueOf(onWatchlist); } /** @@ -1049,11 +1073,11 @@ public class Geocache implements ICache, IWaypoint { } public boolean isLogOffline() { - return logOffline; + return (logOffline != null && logOffline.booleanValue()); } public void setLogOffline(boolean logOffline) { - this.logOffline = logOffline; + this.logOffline = Boolean.valueOf(logOffline); } public boolean isStatusChecked() { @@ -1126,15 +1150,15 @@ public class Geocache implements ICache, IWaypoint { } public void setDisabled(boolean disabled) { - this.disabled = disabled; + this.disabled = Boolean.valueOf(disabled); } public void setArchived(boolean archived) { - this.archived = archived; + this.archived = Boolean.valueOf(archived); } public void setFound(boolean found) { - this.found = found; + this.found = Boolean.valueOf(found); } public void setAttributes(List<String> attributes) { @@ -1477,10 +1501,6 @@ public class Geocache implements ICache, IWaypoint { return this.zoomlevel; } - public void setZoomlevel(int zoomlevel) { - this.zoomlevel = zoomlevel; - } - @Override public int getId() { return 0; diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java index 24b4a58..2d488d6 100644 --- a/main/src/cgeo/geocaching/MainActivity.java +++ b/main/src/cgeo/geocaching/MainActivity.java @@ -328,6 +328,11 @@ public class MainActivity extends AbstractActivity { } private void init() { + + if (app.checkLogin) { + (new FirstLoginThread()).start(); + } + if (initialized) { return; } @@ -335,11 +340,6 @@ public class MainActivity extends AbstractActivity { initialized = true; Settings.setLanguage(Settings.isUseEnglish()); - Settings.getGcLogin(); - - if (app.firstRun) { - (new FirstLoginThread()).start(); - } findOnMap.setClickable(true); findOnMap.setOnClickListener(new OnClickListener() { diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java index 6285cda..ccf3edf 100644 --- a/main/src/cgeo/geocaching/SearchActivity.java +++ b/main/src/cgeo/geocaching/SearchActivity.java @@ -149,7 +149,6 @@ public class SearchActivity extends AbstractActivity { } private void init() { - Settings.getGcLogin(); buttonLatitude.setOnClickListener(new FindByCoordsAction()); buttonLongitude.setOnClickListener(new FindByCoordsAction()); diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java index 5053a85..e637d1f 100644 --- a/main/src/cgeo/geocaching/SearchResult.java +++ b/main/src/cgeo/geocaching/SearchResult.java @@ -271,6 +271,9 @@ public class SearchResult implements Parcelable { if (other != null) { addGeocodes(other.geocodes); addFilteredGeocodes(other.filteredGeocodes); + if (StringUtils.isBlank(url)) { + url = other.url; + } } } diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java index b227939..fd5f714 100644 --- a/main/src/cgeo/geocaching/cgeoapplication.java +++ b/main/src/cgeo/geocaching/cgeoapplication.java @@ -18,7 +18,7 @@ public class cgeoapplication extends Application { private volatile GeoDataProvider geo; private volatile DirectionProvider dir; - public boolean firstRun = true; // c:geo is just launched + public boolean checkLogin = true; // c:geo is just launched public boolean showLoginToast = true; //login toast shown just once. private boolean liveMapHintShown = false; // livemap hint has been shown final private StatusUpdater statusUpdater = new StatusUpdater(); diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index e6fff79..835359a 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -299,7 +299,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, final StatusCode status = Login.login(); if (status == StatusCode.NO_ERROR) { - cgeoapplication.getInstance().firstRun = false; + cgeoapplication.getInstance().checkLogin = false; Login.detectGcCustomDate(); } diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java index 4bc55fe..6a602a7 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCMap.java +++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java @@ -2,7 +2,6 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.Geocache; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.settings.Settings; import cgeo.geocaching.cgData; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; @@ -11,9 +10,11 @@ import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; import cgeo.geocaching.enumerations.LiveMapStrategy.StrategyFlag; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.GeopointFormatter.Format; import cgeo.geocaching.geopoint.Units; import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.LeastRecentlyUsedMap; import cgeo.geocaching.utils.Log; @@ -208,8 +209,7 @@ public class GCMap { cache.setReliableLatLon(false); cache.setGeocode(id); cache.setName(nameCache.get(id)); - cache.setZoomlevel(tile.getZoomlevel()); - cache.setCoords(tile.getCoord(xy)); + cache.setCoords(tile.getCoord(xy), tile.getZoomlevel()); if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && bitmap != null) { for (UTFGridPosition singlePos : singlePositions.get(id)) { if (IconDecoder.parseMapPNG(cache, bitmap, singlePos, tile.getZoomlevel())) { @@ -286,11 +286,18 @@ public class GCMap { Log.d("GCMap.searchByViewport" + viewport.toString()); final SearchResult searchResult = new SearchResult(); - searchResult.setUrl(GCConstants.URL_LIVE_MAP + "?ll=" + viewport.getCenter().getLatitude() + "," + viewport.getCenter().getLongitude()); + + if (Settings.isDebug()) { + searchResult.setUrl(viewport.getCenter().format(Format.LAT_LON_DECMINUTE)); + } if (strategy.flags.contains(StrategyFlag.LOAD_TILES)) { final Set<Tile> tiles = Tile.getTilesForViewport(viewport); + if (Settings.isDebug()) { + searchResult.setUrl(new StringBuilder().append(tiles.iterator().next().getZoomlevel()).append(Formatter.SEPARATOR).append(searchResult.getUrl()).toString()); + } + for (Tile tile : tiles) { if (!Tile.Cache.contains(tile)) { diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index e32f72d..7dc048a 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCParser.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -78,20 +78,15 @@ public abstract class GCParser { searchResult.viewstates = Login.getViewstates(page); // recaptcha - String recaptchaChallenge = null; if (showCaptcha) { final String recaptchaJsParam = TextUtils.getMatch(page, GCConstants.PATTERN_SEARCH_RECAPTCHA, false, null); if (recaptchaJsParam != null) { - final Parameters params = new Parameters("k", recaptchaJsParam.trim()); - final String recaptchaJs = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params)); + thread.setKey(recaptchaJsParam.trim()); - if (StringUtils.isNotBlank(recaptchaJs)) { - recaptchaChallenge = TextUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true); - } + thread.fetchChallenge(); } - if (thread != null && StringUtils.isNotBlank(recaptchaChallenge)) { - thread.setChallenge(recaptchaChallenge); + if (thread != null && StringUtils.isNotBlank(thread.getChallenge())) { thread.notifyNeed(); } } @@ -276,7 +271,7 @@ public abstract class GCParser { } String recaptchaText = null; - if (thread != null && recaptchaChallenge != null) { + if (thread != null && StringUtils.isNotBlank(thread.getChallenge())) { if (thread.getText() == null) { thread.waitForUser(); } @@ -284,7 +279,7 @@ public abstract class GCParser { recaptchaText = thread.getText(); } - if (!cids.isEmpty() && (Settings.isPremiumMember() || showCaptcha) && (recaptchaChallenge == null || StringUtils.isNotBlank(recaptchaText))) { + if (!cids.isEmpty() && (Settings.isPremiumMember() || showCaptcha) && ((thread == null || StringUtils.isBlank(thread.getChallenge())) || StringUtils.isNotBlank(recaptchaText))) { Log.i("Trying to get .loc for " + cids.size() + " caches"); try { @@ -305,8 +300,8 @@ public abstract class GCParser { params.put("CID", cid); } - if (recaptchaChallenge != null && StringUtils.isNotBlank(recaptchaText)) { - params.put("recaptcha_challenge_field", recaptchaChallenge); + if (thread != null && StringUtils.isNotBlank(thread.getChallenge()) && StringUtils.isNotBlank(recaptchaText)) { + params.put("recaptcha_challenge_field", thread.getChallenge()); params.put("recaptcha_response_field", recaptchaText); } params.put("ctl00$ContentBody$uxDownloadLoc", "Download Waypoints"); diff --git a/main/src/cgeo/geocaching/connector/gc/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java index 4b4c93f..2629339 100644 --- a/main/src/cgeo/geocaching/connector/gc/Login.java +++ b/main/src/cgeo/geocaching/connector/gc/Login.java @@ -1,13 +1,13 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.R; -import cgeo.geocaching.settings.Settings; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.network.Cookies; import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.MatcherWrapper; import cgeo.geocaching.utils.TextUtils; @@ -68,8 +68,8 @@ public abstract class Login { private static StatusCode login(boolean retry) { final ImmutablePair<String, String> login = Settings.getGcLogin(); - if (login == null || StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) { - Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.err_login)); + if (StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) { + clearLoginInfo(); Log.e("Login.login: No login information stored"); return StatusCode.NO_LOGIN_INFO_STORED; } @@ -153,9 +153,23 @@ public abstract class Login { return StatusCode.MAINTENANCE; } + resetLoginStatus(); + + return StatusCode.NO_ERROR; + } + + private static void resetLoginStatus() { Cookies.clearCookies(); Settings.setCookieStore(null); - return StatusCode.NO_ERROR; + + setActualLoginStatus(false); + } + + private static void clearLoginInfo() { + resetLoginStatus(); + + setActualCachesFound(-1); + setActualStatus(cgeoapplication.getInstance().getString(R.string.err_login)); } static void setActualCachesFound(final int found) { @@ -475,7 +489,7 @@ public abstract class Login { /** * Unfortunately the cache details page contains user generated whitespace in the personal note, therefore we cannot * remove the white space from cache details pages. - * + * * @param uri * @return */ diff --git a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java b/main/src/cgeo/geocaching/connector/gc/SearchHandler.java index 45832e4..4358399 100644 --- a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java +++ b/main/src/cgeo/geocaching/connector/gc/SearchHandler.java @@ -15,11 +15,13 @@ import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; public class SearchHandler extends Handler { @@ -37,7 +39,7 @@ public class SearchHandler extends Handler { imageView.setImageBitmap(img); } } catch (Exception e) { - // nothing + Log.e("Error setting reCAPTCHA image", e); } } }; @@ -58,6 +60,20 @@ public class SearchHandler extends Handler { imageView = (ImageView) view.findViewById(R.id.image); + ImageButton reloadButton = (ImageButton) view.findViewById(R.id.button_recaptcha_refresh); + reloadButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + recaptchaThread.fetchChallenge(); + try { + (new GetCaptchaThread(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start(); + } catch (MalformedURLException e) { + Log.e("Bad reCAPTCHA image url", e); + } + } + }); + (new GetCaptchaThread(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start(); dlg.setTitle(res.getString(R.string.caches_recaptcha_title)); @@ -76,7 +92,7 @@ public class SearchHandler extends Handler { dlg.create().show(); } } catch (Exception e) { - // nothing + Log.e("Error in reCAPTCHA handler", e); } } @@ -90,6 +106,7 @@ public class SearchHandler extends Handler { @Override public void run() { try { + Log.d("Getting reCAPTCHA image from: " + uri.toString()); HttpURLConnection connection = (HttpURLConnection) uri.openConnection(); connection.setDoInput(true); connection.connect(); diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java index 9d0310c..38cd43e 100644 --- a/main/src/cgeo/geocaching/export/FieldnoteExport.java +++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java @@ -137,8 +137,8 @@ class FieldnoteExport extends AbstractExport { if (!onlyNew || onlyNew && log.date > Settings.getFieldnoteExportDate()) { appendFieldNote(fieldNoteBuffer, cache, log); } - publishProgress(++i); } + publishProgress(++i); } } catch (final Exception e) { Log.e("FieldnoteExport.ExportTask generation", e); diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java index 61be3c5..c31b1ae 100644 --- a/main/src/cgeo/geocaching/export/GpxExport.java +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -1,11 +1,12 @@ package cgeo.geocaching.export; import cgeo.geocaching.Geocache; -import cgeo.geocaching.settings.Settings; import cgeo.geocaching.R; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.utils.AsyncTaskWithProgress; +import cgeo.geocaching.utils.FileUtils; import cgeo.geocaching.utils.Log; import android.app.Activity; @@ -106,6 +107,12 @@ class GpxExport extends AbstractExport { this.activity = activity; } + private File getExportFile() { + final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US); + final Date now = new Date(); + return FileUtils.getUniqueNamedFile(Settings.getGpxExportDir() + File.separatorChar + "export_" + fileNameDateFormat.format(now) + ".gpx"); + } + @Override protected File doInBackgroundInternal(String[] geocodes) { // quick check for being able to write the GPX file @@ -117,8 +124,7 @@ class GpxExport extends AbstractExport { setMessage(cgeoapplication.getInstance().getResources().getQuantityString(R.plurals.cache_counts, allGeocodes.size(), allGeocodes.size())); - final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); - final File exportFile = new File(Settings.getGpxExportDir() + File.separatorChar + "export_" + fileNameDateFormat.format(new Date()) + ".gpx"); + final File exportFile = getExportFile(); BufferedWriter writer = null; try { final File exportLocation = new File(Settings.getGpxExportDir()); diff --git a/main/src/cgeo/geocaching/filter/DistanceFilter.java b/main/src/cgeo/geocaching/filter/DistanceFilter.java new file mode 100644 index 0000000..86b09c7 --- /dev/null +++ b/main/src/cgeo/geocaching/filter/DistanceFilter.java @@ -0,0 +1,56 @@ +package cgeo.geocaching.filter; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.R; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.geopoint.Geopoint; + +import java.util.ArrayList; +import java.util.List; + +class DistanceFilter extends AbstractFilter { + private final IGeoData geo; + private final int minDistance; + private final int maxDistance; + + public DistanceFilter(String name, final int minDistance, final int maxDistance) { + super(name); + this.minDistance = minDistance; + this.maxDistance = maxDistance; + geo = cgeoapplication.getInstance().currentGeo(); + } + + @Override + public boolean accepts(final Geocache cache) { + final Geopoint currentPos = new Geopoint(geo.getLocation()); + final float distance = currentPos.distanceTo(cache.getCoords()); + + return (distance >= minDistance) && (distance <= maxDistance); + } + + public static class Factory implements IFilterFactory { + + private static final int[] KILOMETERS = { 0, 2, 5, 10, 20, 50 }; + + @Override + public List<IFilter> getFilters() { + final List<IFilter> filters = new ArrayList<IFilter>(KILOMETERS.length); + for (int i = 0; i < KILOMETERS.length; i++) { + final int minRange = KILOMETERS[i]; + final int maxRange; + if (i < KILOMETERS.length - 1) { + maxRange = KILOMETERS[i + 1]; + } + else { + maxRange = Integer.MAX_VALUE; + } + final String range = maxRange == Integer.MAX_VALUE ? "> " + String.valueOf(minRange) : String.valueOf(minRange) + " - " + String.valueOf(maxRange); + final String name = cgeoapplication.getInstance().getResources().getQuantityString(R.plurals.tts_kilometers, maxRange, range); + filters.add(new DistanceFilter(name, minRange, maxRange)); + } + return filters; + } + + } +} diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java index 3556eef..2404f44 100644 --- a/main/src/cgeo/geocaching/filter/FilterUserInterface.java +++ b/main/src/cgeo/geocaching/filter/FilterUserInterface.java @@ -55,6 +55,7 @@ public final class FilterUserInterface { register(R.string.caches_filter_track, TrackablesFilter.class); register(R.string.caches_filter_modified, ModifiedFilter.class); register(R.string.caches_filter_origin, OriginFilter.Factory.class); + register(R.string.caches_filter_distance, DistanceFilter.Factory.class); // sort by localized names Collections.sort(registry, new Comparator<FactoryEntry>() { diff --git a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java index ece5c2f..ebf29d1 100644 --- a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java +++ b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java @@ -1,7 +1,13 @@ package cgeo.geocaching.loaders; import cgeo.geocaching.SearchResult; +import cgeo.geocaching.connector.gc.GCConstants; +import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.TextUtils; + +import org.apache.commons.lang3.StringUtils; import android.content.Context; import android.os.Handler; @@ -25,6 +31,7 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult> private Handler recaptchaHandler = null; private String recaptchaChallenge = null; + private String recaptchaKey = null; private String recaptchaText = null; private SearchResult search; private boolean loading; @@ -90,8 +97,27 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult> } @Override - public void setChallenge(String challenge) { - recaptchaChallenge = challenge; + public void setKey(String key) { + recaptchaKey = key; + } + + @Override + public String getKey() { + return recaptchaKey; + } + + @Override + public void fetchChallenge() { + recaptchaChallenge = null; + + if (StringUtils.isNotEmpty(recaptchaKey)) { + final Parameters params = new Parameters("k", getKey()); + final String recaptchaJs = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params)); + + if (StringUtils.isNotBlank(recaptchaJs)) { + recaptchaChallenge = TextUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true); + } + } } @Override diff --git a/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java b/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java index f64bf89..fd5189c 100644 --- a/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java +++ b/main/src/cgeo/geocaching/loaders/RecaptchaReceiver.java @@ -8,7 +8,11 @@ public interface RecaptchaReceiver { public String getChallenge(); - public void setChallenge(String challenge); + public void fetchChallenge(); + + public String getKey(); + + public void setKey(String key); public void notifyNeed(); diff --git a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java index 3ecd1b2..724ab80 100644 --- a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java +++ b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java @@ -92,7 +92,7 @@ public class CheckGcCredentialsPreference extends Preference { ImmutablePair<String, String> credentials = Settings.getGcLogin(); // check credentials for validity - if (credentials == null || StringUtils.isBlank(credentials.getLeft()) + if (StringUtils.isBlank(credentials.getLeft()) || StringUtils.isBlank(credentials.getRight())) { ActivityMixin.showToast(activity, R.string.err_missing_auth); return false; diff --git a/main/src/cgeo/geocaching/settings/EditPasswordPreference.java b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java index d89f128..20d0250 100644 --- a/main/src/cgeo/geocaching/settings/EditPasswordPreference.java +++ b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java @@ -10,7 +10,6 @@ import android.util.AttributeSet; * Use it exactly as an EditTextPreference * * @see SettingsActivity - search for EditPasswordPreference - * @author koem */ public class EditPasswordPreference extends EditTextPreference { diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java index 244c924..a4eeeec 100644 --- a/main/src/cgeo/geocaching/settings/Settings.java +++ b/main/src/cgeo/geocaching/settings/Settings.java @@ -267,8 +267,8 @@ public final class Settings { /** * Get login and password information. - * - * @return a pair (login, password) or null if no valid information is stored + * + * @return a pair either with (login, password) or (empty, empty) if no valid information is stored */ public static ImmutablePair<String, String> getGcLogin() { @@ -276,7 +276,7 @@ public final class Settings { final String password = getString(R.string.pref_password, null); if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { - return null; + return new ImmutablePair<String, String>(StringUtils.EMPTY, StringUtils.EMPTY); } return new ImmutablePair<String, String>(username, password); diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java index 4b1c92b..aa0848a 100644 --- a/main/src/cgeo/geocaching/settings/SettingsActivity.java +++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java @@ -9,6 +9,7 @@ import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; import cgeo.geocaching.compatibility.Compatibility; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.files.SimpleDirChooser; import cgeo.geocaching.maps.MapProviderFactory; import cgeo.geocaching.maps.interfaces.MapSource; @@ -56,7 +57,6 @@ import java.util.List; * guidelines and the <a href="http://developer.android.com/guide/topics/ui/settings.html">Settings API Guide</a> for * more information on developing a Settings UI. * - * @author koem (initial author) */ public class SettingsActivity extends PreferenceActivity { @@ -124,6 +124,7 @@ public class SettingsActivity extends PreferenceActivity { initDebugPreference(); initBasicMemberPreferences(); initSend2CgeoPreferences(); + initServicePreferences(); for (int k : new int[] { R.string.pref_username, R.string.pref_password, R.string.pref_pass_vote, R.string.pref_signature, @@ -136,6 +137,11 @@ public class SettingsActivity extends PreferenceActivity { } } + private void initServicePreferences() { + getPreference(R.string.pref_connectorOCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); + getPreference(R.string.pref_connectorGCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); + } + private static String getKey(final int prefKeyId) { return cgeoapplication.getInstance().getString(prefKeyId); } @@ -493,6 +499,17 @@ public class SettingsActivity extends PreferenceActivity { // simple string representation. preference.setSummary(stringValue); } + // reset log-in if gc user or password is changed + if (isPreference(preference, R.string.pref_username) || isPreference(preference, R.string.pref_password)) { + if (Login.isActualLoginStatus()) { + Login.logout(); + } + cgeoapplication.getInstance().checkLogin = true; + } + // reset log-in status if connector activation was changed + if (isPreference(preference, R.string.pref_connectorOCActive) || isPreference(preference, R.string.pref_connectorGCActive)) { + cgeoapplication.getInstance().checkLogin = true; + } return true; } }; @@ -546,4 +563,8 @@ public class SettingsActivity extends PreferenceActivity { public static void addPreferencesFromResource(final PreferenceActivity preferenceActivity, final int preferencesResId) { preferenceActivity.addPreferencesFromResource(preferencesResId); } + + private static boolean isPreference(final Preference preference, int preferenceKeyId) { + return getKey(preferenceKeyId).equals(preference.getKey()); + } } diff --git a/main/src/cgeo/geocaching/ui/EditNoteDialog.java b/main/src/cgeo/geocaching/ui/EditNoteDialog.java index 9a122e2..50cf57a 100644 --- a/main/src/cgeo/geocaching/ui/EditNoteDialog.java +++ b/main/src/cgeo/geocaching/ui/EditNoteDialog.java @@ -20,13 +20,15 @@ public class EditNoteDialog extends DialogFragment { public static final String ARGUMENT_INITIAL_NOTE = "initialNote"; private EditText mEditText; + private EditNoteDialogListener listener; - public static EditNoteDialog newInstance(final String initialNote) { + public static EditNoteDialog newInstance(final String initialNote, EditNoteDialogListener listener) { EditNoteDialog dialog = new EditNoteDialog(); Bundle arguments = new Bundle(); arguments.putString(EditNoteDialog.ARGUMENT_INITIAL_NOTE, initialNote); dialog.setArguments(arguments); + dialog.listener = listener; return dialog; } @@ -49,8 +51,7 @@ public class EditNoteDialog extends DialogFragment { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { - final EditNoteDialogListener activity = (EditNoteDialogListener) getActivity(); - activity.onFinishEditNoteDialog(mEditText.getText().toString()); + listener.onFinishEditNoteDialog(mEditText.getText().toString()); dialog.dismiss(); } }); diff --git a/main/src/cgeo/geocaching/utils/FileUtils.java b/main/src/cgeo/geocaching/utils/FileUtils.java index 5ab8fcc..0b358d2 100644 --- a/main/src/cgeo/geocaching/utils/FileUtils.java +++ b/main/src/cgeo/geocaching/utils/FileUtils.java @@ -1,6 +1,7 @@ package cgeo.geocaching.utils; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import android.os.Handler; import android.os.Message; @@ -11,8 +12,6 @@ import java.util.List; /** * Utility class for files * - * @author rsudev - * */ public final class FileUtils { @@ -65,4 +64,29 @@ public final class FileUtils { public abstract boolean shouldEnd(); } + + /** + * Create a unique non existing file named like the given file name. If a file with the given name already exists, + * add a number as suffix to the file name.<br> + * Example: For the file name "file.ext" this will return the first file of the list + * <ul> + * <li>file.ext</li> + * <li>file_2.ext</li> + * <li>file_3.ext</li> + * </ul> + * which does not yet exist. + */ + public static File getUniqueNamedFile(final String baseNameAndPath) { + String extension = StringUtils.substringAfterLast(baseNameAndPath, "."); + String pathName = StringUtils.substringBeforeLast(baseNameAndPath, "."); + int number = 1; + while (new File(getNumberedFileName(pathName, extension, number)).exists()) { + number++; + } + return new File(getNumberedFileName(pathName, extension, number)); + } + + private static String getNumberedFileName(String pathName, String extension, int number) { + return pathName + (number > 1 ? "_" + Integer.toString(number) : "") + "." + extension; + } } diff --git a/main/src/cgeo/geocaching/utils/MatcherWrapper.java b/main/src/cgeo/geocaching/utils/MatcherWrapper.java index c3c1663..78b1170 100644 --- a/main/src/cgeo/geocaching/utils/MatcherWrapper.java +++ b/main/src/cgeo/geocaching/utils/MatcherWrapper.java @@ -22,6 +22,10 @@ public class MatcherWrapper { return matcher.find(); } + public boolean find(int start) { + return matcher.find(start); + } + /** * see {@link Matcher#group(int)} */ diff --git a/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java b/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java index 94246e0..75c10ab 100644 --- a/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java +++ b/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java @@ -10,7 +10,7 @@ import android.os.Message; import java.lang.ref.WeakReference; public class SimpleCancellableHandler extends CancellableHandler { - public static final String SUCCESS_TEXT = "success_message"; + public static final String MESSAGE_TEXT = "message_text"; protected final WeakReference<AbstractActivity> activityRef; protected final WeakReference<Progress> progressDialogRef; @@ -22,13 +22,10 @@ public class SimpleCancellableHandler extends CancellableHandler { @Override public void handleRegularMessage(final Message msg) { AbstractActivity activity = activityRef.get(); - if (activity != null && msg.getData() != null && msg.getData().getString(SUCCESS_TEXT) != null) { - activity.showToast(msg.getData().getString(SUCCESS_TEXT)); - } - Progress progressDialog = progressDialogRef.get(); - if (progressDialog != null) { - progressDialog.dismiss(); + if (activity != null && msg.getData() != null && msg.getData().getString(MESSAGE_TEXT) != null) { + activity.showToast(msg.getData().getString(MESSAGE_TEXT)); } + dismissProgress(); return; } @@ -38,10 +35,7 @@ public class SimpleCancellableHandler extends CancellableHandler { if (activity != null) { activity.showToast((String) extra); } - Progress progressDialog = progressDialogRef.get(); - if (progressDialog != null) { - progressDialog.dismiss(); - } + dismissProgress(); } public final void showToast(int resId) { diff --git a/main/src/cgeo/geocaching/utils/SimpleHandler.java b/main/src/cgeo/geocaching/utils/SimpleHandler.java index 554ded6..b01d0e1 100644 --- a/main/src/cgeo/geocaching/utils/SimpleHandler.java +++ b/main/src/cgeo/geocaching/utils/SimpleHandler.java @@ -10,7 +10,7 @@ import android.os.Message; import java.lang.ref.WeakReference; public abstract class SimpleHandler extends Handler { - public static final String SUCCESS_TEXT = "success_message"; + public static final String MESSAGE_TEXT = "message_text"; protected final WeakReference<AbstractActivity> activityRef; protected final WeakReference<Progress> progressDialogRef; @@ -22,13 +22,10 @@ public abstract class SimpleHandler extends Handler { @Override public void handleMessage(final Message msg) { AbstractActivity activity = activityRef.get(); - if (activity != null && msg.getData() != null && msg.getData().getString(SUCCESS_TEXT) != null) { - activity.showToast(msg.getData().getString(SUCCESS_TEXT)); - } - Progress progressDialog = progressDialogRef.get(); - if (progressDialog != null) { - progressDialog.dismiss(); + if (activity != null && msg.getData() != null && msg.getData().getString(MESSAGE_TEXT) != null) { + activity.showToast(msg.getData().getString(MESSAGE_TEXT)); } + dismissProgress(); return; } |
