diff options
Diffstat (limited to 'main/src/cgeo/geocaching/ui')
29 files changed, 973 insertions, 305 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/AbstractViewHolder.java b/main/src/cgeo/geocaching/ui/AbstractViewHolder.java new file mode 100644 index 0000000..cc5cd4d --- /dev/null +++ b/main/src/cgeo/geocaching/ui/AbstractViewHolder.java @@ -0,0 +1,19 @@ +package cgeo.geocaching.ui; + +import butterknife.Views; + +import android.view.View; + +/** + * Abstract super class for all view holders. It is responsible for the invocation of the view injection code and for + * the tagging of views. + * + */ +public abstract class AbstractViewHolder { + + protected AbstractViewHolder(View view) { + Views.inject(this, view); + view.setTag(this); + } + +} diff --git a/main/src/cgeo/geocaching/ui/AddressListAdapter.java b/main/src/cgeo/geocaching/ui/AddressListAdapter.java index eb8b516..736c036 100644 --- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java +++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java @@ -1,5 +1,7 @@ package cgeo.geocaching.ui; +import butterknife.InjectView; + import cgeo.geocaching.R; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.cgeocaches; @@ -24,9 +26,13 @@ public class AddressListAdapter extends ArrayAdapter<Address> { final private LayoutInflater inflater; final private Geopoint location; - private static final class ViewHolder { - TextView label; - TextView distance; + protected static final class ViewHolder extends AbstractViewHolder { + @InjectView(R.id.label) protected TextView label; + @InjectView(R.id.distance) protected TextView distance; + + public ViewHolder(View view) { + super(view); + } } public AddressListAdapter(final Context context) { @@ -44,13 +50,8 @@ public class AddressListAdapter extends ArrayAdapter<Address> { // holder pattern implementation final ViewHolder holder; if (view == null) { - view = inflater.inflate(R.layout.addresses_item, null); - - holder = new ViewHolder(); - holder.label = (TextView) view.findViewById(R.id.label); - holder.distance = (TextView) view.findViewById(R.id.distance); - - view.setTag(holder); + view = inflater.inflate(R.layout.addresslist_item, null); + holder = new ViewHolder(view); } else { holder = (ViewHolder) view.getTag(); } diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java index e98bd77..9059a6b 100644 --- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java +++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java @@ -2,6 +2,7 @@ package cgeo.geocaching.ui; import cgeo.geocaching.Geocache; import cgeo.geocaching.R; +import cgeo.geocaching.Waypoint; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Units; @@ -67,7 +68,7 @@ public final class CacheDetailsCreator { final LayoutInflater inflater = LayoutInflater.from(activity); for (int i = 0; i < 5; i++) { - ImageView star = (ImageView) inflater.inflate(R.layout.star, null); + ImageView star = (ImageView) inflater.inflate(R.layout.star_image, null); if (value - i >= 0.75) { star.setImageResource(R.drawable.star_on); } else if (value - i >= 0.25) { @@ -154,4 +155,24 @@ public final class CacheDetailsCreator { } add(R.string.cache_distance, text); } + + public void addDistance(final Waypoint wpt, final TextView waypointDistanceView) { + Float distance = null; + if (wpt.getCoords() != null) { + final Geopoint currentCoords = cgeoapplication.getInstance().currentGeo().getCoords(); + if (currentCoords != null) { + distance = currentCoords.distanceTo(wpt); + } + } + String text = "--"; + if (distance != null) { + text = Units.getDistanceFromKilometers(distance); + } + else if (waypointDistanceView != null) { + // if there is already a distance in waypointDistance, use it instead of resetting to default. + // this prevents displaying "--" while waiting for a new position update (See bug #1468) + text = waypointDistanceView.getText().toString(); + } + add(R.string.cache_distance, text); + } } diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index 42b774e..3179857 100644 --- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java +++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java @@ -1,10 +1,12 @@ package cgeo.geocaching.ui; +import butterknife.InjectView; + 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; @@ -12,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; @@ -77,13 +80,13 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { private static final int[] RATING_BACKGROUND = new int[3]; static { if (Settings.isLightSkin()) { - RATING_BACKGROUND[0] = R.drawable.favourite_background_red_light; - RATING_BACKGROUND[1] = R.drawable.favourite_background_orange_light; - RATING_BACKGROUND[2] = R.drawable.favourite_background_green_light; + RATING_BACKGROUND[0] = R.drawable.favorite_background_red_light; + RATING_BACKGROUND[1] = R.drawable.favorite_background_orange_light; + RATING_BACKGROUND[2] = R.drawable.favorite_background_green_light; } else { - RATING_BACKGROUND[0] = R.drawable.favourite_background_red_dark; - RATING_BACKGROUND[1] = R.drawable.favourite_background_orange_dark; - RATING_BACKGROUND[2] = R.drawable.favourite_background_green_dark; + RATING_BACKGROUND[0] = R.drawable.favorite_background_red_dark; + RATING_BACKGROUND[1] = R.drawable.favorite_background_orange_dark; + RATING_BACKGROUND[2] = R.drawable.favorite_background_green_dark; } } @@ -91,16 +94,20 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { * view holder for the cache list adapter * */ - private static class ViewHolder { - CheckBox checkbox; - ImageView logStatusMark; - TextView text; - TextView favourite; - TextView info; - ImageView inventory; - DistanceView distance; - CompassMiniView direction; - ImageView dirImg; + protected static class ViewHolder extends AbstractViewHolder { + @InjectView(R.id.checkbox) protected CheckBox checkbox; + @InjectView(R.id.log_status_mark) protected ImageView logStatusMark; + @InjectView(R.id.text) protected TextView text; + @InjectView(R.id.distance) protected DistanceView distance; + @InjectView(R.id.favorite) protected TextView favorite; + @InjectView(R.id.info) protected TextView info; + @InjectView(R.id.inventory) protected ImageView inventory; + @InjectView(R.id.direction) protected CompassMiniView direction; + @InjectView(R.id.dirimg) protected ImageView dirImg; + + public ViewHolder(View view) { + super(view); + } } public CacheListAdapter(final Activity activity, final List<Geocache> list, CacheListType cacheListType) { @@ -348,20 +355,9 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { final ViewHolder holder; if (v == null) { - v = inflater.inflate(R.layout.caches_item, null); - - holder = new ViewHolder(); - holder.checkbox = (CheckBox) v.findViewById(R.id.checkbox); - holder.logStatusMark = (ImageView) v.findViewById(R.id.log_status_mark); - holder.text = (TextView) v.findViewById(R.id.text); - holder.distance = (DistanceView) v.findViewById(R.id.distance); - holder.direction = (CompassMiniView) v.findViewById(R.id.direction); - holder.dirImg = (ImageView) v.findViewById(R.id.dirimg); - holder.inventory = (ImageView) v.findViewById(R.id.inventory); - holder.favourite = (TextView) v.findViewById(R.id.favourite); - holder.info = (TextView) v.findViewById(R.id.info); - - v.setTag(holder); + v = inflater.inflate(R.layout.cacheslist_item, null); + + holder = new ViewHolder(v); } else { holder = (ViewHolder) v.getTag(); } @@ -453,14 +449,14 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { holder.direction.setVisibility(View.GONE); } - holder.favourite.setText(Integer.toString(cache.getFavoritePoints())); + holder.favorite.setText(Integer.toString(cache.getFavoritePoints())); int favoriteBack; // set default background, neither vote nor rating may be available if (lightSkin) { - favoriteBack = R.drawable.favourite_background_light; + favoriteBack = R.drawable.favorite_background_light; } else { - favoriteBack = R.drawable.favourite_background_dark; + favoriteBack = R.drawable.favorite_background_dark; } final float myVote = cache.getMyVote(); if (myVote > 0) { // use my own rating for display, if I have voted @@ -481,7 +477,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { favoriteBack = RATING_BACKGROUND[0]; } } - holder.favourite.setBackgroundResource(favoriteBack); + holder.favorite.setBackgroundResource(favoriteBack); if (cacheListType == CacheListType.HISTORY && cache.getVisitedDate() > 0) { holder.info.setText(Formatter.formatCacheInfoHistory(cache)); @@ -647,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 0ef3a43..b73a2a9 100644 --- a/main/src/cgeo/geocaching/ui/CompassView.java +++ b/main/src/cgeo/geocaching/ui/CompassView.java @@ -3,6 +3,7 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; import cgeo.geocaching.utils.AngleUtils; import cgeo.geocaching.utils.PeriodicHandler; +import cgeo.geocaching.utils.PeriodicHandler.PeriodicHandlerListener; import android.content.Context; import android.graphics.Bitmap; @@ -14,7 +15,7 @@ import android.util.AttributeSet; import android.util.FloatMath; import android.view.View; -public class CompassView extends View { +public class CompassView extends View implements PeriodicHandlerListener { private Context context = null; private Bitmap compassUnderlay = null; @@ -48,7 +49,7 @@ public class CompassView extends View { private int compassOverlayWidth = 0; private int compassOverlayHeight = 0; private boolean initialDisplay; - private final RedrawHandler redrawHandler = new RedrawHandler(); + private final PeriodicHandler redrawHandler = new PeriodicHandler(40, this); public CompassView(Context contextIn) { super(contextIn); @@ -145,26 +146,18 @@ public class CompassView extends View { return AngleUtils.normalize(actual + offset); } - private class RedrawHandler extends PeriodicHandler { - - public RedrawHandler() { - super(40); - } - - @Override - public void act() { - final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown); - final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown); - if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 || - Math.abs(AngleUtils.difference(cacheHeadingShown, newCacheHeadingShown)) >= 2) { - synchronized(CompassView.this) { - azimuthShown = newAzimuthShown; - cacheHeadingShown = newCacheHeadingShown; - } - invalidate(); + @Override + public void onPeriodic() { + final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown); + final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown); + if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 || + Math.abs(AngleUtils.difference(cacheHeadingShown, newCacheHeadingShown)) >= 2) { + synchronized(this) { + azimuthShown = newAzimuthShown; + cacheHeadingShown = newCacheHeadingShown; } + invalidate(); } - } @Override @@ -178,12 +171,12 @@ public class CompassView extends View { 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); @@ -224,38 +217,36 @@ public class CompassView extends View { } 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/CoordinatesFormatSwitcher.java b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java new file mode 100644 index 0000000..afadb33 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java @@ -0,0 +1,38 @@ +package cgeo.geocaching.ui; + +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.GeopointFormatter; + +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.TextView; + +/** + * view click listener to automatically switch different coordinate formats + * + */ +public class CoordinatesFormatSwitcher implements OnClickListener { + + private static GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] { + GeopointFormatter.Format.LAT_LON_DECMINUTE, + GeopointFormatter.Format.LAT_LON_DECSECOND, + GeopointFormatter.Format.LAT_LON_DECDEGREE + }; + + private int position = 0; + + private final Geopoint coordinates; + + public CoordinatesFormatSwitcher(final Geopoint coordinates) { + this.coordinates = coordinates; + } + + @Override + public void onClick(View view) { + position = (position + 1) % availableFormats.length; + TextView textView = (TextView) view; + // rotate coordinate formats on click + textView.setText(coordinates.format(availableFormats[position])); + } + +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java b/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java index 4ba88ae..f10e13a 100644 --- a/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java +++ b/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java @@ -16,6 +16,12 @@ public class DecryptTextClickListener implements View.OnClickListener { try {
final TextView logView = (TextView) view;
+
+ // do not run the click listener if a link was clicked
+ if (logView.getSelectionStart() != -1 || logView.getSelectionEnd() != -1) {
+ return;
+ }
+
CharSequence text = logView.getText();
if (text instanceof Spannable) {
Spannable span = (Spannable) text;
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 new file mode 100644 index 0000000..9a122e2 --- /dev/null +++ b/main/src/cgeo/geocaching/ui/EditNoteDialog.java @@ -0,0 +1,66 @@ +package cgeo.geocaching.ui; + +import cgeo.geocaching.R; + +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.LayoutInflater; +import android.view.View; +import android.widget.EditText; + +public class EditNoteDialog extends DialogFragment { + + public interface EditNoteDialogListener { + void onFinishEditNoteDialog(final String inputText); + } + + public static final String ARGUMENT_INITIAL_NOTE = "initialNote"; + + private EditText mEditText; + + public static EditNoteDialog newInstance(final String initialNote) { + EditNoteDialog dialog = new EditNoteDialog(); + + Bundle arguments = new Bundle(); + arguments.putString(EditNoteDialog.ARGUMENT_INITIAL_NOTE, initialNote); + dialog.setArguments(arguments); + + return dialog; + } + + @Override + 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); + String initialNote = getArguments().getString(ARGUMENT_INITIAL_NOTE); + if (initialNote != null) { + mEditText.setText(initialNote); + initialNote = null; + } + + 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(); + } +} diff --git a/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java b/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java index 1db3f21..c325f50 100644 --- a/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java +++ b/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java @@ -1,5 +1,7 @@ package cgeo.geocaching.ui; +import butterknife.InjectView; + import cgeo.geocaching.R; import cgeo.geocaching.files.IFileSelectionView; import cgeo.geocaching.utils.Log; @@ -17,23 +19,20 @@ import java.util.List; public class FileSelectionListAdapter extends ArrayAdapter<File> { - private IFileSelectionView parentView; - private LayoutInflater inflater; + private final IFileSelectionView parentView; + private final LayoutInflater inflater; public FileSelectionListAdapter(IFileSelectionView parentIn, List<File> listIn) { super(parentIn.getContext(), 0, listIn); parentView = parentIn; + inflater = ((Activity) getContext()).getLayoutInflater(); } @Override public View getView(final int position, final View rowView, final ViewGroup parent) { - if (inflater == null) { - inflater = ((Activity) getContext()).getLayoutInflater(); - } - if (position > getCount()) { - Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position); + Log.w("FileSelectionListAdapter.getView: Attempt to access missing item #" + position); return null; } @@ -44,12 +43,7 @@ public class FileSelectionListAdapter extends ArrayAdapter<File> { ViewHolder holder; if (v == null) { v = inflater.inflate(R.layout.mapfile_item, null); - - holder = new ViewHolder(); - holder.filepath = (TextView) v.findViewById(R.id.mapfilepath); - holder.filename = (TextView) v.findViewById(R.id.mapfilename); - - v.setTag(holder); + holder = new ViewHolder(v); } else { holder = (ViewHolder) v.getTag(); } @@ -85,8 +79,12 @@ public class FileSelectionListAdapter extends ArrayAdapter<File> { } } - private static final class ViewHolder { - TextView filepath; - TextView filename; + protected static final class ViewHolder extends AbstractViewHolder { + @InjectView(R.id.mapfilepath) protected TextView filepath; + @InjectView(R.id.mapfilename) protected TextView filename; + + public ViewHolder(View view) { + super(view); + } } } diff --git a/main/src/cgeo/geocaching/ui/GPXListAdapter.java b/main/src/cgeo/geocaching/ui/GPXListAdapter.java index 9f6c14c..7f3c33f 100644 --- a/main/src/cgeo/geocaching/ui/GPXListAdapter.java +++ b/main/src/cgeo/geocaching/ui/GPXListAdapter.java @@ -1,7 +1,9 @@ package cgeo.geocaching.ui; -import cgeo.geocaching.R; +import butterknife.InjectView; + import cgeo.geocaching.GpxFileListActivity; +import cgeo.geocaching.R; import cgeo.geocaching.files.GPXImporter; import cgeo.geocaching.utils.Log; @@ -18,28 +20,29 @@ import java.io.File; import java.util.List; public class GPXListAdapter extends ArrayAdapter<File> { - private GpxFileListActivity activity = null; - private LayoutInflater inflater = null; + private final GpxFileListActivity activity; + private final LayoutInflater inflater; - private static class ViewHolder { - TextView filepath; - TextView filename; + protected static class ViewHolder extends AbstractViewHolder { + @InjectView(R.id.filepath) protected TextView filepath; + @InjectView(R.id.filename) protected TextView filename; + + public ViewHolder(View view) { + super(view); + } } public GPXListAdapter(GpxFileListActivity parentIn, List<File> listIn) { super(parentIn, 0, listIn); activity = parentIn; + inflater = ((Activity) getContext()).getLayoutInflater(); } @Override public View getView(final int position, final View rowView, final ViewGroup parent) { - if (inflater == null) { - inflater = ((Activity) getContext()).getLayoutInflater(); - } - if (position > getCount()) { - Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position); + Log.w("GPXListAdapter.getView: Attempt to access missing item #" + position); return null; } @@ -50,12 +53,7 @@ public class GPXListAdapter extends ArrayAdapter<File> { final ViewHolder holder; if (view == null) { view = inflater.inflate(R.layout.gpx_item, null); - - holder = new ViewHolder(); - holder.filepath = (TextView) view.findViewById(R.id.filepath); - holder.filename = (TextView) view.findViewById(R.id.filename); - - view.setTag(holder); + holder = new ViewHolder(view); } else { holder = (ViewHolder) view.getTag(); } 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/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java index 9464114..0f860c4 100644 --- a/main/src/cgeo/geocaching/ui/ImagesList.java +++ b/main/src/cgeo/geocaching/ui/ImagesList.java @@ -11,7 +11,6 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.Activity; -import android.app.ProgressDialog; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; @@ -31,6 +30,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.util.Collection; @@ -39,23 +39,18 @@ import java.util.List; public class ImagesList { - private static final int MENU_FILE = 201; - private static final int MENU_BROWSER = 202; - private BitmapDrawable currentDrawable; private Image currentImage; public enum ImageType { - LogImages(R.string.cache_log_images_title, R.string.cache_log_images_loading), - SpoilerImages(R.string.cache_spoiler_images_title, R.string.cache_spoiler_images_loading), - AllImages(R.string.cache_images_title, R.string.cache_images_loading); + LogImages(R.string.cache_log_images_title), + SpoilerImages(R.string.cache_spoiler_images_title), + AllImages(R.string.cache_images_title); private final int titleResId; - private final int loadingResId; - ImageType(final int title, final int loading) { + ImageType(final int title) { this.titleResId = title; - this.loadingResId = loading; } public int getTitle() { @@ -64,9 +59,6 @@ public class ImagesList { } private LayoutInflater inflater = null; - private ProgressDialog progressDialog = null; - private int count = 0; - private int countDone = 0; private final Activity activity; // We could use a Set here, but we will insert no duplicates, so there is no need to check for uniqueness. private final Collection<Bitmap> bitmaps = new LinkedList<Bitmap>(); @@ -83,18 +75,10 @@ public class ImagesList { inflater = activity.getLayoutInflater(); } - public void loadImages(final View parentView, final List<Image> images, ImageType imageType, final boolean offline) { + public void loadImages(final View parentView, final List<Image> images, final boolean offline) { imagesView = (LinearLayout) parentView.findViewById(R.id.spoiler_list); - count = images.size(); - progressDialog = new ProgressDialog(activity); - progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - progressDialog.setMessage(activity.getString(imageType.loadingResId)); - progressDialog.setCancelable(true); - progressDialog.setMax(count); - progressDialog.show(); - for (final Image img : images) { LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null); @@ -154,19 +138,12 @@ public class ImagesList { imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setLayoutParams(new LayoutParams(bounds.width(), bounds.height())); + view.findViewById(R.id.progress_bar).setVisibility(View.GONE); view.addView(imageView); imageView.setId(image.hashCode()); images.put(imageView.getId(), img); } - - synchronized (activity) { - countDone++; - progressDialog.setProgress(countDone); - if (progressDialog.getProgress() >= count) { - progressDialog.dismiss(); - } - } } } @@ -179,10 +156,9 @@ public class ImagesList { } public void onCreateContextMenu(ContextMenu menu, View v) { + activity.getMenuInflater().inflate(R.menu.images_list_context, menu); final Resources res = activity.getResources(); menu.setHeaderTitle(res.getString(R.string.cache_image)); - menu.add(0, MENU_FILE, 0, res.getString(R.string.cache_image_open_file)); - menu.add(0, MENU_BROWSER, 0, res.getString(R.string.cache_image_open_browser)); final ImageView view = (ImageView) v; currentDrawable = (BitmapDrawable) view.getDrawable(); currentImage = images.get(view.getId()); @@ -190,10 +166,10 @@ public class ImagesList { public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { - case MENU_FILE: + case R.id.image_open_file: viewImageInStandardApp(currentDrawable); return true; - case MENU_BROWSER: + case R.id.image_open_browser: if (currentImage != null) { currentImage.openInBrowser(activity); } @@ -205,15 +181,15 @@ public class ImagesList { private void viewImageInStandardApp(final BitmapDrawable image) { final File file = LocalStorage.getStorageFile(null, "temp.jpg", false, true); - FileOutputStream fos = null; + BufferedOutputStream stream = null; try { - fos = new FileOutputStream(file); - image.getBitmap().compress(CompressFormat.JPEG, 100, fos); + stream = new BufferedOutputStream(new FileOutputStream(file)); + image.getBitmap().compress(CompressFormat.JPEG, 100, stream); } catch (Exception e) { - Log.e("ImagesActivity.handleMessage.onClick", e); + Log.e("ImagesList.viewImageInStandardApp", e); return; } finally { - IOUtils.closeQuietly(fos); + IOUtils.closeQuietly(stream); } final Intent intent = new Intent(); 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 2615947..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; @@ -61,31 +61,12 @@ public class LoggingUI extends AbstractUIFactory { } } - private static final int MENU_ICON_LOG_VISIT = R.drawable.ic_menu_edit; - private static final int MENU_LOG_VISIT = 100; - private static final int MENU_LOG_VISIT_OFFLINE = 101; - - public static void addMenuItems(final Menu menu, final Geocache cache) { - if (cache == null) { - return; - } - if (!cache.supportsLogging()) { - return; - } - if (Settings.getLogOffline()) { - menu.add(0, MENU_LOG_VISIT_OFFLINE, 0, res.getString(R.string.cache_menu_visit_offline)).setIcon(MENU_ICON_LOG_VISIT); - } - else { - menu.add(0, MENU_LOG_VISIT, 0, res.getString(R.string.cache_menu_visit)).setIcon(MENU_ICON_LOG_VISIT); - } - } - public static boolean onMenuItemSelected(final MenuItem item, IAbstractActivity activity, Geocache cache) { switch (item.getItemId()) { - case MENU_LOG_VISIT: + case R.id.menu_log_visit: cache.logVisit(activity); return true; - case MENU_LOG_VISIT_OFFLINE: + case R.id.menu_log_visit_offline: showOfflineMenu(cache, (Activity) activity); return true; default: @@ -123,7 +104,7 @@ public class LoggingUI extends AbstractUIFactory { break; case CLEAR_LOG: - cgData.clearLogOffline(cache.getGeocode()); + cache.clearOfflineLog(); break; } } else { @@ -136,10 +117,17 @@ public class LoggingUI extends AbstractUIFactory { } - public static void onPrepareOptionsMenu(Menu menu) { - final MenuItem item = menu.findItem(MENU_LOG_VISIT); - if (item != null) { - item.setEnabled(Settings.isLogin()); - } + public static void onPrepareOptionsMenu(Menu menu, Geocache cache) { + final MenuItem itemLog = menu.findItem(R.id.menu_log_visit); + itemLog.setVisible(cache.supportsLogging() && !Settings.getLogOffline()); + itemLog.setEnabled(Settings.isLogin()); + + final MenuItem itemOffline = menu.findItem(R.id.menu_log_visit_offline); + itemOffline.setVisible(cache.supportsLogging() && Settings.getLogOffline()); + } + + public static void addMenuItems(Activity activity, Menu menu, Geocache cache) { + activity.getMenuInflater().inflate(R.menu.logging_ui, menu); + onPrepareOptionsMenu(menu, cache); } } 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 dada8fd..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; @@ -47,7 +44,7 @@ public class CoordinatesInputDialog extends Dialog { private coordInputFormatEnum currentFormat = null; public CoordinatesInputDialog(final AbstractActivity context, final Geocache cache, final Geopoint gp, final IGeoData geo) { - super(context, ActivityMixin.getTheme()); + super(context, ActivityMixin.getDialogTheme()); this.context = context; this.geo = geo; this.cache = cache; @@ -65,22 +62,7 @@ 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.coords); - - findViewById(R.id.actionBarManualbutton).setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View view) { - ActivityMixin.goManual(context, "c:geo-geocoordinate-input"); - } - }); + setContentView(R.layout.coordinatesinput_dialog); final Spinner spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats); final ArrayAdapter<CharSequence> adapter = @@ -346,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)); } @@ -355,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/CustomProgressDialog.java b/main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java index c2b722c..e80c446 100644 --- a/main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java +++ b/main/src/cgeo/geocaching/ui/dialog/CustomProgressDialog.java @@ -19,7 +19,7 @@ import java.lang.reflect.Method; public class CustomProgressDialog extends ProgressDialog { public CustomProgressDialog(Context context) { - super(context, ActivityMixin.getTheme()); + super(context, ActivityMixin.getDialogTheme()); } @Override 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/EditorDialog.java b/main/src/cgeo/geocaching/ui/dialog/EditorDialog.java deleted file mode 100644 index 4db69e5..0000000 --- a/main/src/cgeo/geocaching/ui/dialog/EditorDialog.java +++ /dev/null @@ -1,60 +0,0 @@ -package cgeo.geocaching.ui.dialog; - -import cgeo.geocaching.CacheDetailActivity; -import cgeo.geocaching.R; -import cgeo.geocaching.activity.ActivityMixin; - -import android.app.Dialog; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.Window; -import android.widget.Button; -import android.widget.EditText; - -public class EditorDialog extends Dialog { - - private CharSequence editorText; - private EditorUpdate editorUpdate; - - public EditorDialog(CacheDetailActivity cacheDetailActivity, CharSequence editable) { - super(cacheDetailActivity, ActivityMixin.getTheme()); - this.editorText = editable; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.editor); - - final EditText editText = (EditText) findViewById(R.id.editorEditText); - editText.setText(editorText); - - final Button buttonSave = (Button) findViewById(R.id.editorSave); - buttonSave.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - editorUpdate.update(editText.getEditableText()); - EditorDialog.this.hide(); - } - }); - } - - public interface EditorUpdate { - public void update(CharSequence editorText); - } - - public void setOnEditorUpdate(EditorUpdate editorUpdate) { - this.editorUpdate = editorUpdate; - - } - - @Override - public void show() { - super.show(); - getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - } - -} 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 |
