diff options
Diffstat (limited to 'main/src/cgeo/geocaching/CacheDetailActivity.java')
| -rw-r--r-- | main/src/cgeo/geocaching/CacheDetailActivity.java | 573 |
1 files changed, 219 insertions, 354 deletions
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 4068e38..55cfb2b 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -3,6 +3,7 @@ package cgeo.geocaching; import butterknife.ButterKnife; import butterknife.InjectView; +import cgeo.calendar.CalendarAddon; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.AbstractViewPagerActivity; import cgeo.geocaching.activity.Progress; @@ -20,6 +21,7 @@ import cgeo.geocaching.geopoint.Units; import cgeo.geocaching.list.StoredList; import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.network.Network; +import cgeo.geocaching.sensors.IGeoData; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.ui.AbstractCachingPageViewCreator; import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod; @@ -38,18 +40,14 @@ import cgeo.geocaching.ui.WeakReferenceHandler; import cgeo.geocaching.ui.dialog.Dialogs; import cgeo.geocaching.ui.logs.CacheLogsViewCreator; import cgeo.geocaching.utils.CancellableHandler; -import cgeo.geocaching.utils.ClipboardUtils; import cgeo.geocaching.utils.CryptUtils; -import cgeo.geocaching.utils.GeoDirHandler; -import cgeo.geocaching.utils.HtmlUtils; +import cgeo.geocaching.sensors.GeoDirHandler; import cgeo.geocaching.utils.ImageUtils; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.MatcherWrapper; -import cgeo.geocaching.utils.RunnableWithArgument; import cgeo.geocaching.utils.SimpleCancellableHandler; import cgeo.geocaching.utils.SimpleHandler; import cgeo.geocaching.utils.TextUtils; -import cgeo.geocaching.utils.TranslationUtils; import cgeo.geocaching.utils.UnknownTagsHandler; import org.apache.commons.collections4.CollectionUtils; @@ -57,6 +55,15 @@ import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; +import rx.Observable; +import rx.Observable.OnSubscribe; +import rx.Observer; +import rx.Scheduler.Inner; +import rx.Subscriber; +import rx.Subscription; +import rx.android.observables.AndroidObservable; +import rx.functions.Action1; +import rx.schedulers.Schedulers; import android.R.color; import android.app.AlertDialog; @@ -71,7 +78,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -80,7 +86,6 @@ import android.text.Editable; import android.text.Html; import android.text.Spannable; import android.text.Spanned; -import android.text.format.DateUtils; import android.text.style.ForegroundColorSpan; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; @@ -109,7 +114,6 @@ import android.widget.TextView.BufferType; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.EnumSet; import java.util.List; import java.util.Locale; @@ -141,7 +145,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc private final GeoDirHandler locationUpdater = new GeoDirHandler() { @Override - public void updateGeoData(final IGeoData geo) { + public void updateGeoDir(final IGeoData geo, final float dir) { if (cacheDistanceView == null) { return; } @@ -164,6 +168,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc private TextView cacheDistanceView; protected ImagesList imagesList; + private Subscription imagesSubscription; /** * waypoint selected in context menu. This variable will be gone when the waypoint context menu is a fragment. */ @@ -176,24 +181,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc // set title in code, as the activity needs a hard coded title due to the intent filters setTitle(res.getString(R.string.cache)); - String geocode = null; - - // TODO Why can it happen that search is not null? onCreate should be called only once and it is not set before. - if (search != null) { - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_ALL_DB_ONLY); - if (cache != null && cache.getGeocode() != null) { - geocode = cache.getGeocode(); - } - } - // get parameters final Bundle extras = getIntent().getExtras(); final Uri uri = getIntent().getData(); // try to get data from extras String name = null; + String geocode = null; String guid = null; - if (geocode == null && extras != null) { + if (extras != null) { geocode = extras.getString(Intents.EXTRA_GEOCODE); name = extras.getString(Intents.EXTRA_NAME); guid = extras.getString(Intents.EXTRA_GUID); @@ -305,8 +301,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } }); - // Initialization done. Let's load the data with the given information. - new LoadCacheThread(geocode, guid, loadCacheHandler).start(); + final String realGeocode = geocode; + final String realGuid = guid; + Schedulers.io().schedule(new Action1<Inner>() { + @Override + public void call(final Inner inner) { + search = Geocache.searchByGeocode(realGeocode, StringUtils.isBlank(realGeocode) ? realGuid : null, 0, false, loadCacheHandler); + loadCacheHandler.sendMessage(Message.obtain()); + } + }); } @Override @@ -317,13 +320,20 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void onResume() { - super.onResume(); + super.onResume(locationUpdater.start()); if (refreshOnResume) { notifyDataSetChanged(); refreshOnResume = false; } - locationUpdater.startGeo(); + } + + @Override + public void onDestroy() { + if (imagesList != null) { + imagesSubscription.unsubscribe(); + } + super.onDestroy(); } @Override @@ -336,7 +346,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void onPause() { - locationUpdater.stopGeo(); super.onPause(); } @@ -349,12 +358,12 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); final String itemTitle = (String) ((TextView) ((View) view.getParent()).findViewById(R.id.name)).getText(); - buildDetailsContextMenu(menu, itemTitle, true); + buildDetailsContextMenu(menu, clickedItemText, itemTitle, true); break; case R.id.shortdesc: assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); - buildDetailsContextMenu(menu, res.getString(R.string.cache_description), false); + buildDetailsContextMenu(menu, clickedItemText, res.getString(R.string.cache_description), false); break; case R.id.longdesc: assert view instanceof TextView; @@ -365,22 +374,28 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } else { clickedItemText = shortDesc + "\n\n" + ((TextView) view).getText(); } - buildDetailsContextMenu(menu, res.getString(R.string.cache_description), false); + buildDetailsContextMenu(menu, clickedItemText, res.getString(R.string.cache_description), false); break; case R.id.personalnote: assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); - buildDetailsContextMenu(menu, res.getString(R.string.cache_personal_note), true); + buildDetailsContextMenu(menu, clickedItemText, res.getString(R.string.cache_personal_note), true); break; case R.id.hint: assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); - buildDetailsContextMenu(menu, res.getString(R.string.cache_hint), false); + buildDetailsContextMenu(menu, clickedItemText, res.getString(R.string.cache_hint), false); break; case R.id.log: assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); - buildDetailsContextMenu(menu, res.getString(R.string.cache_logs), false); + buildDetailsContextMenu(menu, clickedItemText, res.getString(R.string.cache_logs), false); + break; + case R.id.date: // event date + assert view instanceof TextView; + clickedItemText = ((TextView) view).getText(); + buildDetailsContextMenu(menu, clickedItemText, res.getString(R.string.cache_event), true); + menu.findItem(R.id.menu_calendar).setVisible(cache.canBeAddedToCalendar()); break; case R.id.waypoint: menu.setHeaderTitle(selectedWaypoint.getName() + " (" + res.getString(R.string.waypoint) + ")"); @@ -406,41 +421,13 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } } - private void buildDetailsContextMenu(ContextMenu menu, String fieldTitle, boolean copyOnly) { - menu.setHeaderTitle(fieldTitle); - getMenuInflater().inflate(R.menu.details_context, menu); - menu.findItem(R.id.menu_translate_to_sys_lang).setVisible(!copyOnly); - if (!copyOnly) { - if (clickedItemText.length() > TranslationUtils.TRANSLATION_TEXT_LENGTH_WARN) { - showToast(res.getString(R.string.translate_length_warning)); - } - menu.findItem(R.id.menu_translate_to_sys_lang).setTitle(res.getString(R.string.translate_to_sys_lang, Locale.getDefault().getDisplayLanguage())); - } - final boolean localeIsEnglish = StringUtils.equals(Locale.getDefault().getLanguage(), Locale.ENGLISH.getLanguage()); - menu.findItem(R.id.menu_translate_to_english).setVisible(!copyOnly && !localeIsEnglish); - } - @Override public boolean onContextItemSelected(MenuItem item) { + if (onClipboardItemSelected(item, clickedItemText)) { + return true; + } switch (item.getItemId()) { - // detail fields - case R.id.menu_copy: - ClipboardUtils.copyToClipboard(clickedItemText); - showToast(res.getString(R.string.clipboard_copy_ok)); - return true; - case R.id.menu_translate_to_sys_lang: - TranslationUtils.startActivityTranslate(this, Locale.getDefault().getLanguage(), HtmlUtils.extractText(clickedItemText)); - return true; - case R.id.menu_translate_to_english: - TranslationUtils.startActivityTranslate(this, Locale.ENGLISH.getLanguage(), HtmlUtils.extractText(clickedItemText)); - return true; - case R.id.menu_cache_share_field: - final Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - intent.putExtra(Intent.EXTRA_TEXT, clickedItemText.toString()); - startActivity(Intent.createChooser(intent, res.getText(R.string.cache_share_field))); - return true; - // waypoints + // waypoints case R.id.menu_waypoint_edit: if (selectedWaypoint != null) { EditWaypointActivity.startActivityEditWaypoint(this, cache, selectedWaypoint.getId()); @@ -484,6 +471,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc new ResetCoordsThread(cache, handler, selectedWaypoint, true, false, progressDialog).start(); } return true; + case R.id.menu_calendar: + CalendarAddon.addToCalendarWithIntent(this, cache); + return true; default: break; } @@ -542,20 +532,19 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { updateStatusMsg((String) msg.obj); } else { - CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get()); + final CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get()); if (activity == null) { return; } - SearchResult search = activity.getSearch(); - if (search == null) { + if (activity.search == null) { showToast(R.string.err_dwld_details_failed); dismissProgress(); finishActivity(); return; } - if (search.getError() != null) { - activity.showToast(activity.getResources().getString(R.string.err_dwld_details_failed) + " " + search.getError().getErrorString(activity.getResources()) + "."); + if (activity.search.getError() != null) { + activity.showToast(activity.getResources().getString(R.string.err_dwld_details_failed) + " " + activity.search.getError().getErrorString(activity.getResources()) + "."); dismissProgress(); finishActivity(); return; @@ -620,37 +609,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } /** - * Loads the cache with the given geocode or guid. - */ - private class LoadCacheThread extends Thread { - - private CancellableHandler handler = null; - private String geocode; - private String guid; - - public LoadCacheThread(final String geocode, final String guid, final CancellableHandler handlerIn) { - handler = handlerIn; - - if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid)) { - showToast(res.getString(R.string.err_detail_cache_forgot)); - - progress.dismiss(); - finish(); - return; - } - - this.geocode = geocode; - this.guid = guid; - } - - @Override - public void run() { - search = Geocache.searchByGeocode(geocode, StringUtils.isBlank(geocode) ? guid : null, 0, false, handler); - handler.sendMessage(Message.obtain()); - } - } - - /** * Tries to navigate to the {@link Geocache} of this activity. */ private void startDefaultNavigation() { @@ -691,7 +649,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc return; } imagesList = new ImagesList(this, cache.getGeocode()); - imagesList.loadImages(imageView, cache.getImages(), false); + imagesSubscription = imagesList.loadImages(imageView, cache.getImages(), false); } public static void startActivity(final Context context, final String geocode) { @@ -908,8 +866,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc */ private LinearLayout detailsList; - // TODO Do we need this thread-references? - private RefreshCacheThread refreshThread; private Thread watchlistThread; @Override @@ -922,9 +878,17 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc view = (ScrollView) getLayoutInflater().inflate(R.layout.cachedetail_details_page, null); // Start loading preview map - if (Settings.isStoreOfflineMaps()) { - new PreviewMapTask().execute((Void) null); - } + AndroidObservable.fromActivity(CacheDetailActivity.this, previewMap.subscribeOn(Schedulers.io())).subscribe(new Action1<BitmapDrawable>() { + @Override + public void call(final BitmapDrawable image) { + final Bitmap bitmap = image.getBitmap(); + if (bitmap != null && bitmap.getWidth() > 10) { + final ImageView imageView = (ImageView) view.findViewById(R.id.map_preview); + imageView.setImageDrawable(image); + view.findViewById(R.id.map_preview_box).setVisibility(View.VISIBLE); + } + } + }); detailsList = (LinearLayout) view.findViewById(R.id.details_list); final CacheDetailsCreator details = new CacheDetailsCreator(CacheDetailActivity.this, detailsList); @@ -972,17 +936,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc ownerView.setOnClickListener(new OwnerActionsClickListener(cache)); } - // cache hidden - final Date hiddenDate = cache.getHiddenDate(); - if (hiddenDate != null) { - final long time = hiddenDate.getTime(); - if (time > 0) { - String dateString = Formatter.formatFullDate(time); - if (cache.isEventCache()) { - dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString; - } - details.add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString); - } + // hidden or event date + final TextView hiddenView = details.addHiddenDate(cache); + if (hiddenView != null) { + registerForContextMenu(hiddenView); } // cache location @@ -1051,9 +1008,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc if (Settings.getChooseList()) { // let user select list to store cache in new StoredList.UserInterface(CacheDetailActivity.this).promptForListSelection(R.string.list_title, - new RunnableWithArgument<Integer>() { + new Action1<Integer>() { @Override - public void run(final Integer selectedListId) { + public void call(final Integer selectedListId) { storeCache(selectedListId, new StoreCacheHandler(CacheDetailActivity.this, progress)); } }, true, StoredList.TEMPORARY_LIST_ID); @@ -1081,27 +1038,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true, refreshCacheHandler.cancelMessage()); - if (refreshThread != null) { - refreshThread.interrupt(); - } - - refreshThread = new RefreshCacheThread(refreshCacheHandler); - refreshThread.start(); - } - } - - private class RefreshCacheThread extends Thread { - final private CancellableHandler handler; - - public RefreshCacheThread(final CancellableHandler handler) { - this.handler = handler; - } - - @Override - public void run() { - cache.refresh(cache.getListId(), handler); - refreshThread = null; - handler.sendEmptyMessage(0); + cache.refresh(cache.getListId(), refreshCacheHandler, Schedulers.io()); } } @@ -1114,20 +1051,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } progress.show(CacheDetailActivity.this, res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true, null); - new DropCacheThread(new ChangeNotificationHandler(CacheDetailActivity.this, progress)).start(); - } - } - - private class DropCacheThread extends Thread { - private Handler handler; - - public DropCacheThread(Handler handler) { - this.handler = handler; - } - - @Override - public void run() { - cache.drop(this.handler); + cache.drop(new ChangeNotificationHandler(CacheDetailActivity.this, progress), Schedulers.io()); } } @@ -1302,9 +1226,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void onClick(View view) { new StoredList.UserInterface(CacheDetailActivity.this).promptForListSelection(R.string.list_title, - new RunnableWithArgument<Integer>() { + new Action1<Integer>() { @Override - public void run(final Integer selectedListId) { + public void call(final Integer selectedListId) { switchListById(selectedListId); } }, true, cache.getListId()); @@ -1368,7 +1292,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc final LinearLayout layout = (LinearLayout) view.findViewById(R.id.favpoint_box); final boolean supportsFavoritePoints = cache.supportsFavoritePoints(); layout.setVisibility(supportsFavoritePoints ? View.VISIBLE : View.GONE); - if (!supportsFavoritePoints || cache.isOwner() || !Settings.isPremiumMember()) { + if (!supportsFavoritePoints || cache.isOwner() || !Settings.isGCPremiumMember()) { return; } final Button buttonAdd = (Button) view.findViewById(R.id.add_to_favpoint); @@ -1418,58 +1342,41 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc box.setVisibility(View.GONE); } } + } - private class PreviewMapTask extends AsyncTask<Void, Void, BitmapDrawable> { - @Override - protected BitmapDrawable doInBackground(Void... parameters) { - try { - // persistent preview from storage - Bitmap image = decode(cache); + private Observable<BitmapDrawable> previewMap = Observable.create(new OnSubscribe<BitmapDrawable>() { + @Override + public void call(final Subscriber<? super BitmapDrawable> subscriber) { + try { + // persistent preview from storage + Bitmap image = StaticMapsProvider.getPreviewMap(cache); - if (image == null) { + if (image == null) { + if (Settings.isStoreOfflineMaps()) { StaticMapsProvider.storeCachePreviewMap(cache); - image = decode(cache); - if (image == null) { - return null; - } + image = StaticMapsProvider.getPreviewMap(cache); } - - return ImageUtils.scaleBitmapToFitDisplay(image); - } catch (final Exception e) { - Log.w("CacheDetailActivity.PreviewMapTask", e); - return null; } - } - private Bitmap decode(final Geocache cache) { - return StaticMapsProvider.getPreviewMap(cache.getGeocode()); - } - - @Override - protected void onPostExecute(BitmapDrawable image) { - if (image == null) { - return; - } - - try { - final Bitmap bitmap = image.getBitmap(); - if (bitmap == null || bitmap.getWidth() <= 10) { - return; - } - - final ImageView imageView = (ImageView) view.findViewById(R.id.map_preview); - imageView.setImageDrawable(image); - view.findViewById(R.id.map_preview_box).setVisibility(View.VISIBLE); - } catch (final Exception e) { - Log.e("CacheDetailActivity.PreviewMapTask", e); + if (image != null) { + subscriber.onNext(ImageUtils.scaleBitmapToFitDisplay(image)); } + subscriber.onCompleted(); + } catch (final Exception e) { + Log.w("CacheDetailActivity.previewMap", e); + subscriber.onError(e); } } - } + + }); protected class DescriptionViewCreator extends AbstractCachingPageViewCreator<ScrollView> { @InjectView(R.id.personalnote) protected TextView personalNoteView; + @InjectView(R.id.shortdesc) protected IndexOutOfBoundsAvoidingTextView shortDescView; + @InjectView(R.id.longdesc) protected IndexOutOfBoundsAvoidingTextView longDescView; + @InjectView(R.id.show_description) protected Button showDesc; + @InjectView(R.id.loading) protected View loadingView; @Override public ScrollView getDispatchedView() { @@ -1483,7 +1390,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc // cache short description if (StringUtils.isNotBlank(cache.getShortDescription())) { - new LoadDescriptionTask(cache.getShortDescription(), view.findViewById(R.id.shortdesc), null, null).execute(); + loadDescription(cache.getShortDescription(), shortDescView, null); } // long description @@ -1491,7 +1398,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc if (Settings.isAutoLoadDescription()) { loadLongDescription(); } else { - final Button showDesc = (Button) view.findViewById(R.id.show_description); showDesc.setVisibility(View.VISIBLE); showDesc.setOnClickListener(new View.OnClickListener() { @Override @@ -1605,12 +1511,23 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } private void loadLongDescription() { - final Button showDesc = (Button) view.findViewById(R.id.show_description); showDesc.setVisibility(View.GONE); showDesc.setOnClickListener(null); view.findViewById(R.id.loading).setVisibility(View.VISIBLE); - new LoadDescriptionTask(cache.getDescription(), view.findViewById(R.id.longdesc), view.findViewById(R.id.loading), view.findViewById(R.id.shortdesc)).execute(); + final String longDescription = cache.getDescription(); + loadDescription(longDescription, longDescView, loadingView); + + // Hide the short description, if it is contained somewhere at the start of the long description. + if (shortDescView != null) { + final String shortDescription = cache.getShortDescription(); + if (StringUtils.isNotBlank(shortDescription)) { + final int index = longDescription.indexOf(shortDescription); + if (index >= 0 && index < 200) { + shortDescView.setVisibility(View.GONE); + } + } + } } private void warnPersonalNoteNeedsStoring() { @@ -1641,148 +1558,118 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } - /** - * Loads the description in background. <br /> - * <br /> - * Params: - * <ol> - * <li>description string (String)</li> - * <li>target description view (TextView)</li> - * <li>loading indicator view (View, may be null)</li> - * </ol> - */ - private class LoadDescriptionTask extends AsyncTask<Object, Void, Void> { - private final View loadingIndicatorView; - private final IndexOutOfBoundsAvoidingTextView descriptionView; - private final String descriptionString; - private Spanned description; - private final View shortDescView; + /** + * Load the description in the background. + * @param descriptionString the HTML description as retrieved from the connector + * @param descriptionView the view to fill + * @param loadingIndicatorView the loading indicator view, will be hidden when completed + */ + private void loadDescription(final String descriptionString, final IndexOutOfBoundsAvoidingTextView descriptionView, final View loadingIndicatorView) { + // The producer produces successives (without then with images) versions of the description. + final Observable<Spanned> producer = Observable.create(new OnSubscribe<Spanned>() { + @Override + public void call(final Subscriber<? super Spanned> subscriber) { + try { + // Fast preview: parse only HTML without loading any images + final HtmlImageCounter imageCounter = new HtmlImageCounter(); + final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler(); + Spanned description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler); + addWarning(unknownTagsHandler, description); + subscriber.onNext(description); + + if (imageCounter.getImageCount() > 0) { + // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview + description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler); + addWarning(unknownTagsHandler, description); + subscriber.onNext(description); + } - public LoadDescriptionTask(final String description, final View descriptionView, final View loadingIndicatorView, final View shortDescView) { - assert descriptionView instanceof IndexOutOfBoundsAvoidingTextView; - this.descriptionString = description; - this.descriptionView = (IndexOutOfBoundsAvoidingTextView) descriptionView; - this.loadingIndicatorView = loadingIndicatorView; - this.shortDescView = shortDescView; - } + subscriber.onCompleted(); + } catch (final Exception e) { + Log.e("loadDescription", e); + subscriber.onError(e); + } + } - @Override - protected Void doInBackground(Object... params) { - try { - // Fast preview: parse only HTML without loading any images - final HtmlImageCounter imageCounter = new HtmlImageCounter(); - final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler(); - description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler); - publishProgress(); - - boolean needsRefresh = false; - if (imageCounter.getImageCount() > 0) { - // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview - description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler); - needsRefresh = true; - } - - // If description has an HTML construct which may be problematic to render, add a note at the end of the long description. - // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though - // sometimes technically incorrect. - if (unknownTagsHandler.isProblematicDetected() && descriptionView != null) { + // If description has an HTML construct which may be problematic to render, add a note at the end of the long description. + // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though + // sometimes technically incorrect. + private void addWarning(final UnknownTagsHandler unknownTagsHandler, final Spanned description) { + if (unknownTagsHandler.isProblematicDetected()) { final int startPos = description.length(); final IConnector connector = ConnectorFactory.getConnector(cache); final Spanned tableNote = Html.fromHtml(res.getString(R.string.cache_description_table_note, "<a href=\"" + cache.getUrl() + "\">" + connector.getName() + "</a>")); ((Editable) description).append("\n\n").append(tableNote); ((Editable) description).setSpan(new StyleSpan(Typeface.ITALIC), startPos, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - needsRefresh = true; } - - if (needsRefresh) { - publishProgress(); - } - } catch (final Exception e) { - Log.e("LoadDescriptionTask: ", e); - } - return null; - } - - @Override - protected void onProgressUpdate(Void... values) { - if (description == null) { - showToast(res.getString(R.string.err_load_descr_failed)); - return; - } - if (StringUtils.isNotBlank(descriptionString)) { - try { - descriptionView.setText(description, TextView.BufferType.SPANNABLE); - } catch (final Exception e) { - // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412 - Log.e("Android bug setting text: ", e); - // remove the formatting by converting to a simple string - descriptionView.setText(description.toString()); - } - descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); - fixTextColor(descriptionView, descriptionString); - descriptionView.setVisibility(View.VISIBLE); - registerForContextMenu(descriptionView); - - hideDuplicatedShortDescription(); } - } + }); - /** - * Hide the short description, if it is contained somewhere at the start of the long description. - */ - private void hideDuplicatedShortDescription() { - if (shortDescView != null) { - final String shortDescription = cache.getShortDescription(); - if (StringUtils.isNotBlank(shortDescription)) { - final int index = descriptionString.indexOf(shortDescription); - if (index >= 0 && index < 200) { - shortDescView.setVisibility(View.GONE); + AndroidObservable.fromActivity(this, producer.subscribeOn(Schedulers.io())) + .subscribe(new Observer<Spanned>() { + @Override + public void onCompleted() { + if (null != loadingIndicatorView) { + loadingIndicatorView.setVisibility(View.GONE); + } } - } - } - } - @Override - protected void onPostExecute(Void result) { - if (null != loadingIndicatorView) { - loadingIndicatorView.setVisibility(View.GONE); - } - } + @Override + public void onError(final Throwable throwable) { + showToast(res.getString(R.string.err_load_descr_failed)); + } - /** - * Handle caches with black font color in dark skin and white font color in light skin - * by changing background color of the view - * - * @param view - * containing the text - * @param text - * to be checked - */ - private void fixTextColor(final TextView view, final String text) { - int backcolor; - if (Settings.isLightSkin()) { - backcolor = color.white; - - for (final Pattern pattern : LIGHT_COLOR_PATTERNS) { - final MatcherWrapper matcher = new MatcherWrapper(pattern, text); - if (matcher.find()) { - view.setBackgroundResource(color.darker_gray); - return; + @Override + public void onNext(final Spanned description) { + if (StringUtils.isNotBlank(descriptionString)) { + try { + descriptionView.setText(description, TextView.BufferType.SPANNABLE); + } catch (final Exception e) { + // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412 + Log.e("Android bug setting text: ", e); + // remove the formatting by converting to a simple string + descriptionView.setText(description.toString()); + } + descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); + fixTextColor(descriptionString); + descriptionView.setVisibility(View.VISIBLE); + registerForContextMenu(descriptionView); + } } - } - } else { - backcolor = color.black; - for (final Pattern pattern : DARK_COLOR_PATTERNS) { - final MatcherWrapper matcher = new MatcherWrapper(pattern, text); - if (matcher.find()) { - view.setBackgroundResource(color.darker_gray); - return; + /** + * Handle caches with black font color in dark skin and white font color in light skin + * by changing background color of the view + * + * @param text + * to be checked + */ + private void fixTextColor(final String text) { + int backcolor; + if (Settings.isLightSkin()) { + backcolor = color.white; + + for (final Pattern pattern : LIGHT_COLOR_PATTERNS) { + final MatcherWrapper matcher = new MatcherWrapper(pattern, text); + if (matcher.find()) { + descriptionView.setBackgroundResource(color.darker_gray); + return; + } + } + } else { + backcolor = color.black; + + for (final Pattern pattern : DARK_COLOR_PATTERNS) { + final MatcherWrapper matcher = new MatcherWrapper(pattern, text); + if (matcher.find()) { + descriptionView.setBackgroundResource(color.darker_gray); + return; + } + } + } + descriptionView.setBackgroundResource(backcolor); } - } - } - view.setBackgroundResource(backcolor); - } + }); } private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ListView> { @@ -1882,6 +1769,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc // note final TextView noteView = holder.noteView; if (StringUtils.isNotBlank(wpt.getNote())) { + noteView.setOnClickListener(new DecryptTextClickListener(noteView)); noteView.setVisibility(View.VISIBLE); if (TextUtils.containsHtml(wpt.getNote())) { noteView.setText(Html.fromHtml(wpt.getNote()), TextView.BufferType.SPANNABLE); @@ -2255,10 +2143,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc return cache; } - public SearchResult getSearch() { - return search; - } - private static class StoreCacheHandler extends SimpleCancellableHandler { public StoreCacheHandler(CacheDetailActivity activity, Progress progress) { @@ -2326,33 +2210,14 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } } - private StoreCacheThread storeThread; - - 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; - } - } - protected void storeCache(final int listId, final StoreCacheHandler storeCacheHandler) { progress.show(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(); + Schedulers.io().schedule(new Action1<Inner>() { + @Override + public void call(final Inner inner) { + cache.store(listId, storeCacheHandler); + } + }); } private static final class StoreCachePersonalNoteHandler extends StoreCacheHandler { |
