diff options
Diffstat (limited to 'main/src/cgeo/geocaching/ui')
19 files changed, 735 insertions, 102 deletions
diff --git a/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java new file mode 100644 index 0000000..b717568 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java @@ -0,0 +1,76 @@ +package cgeo.geocaching.ui; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgeocaches; +import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.network.Network; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Resources; +import android.net.Uri; +import android.view.View; + +abstract class AbstractUserClickListener implements View.OnClickListener { + + private final boolean enabled; + + public AbstractUserClickListener(final boolean enabled) { + this.enabled = enabled; + } + + @Override + public void onClick(View view) { + if (view == null) { + return; + } + if (!enabled) { + return; + } + + showUserActionsDialog(getUserName(view), view); + } + + protected abstract CharSequence getUserName(View view); + + /** + * Opens a dialog to do actions on an user name + */ + protected static void showUserActionsDialog(final CharSequence name, final View view) { + final AbstractActivity context = (AbstractActivity) view.getContext(); + final Resources res = context.getResources(); + final CharSequence[] items = { res.getString(R.string.user_menu_view_hidden), + res.getString(R.string.user_menu_view_found), + res.getString(R.string.user_menu_open_browser), + res.getString(R.string.user_menu_send_message) + }; + + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(res.getString(R.string.user_menu_title) + " " + name); + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int item) { + switch (item) { + case 0: + cgeocaches.startActivityOwner(context, name.toString()); + return; + case 1: + cgeocaches.startActivityUserName(context, name.toString()); + return; + case 2: + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + Network.encode(name.toString())))); + return; + case 3: + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/email/?u=" + Network.encode(name.toString())))); + return; + default: + break; + } + } + }); + final AlertDialog alert = builder.create(); + alert.show(); + } + +} diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index d95363e..3179857 100644 --- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java +++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java @@ -6,7 +6,7 @@ import cgeo.geocaching.CacheDetailActivity; import cgeo.geocaching.Geocache; import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheListType; import cgeo.geocaching.enumerations.CacheType; @@ -14,6 +14,7 @@ import cgeo.geocaching.filter.IFilter; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.sorting.CacheComparator; import cgeo.geocaching.sorting.DistanceComparator; +import cgeo.geocaching.sorting.EventDateComparator; import cgeo.geocaching.sorting.InverseComparator; import cgeo.geocaching.sorting.VisitComparator; import cgeo.geocaching.utils.AngleUtils; @@ -642,4 +643,25 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { } return list.size(); } + + public void setInitialComparator() { + CacheComparator comparator = null; // a null comparator will automatically sort by distance + if (cacheListType == CacheListType.HISTORY) { + comparator = new VisitComparator(); + } else { + if (CollectionUtils.isNotEmpty(list)) { + boolean eventsOnly = true; + for (final Geocache cache : list) { + if (!cache.isEventCache()) { + eventsOnly = false; + break; + } + } + if (eventsOnly) { + comparator = new EventDateComparator(); + } + } + } + setComparator(comparator); + } } diff --git a/main/src/cgeo/geocaching/ui/CompassMiniView.java b/main/src/cgeo/geocaching/ui/CompassMiniView.java index da8f69e..92280dc 100644 --- a/main/src/cgeo/geocaching/ui/CompassMiniView.java +++ b/main/src/cgeo/geocaching/ui/CompassMiniView.java @@ -1,7 +1,7 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.AngleUtils; diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java index c926057..b73a2a9 100644 --- a/main/src/cgeo/geocaching/ui/CompassView.java +++ b/main/src/cgeo/geocaching/ui/CompassView.java @@ -171,12 +171,12 @@ public class CompassView extends View implements PeriodicHandlerListener { headingDrawn = cacheHeadingShown; } - float azimuthTemp = azimuthDrawn; + final float azimuthTemp = azimuthDrawn; final float azimuthRelative = AngleUtils.normalize(azimuthTemp - headingDrawn); // compass margins - int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2); - int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2); + final int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2); + final int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2); super.onDraw(canvas); @@ -217,38 +217,36 @@ public class CompassView extends View implements PeriodicHandlerListener { } private int measureWidth(int measureSpec) { - int result; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); + final int specMode = MeasureSpec.getMode(measureSpec); + final int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { - result = specSize; - } else { - result = compassArrow.getWidth() + getPaddingLeft() + getPaddingRight(); + return specSize; + } - if (specMode == MeasureSpec.AT_MOST) { - result = Math.min(result, specSize); - } + final int desired = compassArrow.getWidth() + getPaddingLeft() + getPaddingRight(); + if (specMode == MeasureSpec.AT_MOST) { + return Math.min(desired, specSize); } - return result; + return desired; } private int measureHeight(int measureSpec) { - int result; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); + // The duplicated code in measureHeight and measureWidth cannot be avoided. + // Those methods must be efficient, therefore we cannot extract the code differences and unify the remainder. + final int specMode = MeasureSpec.getMode(measureSpec); + final int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { - result = specSize; - } else { - result = compassArrow.getHeight() + getPaddingTop() + getPaddingBottom(); + return specSize; + } - if (specMode == MeasureSpec.AT_MOST) { - result = Math.min(result, specSize); - } + final int desired = compassArrow.getHeight() + getPaddingTop() + getPaddingBottom(); + if (specMode == MeasureSpec.AT_MOST) { + return Math.min(desired, specSize); } - return result; + return desired; } } diff --git a/main/src/cgeo/geocaching/ui/DistanceView.java b/main/src/cgeo/geocaching/ui/DistanceView.java index 9611511..b36166d 100644 --- a/main/src/cgeo/geocaching/ui/DistanceView.java +++ b/main/src/cgeo/geocaching/ui/DistanceView.java @@ -36,8 +36,4 @@ public class DistanceView extends TextView { public void setDistance(Float distance) { setText("~" + Units.getDistanceFromKilometers(distance)); } - - public void clear() { - setText(null); - } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/ui/EditNoteDialog.java b/main/src/cgeo/geocaching/ui/EditNoteDialog.java index bbf0618..9a122e2 100644 --- a/main/src/cgeo/geocaching/ui/EditNoteDialog.java +++ b/main/src/cgeo/geocaching/ui/EditNoteDialog.java @@ -1,21 +1,17 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.R.string; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.app.DialogFragment; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager.LayoutParams; -import android.view.inputmethod.EditorInfo; import android.widget.EditText; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; -public class EditNoteDialog extends DialogFragment implements OnEditorActionListener { +public class EditNoteDialog extends DialogFragment { public interface EditNoteDialogListener { void onFinishEditNoteDialog(final String inputText); @@ -24,7 +20,6 @@ public class EditNoteDialog extends DialogFragment implements OnEditorActionList public static final String ARGUMENT_INITIAL_NOTE = "initialNote"; private EditText mEditText; - private String initialNote; public static EditNoteDialog newInstance(final String initialNote) { EditNoteDialog dialog = new EditNoteDialog(); @@ -37,34 +32,35 @@ public class EditNoteDialog extends DialogFragment implements OnEditorActionList } @Override - public View onCreateView(final LayoutInflater inflater, final ViewGroup container, - final Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_edit_note, container); + public Dialog onCreateDialog(Bundle savedInstanceState) { + LayoutInflater inflater = getActivity().getLayoutInflater(); + View view = inflater.inflate(R.layout.fragment_edit_note, null); mEditText = (EditText) view.findViewById(R.id.note); - initialNote = getArguments().getString(ARGUMENT_INITIAL_NOTE); + String initialNote = getArguments().getString(ARGUMENT_INITIAL_NOTE); if (initialNote != null) { mEditText.setText(initialNote); initialNote = null; } - getDialog().setTitle(string.cache_personal_note); - mEditText.requestFocus(); - getDialog().getWindow().setSoftInputMode( - LayoutParams.SOFT_INPUT_STATE_VISIBLE); - mEditText.setOnEditorActionListener(this); - return view; + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.cache_personal_note); + builder.setView(view); + builder.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + final EditNoteDialogListener activity = (EditNoteDialogListener) getActivity(); + activity.onFinishEditNoteDialog(mEditText.getText().toString()); + dialog.dismiss(); + } + }); + builder.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }); + return builder.create(); } - - @Override - public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) { - if (EditorInfo.IME_ACTION_DONE == actionId) { - final EditNoteDialogListener activity = (EditNoteDialogListener) getActivity(); - activity.onFinishEditNoteDialog(mEditText.getText().toString()); - dismiss(); - return true; - } - return false; - } - - } 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/IndexOutOfBoundsAvoidingTextView.java b/main/src/cgeo/geocaching/ui/IndexOutOfBoundsAvoidingTextView.java new file mode 100644 index 0000000..a0c8b52 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/IndexOutOfBoundsAvoidingTextView.java @@ -0,0 +1,55 @@ +package cgeo.geocaching.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.TextView; + +/** + * Jelly beans can crash when calculating the layout of a textview. + * + * https://code.google.com/p/android/issues/detail?id=35466 + * + */ +public class IndexOutOfBoundsAvoidingTextView extends TextView { + + public IndexOutOfBoundsAvoidingTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public IndexOutOfBoundsAvoidingTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public IndexOutOfBoundsAvoidingTextView(Context context) { + super(context); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + try{ + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } catch (IndexOutOfBoundsException e) { + setText(getText().toString()); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + public void setGravity(int gravity){ + try{ + super.setGravity(gravity); + } catch (IndexOutOfBoundsException e) { + setText(getText().toString()); + super.setGravity(gravity); + } + } + + @Override + public void setText(CharSequence text, BufferType type) { + try{ + super.setText(text, type); + } catch (IndexOutOfBoundsException e) { + setText(text.toString()); + } + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/ui/LoggingUI.java b/main/src/cgeo/geocaching/ui/LoggingUI.java index ac74dd3..0ee724a 100644 --- a/main/src/cgeo/geocaching/ui/LoggingUI.java +++ b/main/src/cgeo/geocaching/ui/LoggingUI.java @@ -3,7 +3,7 @@ package cgeo.geocaching.ui; import cgeo.geocaching.Geocache; import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.cgData; import cgeo.geocaching.activity.IAbstractActivity; import cgeo.geocaching.enumerations.LogType; diff --git a/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java new file mode 100644 index 0000000..45ce237 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java @@ -0,0 +1,31 @@ +package cgeo.geocaching.ui; + +import cgeo.geocaching.Geocache; + +import org.apache.commons.lang3.StringUtils; + +import android.view.View; +import android.widget.TextView; + +/** + * Listener for clicks on owner name + */ +public class OwnerActionsClickListener extends AbstractUserClickListener { + + private final Geocache cache; + + public OwnerActionsClickListener(Geocache cache) { + super(cache.supportsUserActions()); + this.cache = cache; + } + + @Override + protected String getUserName(View view) { + // Use real owner name vice the one owner chose to display + if (StringUtils.isNotBlank(cache.getOwnerUserId())) { + return cache.getOwnerUserId(); + } + return ((TextView) view).getText().toString(); + } +} + diff --git a/main/src/cgeo/geocaching/ui/UserActionsClickListener.java b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java new file mode 100644 index 0000000..292074e --- /dev/null +++ b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java @@ -0,0 +1,26 @@ +package cgeo.geocaching.ui; + +import cgeo.geocaching.Geocache; + +import android.view.View; +import android.widget.TextView; + +/** + * Listener for clicks on user name + */ +public class UserActionsClickListener extends AbstractUserClickListener { + + public UserActionsClickListener(Geocache cache) { + super(cache.supportsUserActions()); + } + + public UserActionsClickListener() { + super(true); + } + + @Override + protected CharSequence getUserName(View view) { + return ((TextView) view).getText().toString(); + } +} + diff --git a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java index 4ab9af0..959cb14 100644 --- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java +++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java @@ -3,8 +3,8 @@ package cgeo.geocaching.ui.dialog; import cgeo.geocaching.Geocache; import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; -import cgeo.geocaching.Settings.coordInputFormatEnum; +import cgeo.geocaching.settings.Settings; +import cgeo.geocaching.settings.Settings.coordInputFormatEnum; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.compatibility.Compatibility; @@ -13,13 +13,10 @@ import cgeo.geocaching.geopoint.GeopointFormatter; import org.apache.commons.lang3.StringUtils; -import android.app.Dialog; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; @@ -28,7 +25,7 @@ import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; -public class CoordinatesInputDialog extends Dialog { +public class CoordinatesInputDialog extends NoTitleDialog { final private AbstractActivity context; final private IGeoData geo; @@ -65,13 +62,6 @@ public class CoordinatesInputDialog extends Dialog { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - try { - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - } catch (Exception e) { - // nothing - } - setContentView(R.layout.coordinatesinput_dialog); final Spinner spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats); @@ -338,7 +328,7 @@ public class CoordinatesInputDialog extends Dialog { if (currentFormat == coordInputFormatEnum.Plain) { try { gp = new Geopoint(eLat.getText().toString(), eLon.getText().toString()); - } catch (Geopoint.ParseException e) { + } catch (final Geopoint.ParseException e) { if (signalError) { context.showToast(context.getResources().getString(R.string.err_parse_lat_lon)); } @@ -347,20 +337,20 @@ public class CoordinatesInputDialog extends Dialog { return true; } - String latDir = bLat.getText().toString(); - String lonDir = bLon.getText().toString(); - String latDeg = eLatDeg.getText().toString(); - String lonDeg = eLonDeg.getText().toString(); - String latDegFrac = eLatMin.getText().toString(); - String lonDegFrac = eLonMin.getText().toString(); - String latMin = eLatMin.getText().toString(); - String lonMin = eLonMin.getText().toString(); - String latMinFrac = eLatSec.getText().toString(); - String lonMinFrac = eLonSec.getText().toString(); - String latSec = eLatSec.getText().toString(); - String lonSec = eLonSec.getText().toString(); - String latSecFrac = eLatSub.getText().toString(); - String lonSecFrac = eLonSub.getText().toString(); + final String latDir = bLat.getText().toString(); + final String lonDir = bLon.getText().toString(); + final String latDeg = eLatDeg.getText().toString(); + final String lonDeg = eLonDeg.getText().toString(); + final String latDegFrac = eLatMin.getText().toString(); + final String lonDegFrac = eLonMin.getText().toString(); + final String latMin = eLatMin.getText().toString(); + final String lonMin = eLonMin.getText().toString(); + final String latMinFrac = eLatSec.getText().toString(); + final String lonMinFrac = eLonSec.getText().toString(); + final String latSec = eLatSec.getText().toString(); + final String lonSec = eLonSec.getText().toString(); + final String latSecFrac = eLatSub.getText().toString(); + final String lonSecFrac = eLonSub.getText().toString(); switch (currentFormat) { case Deg: diff --git a/main/src/cgeo/geocaching/ui/dialog/DateDialog.java b/main/src/cgeo/geocaching/ui/dialog/DateDialog.java index a9c579c..18f8e2e 100644 --- a/main/src/cgeo/geocaching/ui/dialog/DateDialog.java +++ b/main/src/cgeo/geocaching/ui/dialog/DateDialog.java @@ -3,15 +3,12 @@ package cgeo.geocaching.ui.dialog; import cgeo.geocaching.R; import android.app.Activity; -import android.app.Dialog; import android.os.Bundle; -import android.view.ViewGroup.LayoutParams; -import android.view.Window; import android.widget.DatePicker; import java.util.Calendar; -public class DateDialog extends Dialog { +public class DateDialog extends NoTitleDialog { public interface DateDialogParent { abstract public void setDate(final Calendar date); @@ -32,13 +29,6 @@ public class DateDialog extends Dialog { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - try { - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - } catch (Exception e) { - // nothing - } - setContentView(R.layout.date); final DatePicker picker = (DatePicker) findViewById(R.id.picker); diff --git a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java index 862b1a0..2c4f38d 100644 --- a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java +++ b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java @@ -1,7 +1,7 @@ package cgeo.geocaching.ui.dialog; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; +import cgeo.geocaching.settings.Settings; import cgeo.geocaching.cgeoapplication; import android.app.Activity; diff --git a/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java b/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java new file mode 100644 index 0000000..fc5ebe6 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/dialog/NoTitleDialog.java @@ -0,0 +1,30 @@ +package cgeo.geocaching.ui.dialog; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.ViewGroup.LayoutParams; +import android.view.Window; + +public abstract class NoTitleDialog extends Dialog { + + public NoTitleDialog(Context context) { + super(context); + } + + public NoTitleDialog(Context context, int theme) { + super(context, theme); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + try { + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + } catch (final Exception e) { + // nothing + } + } +} 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..8da711e --- /dev/null +++ b/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java @@ -0,0 +1,112 @@ +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 Resources res = cgeoapplication.getInstance().getResources(); + + public CacheLogsViewCreator(CacheDetailActivity cacheDetailActivity, boolean allLogs) { + super(cacheDetailActivity); + this.allLogs = allLogs; + } + + /** + * May return null! + * + * @return + */ + private Geocache getCache() { + if (this.activity instanceof CacheDetailActivity) { + CacheDetailActivity details = (CacheDetailActivity) this.activity; + return details.getCache(); + } + return null; + } + + @Override + protected List<LogEntry> getLogs() { + return allLogs ? getCache().getLogs() : getCache().getFriendsLogs(); + } + + @Override + protected void addHeaderView() { + // adds the log counts + final Map<LogType, Integer> logCounts = getCache().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 getCache() != null; + } + + @Override + protected String getGeocode() { + return getCache().getGeocode(); + } + + @Override + protected UserActionsClickListener createUserActionsListener() { + return new UserActionsClickListener(getCache()); + } + +}
\ 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 |
