diff options
| author | Bananeweizen <bananeweizen@gmx.de> | 2013-06-22 20:51:14 +0200 |
|---|---|---|
| committer | Bananeweizen <bananeweizen@gmx.de> | 2013-06-23 09:08:21 +0200 |
| commit | 9e9e7c2f8ce38be8b1a02a8b8632f919fa81d203 (patch) | |
| tree | 9739a96c9891a62745f7cee0dff5ed63ccf739dd /main/src/cgeo/geocaching/ui | |
| parent | ec9af65d1d5130b0c046c58b964dfd04944eb218 (diff) | |
| download | cgeo-9e9e7c2f8ce38be8b1a02a8b8632f919fa81d203.zip cgeo-9e9e7c2f8ce38be8b1a02a8b8632f919fa81d203.tar.gz cgeo-9e9e7c2f8ce38be8b1a02a8b8632f919fa81d203.tar.bz2 | |
#2910: remove code duplication in logs views
Diffstat (limited to 'main/src/cgeo/geocaching/ui')
8 files changed, 425 insertions, 7 deletions
diff --git a/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java index b5e5c9a..b717568 100644 --- a/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java +++ b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java @@ -1,6 +1,5 @@ package cgeo.geocaching.ui; -import cgeo.geocaching.Geocache; import cgeo.geocaching.R; import cgeo.geocaching.cgeocaches; import cgeo.geocaching.activity.AbstractActivity; @@ -15,10 +14,10 @@ import android.view.View; abstract class AbstractUserClickListener implements View.OnClickListener { - protected final Geocache cache; + private final boolean enabled; - public AbstractUserClickListener(final Geocache cache) { - this.cache = cache; + public AbstractUserClickListener(final boolean enabled) { + this.enabled = enabled; } @Override @@ -26,7 +25,7 @@ abstract class AbstractUserClickListener implements View.OnClickListener { if (view == null) { return; } - if (!cache.supportsUserActions()) { + if (!enabled) { return; } diff --git a/main/src/cgeo/geocaching/ui/HtmlImageCounter.java b/main/src/cgeo/geocaching/ui/HtmlImageCounter.java new file mode 100644 index 0000000..24b70ea --- /dev/null +++ b/main/src/cgeo/geocaching/ui/HtmlImageCounter.java @@ -0,0 +1,19 @@ +package cgeo.geocaching.ui; + +import android.graphics.drawable.Drawable; +import android.text.Html; + +public class HtmlImageCounter implements Html.ImageGetter { + + private int imageCount = 0; + + @Override + public Drawable getDrawable(String url) { + imageCount++; + return null; + } + + public int getImageCount() { + return imageCount; + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java index e7b04a5..45ce237 100644 --- a/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java +++ b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java @@ -12,8 +12,11 @@ import android.widget.TextView; */ public class OwnerActionsClickListener extends AbstractUserClickListener { + private final Geocache cache; + public OwnerActionsClickListener(Geocache cache) { - super(cache); + super(cache.supportsUserActions()); + this.cache = cache; } @Override diff --git a/main/src/cgeo/geocaching/ui/UserActionsClickListener.java b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java index 8235446..292074e 100644 --- a/main/src/cgeo/geocaching/ui/UserActionsClickListener.java +++ b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java @@ -11,7 +11,11 @@ import android.widget.TextView; public class UserActionsClickListener extends AbstractUserClickListener { public UserActionsClickListener(Geocache cache) { - super(cache); + super(cache.supportsUserActions()); + } + + public UserActionsClickListener() { + super(true); } @Override diff --git a/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java new file mode 100644 index 0000000..a785681 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java @@ -0,0 +1,101 @@ +package cgeo.geocaching.ui.logs; + +import cgeo.geocaching.CacheDetailActivity; +import cgeo.geocaching.Geocache; +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.ui.UserActionsClickListener; + +import org.apache.commons.lang3.StringUtils; + +import android.content.res.Resources; +import android.view.View; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class CacheLogsViewCreator extends LogsViewCreator { + private final boolean allLogs; + private final Geocache cache; + private final Resources res = cgeoapplication.getInstance().getResources(); + + public CacheLogsViewCreator(CacheDetailActivity cacheDetailActivity, final Geocache cache, boolean allLogs) { + super(cacheDetailActivity); + this.cache = cache; + this.allLogs = allLogs; + } + + @Override + protected List<LogEntry> getLogs() { + return allLogs ? cache.getLogs() : cache.getFriendsLogs(); + } + + @Override + protected void addHeaderView() { + // adds the log counts + final Map<LogType, Integer> logCounts = cache.getLogCounts(); + if (logCounts != null) { + final List<Entry<LogType, Integer>> sortedLogCounts = new ArrayList<Entry<LogType, Integer>>(logCounts.size()); + for (final Entry<LogType, Integer> entry : logCounts.entrySet()) { + // it may happen that the label is unknown -> then avoid any output for this type + if (entry.getKey() != LogType.PUBLISH_LISTING && entry.getKey().getL10n() != null) { + sortedLogCounts.add(entry); + } + } + + if (!sortedLogCounts.isEmpty()) { + // sort the log counts by type id ascending. that way the FOUND, DNF log types are the first and most visible ones + Collections.sort(sortedLogCounts, new Comparator<Entry<LogType, Integer>>() { + + @Override + public int compare(Entry<LogType, Integer> logCountItem1, Entry<LogType, Integer> logCountItem2) { + return logCountItem1.getKey().compareTo(logCountItem2.getKey()); + } + }); + + final ArrayList<String> labels = new ArrayList<String>(sortedLogCounts.size()); + for (final Entry<LogType, Integer> pair : sortedLogCounts) { + labels.add(pair.getValue() + "× " + pair.getKey().getL10n()); + } + + final TextView countView = new TextView(activity); + countView.setText(res.getString(R.string.cache_log_types) + ": " + StringUtils.join(labels, ", ")); + view.addHeaderView(countView, null, false); + } + } + } + + @Override + protected void fillCountOrLocation(LogViewHolder holder, final LogEntry log) { + // finds count + if (log.found == -1) { + holder.countOrLocation.setVisibility(View.GONE); + } else { + holder.countOrLocation.setVisibility(View.VISIBLE); + holder.countOrLocation.setText(res.getQuantityString(R.plurals.cache_counts, log.found, log.found)); + } + } + + @Override + protected boolean isValid() { + return cache != null; + } + + @Override + protected String getGeocode() { + return cache.getGeocode(); + } + + @Override + protected UserActionsClickListener createUserActionsListener() { + return new UserActionsClickListener(cache); + } + +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/ui/logs/LogViewHolder.java b/main/src/cgeo/geocaching/ui/logs/LogViewHolder.java new file mode 100644 index 0000000..16f5537 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/logs/LogViewHolder.java @@ -0,0 +1,47 @@ +package cgeo.geocaching.ui.logs; + +import butterknife.InjectView; + +import cgeo.geocaching.R; +import cgeo.geocaching.ui.AbstractViewHolder; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +public class LogViewHolder extends AbstractViewHolder { + @InjectView(R.id.added) protected TextView date ; + @InjectView(R.id.type) protected TextView type; + @InjectView(R.id.author) protected TextView author; + @InjectView(R.id.count_or_location) protected TextView countOrLocation; + @InjectView(R.id.log) protected TextView text; + @InjectView(R.id.log_images) protected TextView images; + @InjectView(R.id.log_mark) protected ImageView marker; + + private int position; + + public LogViewHolder(View rowView) { + super(rowView); + } + + /** + * Read the position of the cursor pointed to by this holder. <br/> + * This must be called by the UI thread. + * + * @return the cursor position + */ + public int getPosition() { + return position; + } + + /** + * Set the position of the cursor pointed to by this holder. <br/> + * This must be called by the UI thread. + * + * @param position + * the cursor position + */ + public void setPosition(final int position) { + this.position = position; + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java new file mode 100644 index 0000000..ee2713a --- /dev/null +++ b/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java @@ -0,0 +1,175 @@ +package cgeo.geocaching.ui.logs; + +import cgeo.geocaching.Image; +import cgeo.geocaching.ImagesActivity; +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.StoredList; +import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.activity.Progress; +import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.ui.AbstractCachingPageViewCreator; +import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod; +import cgeo.geocaching.ui.DecryptTextClickListener; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.ui.HtmlImageCounter; +import cgeo.geocaching.ui.UserActionsClickListener; +import cgeo.geocaching.utils.TextUtils; +import cgeo.geocaching.utils.UnknownTagsHandler; + +import org.apache.commons.lang3.StringEscapeUtils; + +import android.os.AsyncTask; +import android.text.Html; +import android.text.Spanned; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +public abstract class LogsViewCreator extends AbstractCachingPageViewCreator<ListView> { + + protected final AbstractActivity activity; + + public LogsViewCreator(AbstractActivity activity) { + this.activity = activity; + } + + @Override + public ListView getDispatchedView() { + if (!isValid()) { + return null; + } + + final List<LogEntry> logs = getLogs(); + + view = (ListView) activity.getLayoutInflater().inflate(R.layout.logs_page, null); + addHeaderView(); + view.setAdapter(new ArrayAdapter<LogEntry>(activity, R.layout.logs_item, logs) { + + @Override + public View getView(final int position, final View convertView, final android.view.ViewGroup parent) { + View rowView = convertView; + if (null == rowView) { + rowView = activity.getLayoutInflater().inflate(R.layout.logs_item, null); + } + LogViewHolder holder = (LogViewHolder) rowView.getTag(); + if (null == holder) { + holder = new LogViewHolder(rowView); + } + holder.setPosition(position); + + final LogEntry log = getItem(position); + fillViewHolder(convertView, holder, log); + return rowView; + } + }); + + return view; + } + + protected void fillViewHolder(final View convertView, LogViewHolder holder, final LogEntry log) { + if (log.date > 0) { + holder.date.setText(Formatter.formatShortDateVerbally(log.date)); + holder.date.setVisibility(View.VISIBLE); + } else { + holder.date.setVisibility(View.GONE); + } + + holder.type.setText(log.type.getL10n()); + holder.author.setText(StringEscapeUtils.unescapeHtml4(log.author)); + + fillCountOrLocation(holder, log); + + // logtext, avoid parsing HTML if not necessary + String logText = log.log; + if (TextUtils.containsHtml(logText)) { + logText = log.getDisplayText(); + // Fast preview: parse only HTML without loading any images + final HtmlImageCounter imageCounter = new HtmlImageCounter(); + final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler(); + holder.text.setText(Html.fromHtml(logText, imageCounter, unknownTagsHandler), TextView.BufferType.SPANNABLE); + 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 + final LogImageLoader loader = new LogImageLoader(holder); + loader.execute(logText); + } + } + else { + holder.text.setText(logText, TextView.BufferType.SPANNABLE); + } + + // images + if (log.hasLogImages()) { + holder.images.setText(log.getImageTitles()); + holder.images.setVisibility(View.VISIBLE); + holder.images.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ImagesActivity.startActivityLogImages(activity, getGeocode(), new ArrayList<Image>(log.getLogImages())); + } + }); + } else { + holder.images.setVisibility(View.GONE); + } + + // colored marker + final int marker = log.type.markerId; + if (marker != 0) { + holder.marker.setVisibility(View.VISIBLE); + holder.marker.setImageResource(marker); + } + else { + holder.marker.setVisibility(View.GONE); + } + + if (null == convertView) { + holder.author.setOnClickListener(createUserActionsListener()); + holder.text.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); + holder.text.setOnClickListener(new DecryptTextClickListener()); + activity.registerForContextMenu(holder.text); + } + } + + abstract protected UserActionsClickListener createUserActionsListener(); + + abstract protected String getGeocode(); + + abstract protected List<LogEntry> getLogs(); + + abstract protected void addHeaderView(); + + abstract protected void fillCountOrLocation(LogViewHolder holder, final LogEntry log); + + abstract protected boolean isValid(); + + /** Loads the Log Images outside the ui thread. */ + + private class LogImageLoader extends AsyncTask<String, Progress, Spanned> { + final private LogViewHolder holder; + final private int position; + + public LogImageLoader(LogViewHolder holder) { + this.holder = holder; + this.position = holder.getPosition(); + } + + @Override + protected Spanned doInBackground(String... logtext) { + return Html.fromHtml(logtext[0], new HtmlImage(getGeocode(), false, StoredList.STANDARD_LIST_ID, false), null); //, TextView.BufferType.SPANNABLE) + } + + @Override + protected void onPostExecute(Spanned result) { + // Ensure that this holder and its view still references the right item before updating the text. + if (position == holder.getPosition()) { + holder.text.setText(result); + } + } + + } + +} diff --git a/main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java new file mode 100644 index 0000000..4c57406 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java @@ -0,0 +1,70 @@ +package cgeo.geocaching.ui.logs; + +import cgeo.geocaching.CacheDetailActivity; +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.Trackable; +import cgeo.geocaching.TrackableActivity; +import cgeo.geocaching.ui.UserActionsClickListener; + +import org.apache.commons.lang3.StringUtils; + +import android.text.Html; +import android.view.View; + +import java.util.List; + +public class TrackableLogsViewCreator extends LogsViewCreator { + + private final Trackable trackable; + + /** + * @param trackableActivity + */ + public TrackableLogsViewCreator(TrackableActivity trackableActivity, final Trackable trackable) { + super(trackableActivity); + this.trackable = trackable; + } + + @Override + protected boolean isValid() { + return trackable != null; + } + + @Override + protected List<LogEntry> getLogs() { + return trackable.getLogs(); + } + + @Override + protected void addHeaderView() { + // empty + } + + @Override + protected void fillCountOrLocation(LogViewHolder holder, final LogEntry log) { + if (StringUtils.isBlank(log.cacheName)) { + holder.countOrLocation.setVisibility(View.GONE); + } else { + holder.countOrLocation.setText(Html.fromHtml(log.cacheName)); + final String cacheGuid = log.cacheGuid; + final String cacheName = log.cacheName; + holder.countOrLocation.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View arg0) { + CacheDetailActivity.startActivityGuid(activity, cacheGuid, Html.fromHtml(cacheName).toString()); + } + }); + } + } + + @Override + protected String getGeocode() { + return trackable.getGeocode(); + } + + @Override + protected UserActionsClickListener createUserActionsListener() { + return new UserActionsClickListener(); + } + +}
\ No newline at end of file |
