Merge pull request #7262 from osmandapp/contextMenuForTravelPoints

WptPt context menu upgrade
This commit is contained in:
Alexey 2019-07-16 11:43:42 +03:00 committed by GitHub
commit b0996dc825
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 263 additions and 51 deletions

View file

@ -2,6 +2,7 @@ package net.osmand.plus.mapcontextmenu;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Color; import android.graphics.Color;
@ -14,6 +15,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.view.ContextThemeWrapper; import android.support.v7.view.ContextThemeWrapper;
import android.text.ClipboardManager; import android.text.ClipboardManager;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -500,9 +502,23 @@ public class MenuBuilder {
needLinks, textLinesLimit, isUrl, onClickListener, matchWidthDivider); needLinks, textLinesLimit, isUrl, onClickListener, matchWidthDivider);
} }
public View buildRow(final View view, Drawable icon, final String buttonText, final String text, int textColor, String secondaryText,
boolean collapsable, final CollapsableView collapsableView, boolean needLinks,
int textLinesLimit, boolean isUrl, OnClickListener onClickListener, boolean matchWidthDivider) {
return buildRow(view, icon, buttonText, text, textColor, secondaryText, collapsable, collapsableView,
needLinks, textLinesLimit, isUrl, false, false, onClickListener, matchWidthDivider);
}
public View buildRow(View view, int iconId, String buttonText, String text, int textColor,
boolean collapsable, final CollapsableView collapsableView,
boolean needLinks, int textLinesLimit, boolean isUrl, boolean isNumber, boolean isEmail, OnClickListener onClickListener, boolean matchWidthDivider) {
return buildRow(view, iconId == 0 ? null : getRowIcon(iconId), buttonText, text, textColor, null, collapsable, collapsableView,
needLinks, textLinesLimit, isUrl, isNumber, isEmail, onClickListener, matchWidthDivider);
}
public View buildRow(final View view, Drawable icon, final String buttonText, final String text, int textColor, String secondaryText, public View buildRow(final View view, Drawable icon, final String buttonText, final String text, int textColor, String secondaryText,
boolean collapsable, final CollapsableView collapsableView, boolean needLinks, boolean collapsable, final CollapsableView collapsableView, boolean needLinks,
int textLinesLimit, boolean isUrl, OnClickListener onClickListener, boolean matchWidthDivider) { int textLinesLimit, boolean isUrl, boolean isNumber, boolean isEmail, OnClickListener onClickListener, boolean matchWidthDivider) {
if (!isFirstRow()) { if (!isFirstRow()) {
buildRowDivider(view); buildRowDivider(view);
@ -567,7 +583,7 @@ public class MenuBuilder {
int linkTextColor = ContextCompat.getColor(view.getContext(), light ? R.color.ctx_menu_bottom_view_url_color_light : R.color.ctx_menu_bottom_view_url_color_dark); int linkTextColor = ContextCompat.getColor(view.getContext(), light ? R.color.ctx_menu_bottom_view_url_color_light : R.color.ctx_menu_bottom_view_url_color_dark);
if (isUrl) { if (isUrl || isNumber || isEmail) {
textView.setTextColor(linkTextColor); textView.setTextColor(linkTextColor);
} else if (needLinks) { } else if (needLinks) {
Linkify.addLinks(textView, Linkify.ALL); Linkify.addLinks(textView, Linkify.ALL);
@ -664,6 +680,22 @@ public class MenuBuilder {
v.getContext().startActivity(intent); v.getContext().startActivity(intent);
} }
}); });
} else if (isNumber) {
ll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
showDialog(text, Intent.ACTION_DIAL, "tel:", v);
}
});
} else if (isEmail) {
ll.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:" + text));
v.getContext().startActivity(intent);
}
});
} }
((LinearLayout) view).addView(baseView); ((LinearLayout) view).addView(baseView);
@ -674,6 +706,29 @@ public class MenuBuilder {
return ll; return ll;
} }
protected void showDialog(String text, final String actionType, final String dataPrefix, final View v) {
final String[] items = text.split("[,;]");
final Intent intent = new Intent(actionType);
if (items.length > 1) {
for (int i = 0; i < items.length; i++) {
items[i] = items[i].trim();
}
AlertDialog.Builder dlg = new AlertDialog.Builder(v.getContext());
dlg.setNegativeButton(R.string.shared_string_cancel, null);
dlg.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
intent.setData(Uri.parse(dataPrefix + items[which]));
v.getContext().startActivity(intent);
}
});
dlg.show();
} else {
intent.setData(Uri.parse(dataPrefix + text));
v.getContext().startActivity(intent);
}
}
protected void setDividerWidth(boolean matchWidthDivider) { protected void setDividerWidth(boolean matchWidthDivider) {
this.matchWidthDivider = matchWidthDivider; this.matchWidthDivider = matchWidthDivider;

View file

@ -198,7 +198,7 @@ public abstract class MenuController extends BaseMenuController implements Colla
} else if (object instanceof OsmPoint) { } else if (object instanceof OsmPoint) {
menuController = new EditPOIMenuController(mapActivity, pointDescription, (OsmPoint) object); menuController = new EditPOIMenuController(mapActivity, pointDescription, (OsmPoint) object);
} else if (object instanceof WptPt) { } else if (object instanceof WptPt) {
menuController = new WptPtMenuController(mapActivity, pointDescription, (WptPt) object); menuController = WptPtMenuController.getInstance(mapActivity, pointDescription, (WptPt) object);
} else if (object instanceof DownloadMapObject) { } else if (object instanceof DownloadMapObject) {
menuController = new MapDataMenuController(mapActivity, pointDescription, (DownloadMapObject) object); menuController = new MapDataMenuController(mapActivity, pointDescription, (DownloadMapObject) object);
} else if (object instanceof OpenStreetNote) { } else if (object instanceof OpenStreetNote) {

View file

@ -282,24 +282,7 @@ public class AmenityMenuBuilder extends MenuBuilder {
ll.setOnClickListener(new View.OnClickListener() { ll.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(final View v) { public void onClick(final View v) {
final String[] phones = text.split(",|;"); showDialog(text, Intent.ACTION_DIAL, "tel:", v);
if (phones.length > 1) {
AlertDialog.Builder dlg = new AlertDialog.Builder(v.getContext());
dlg.setNegativeButton(R.string.shared_string_cancel, null);
dlg.setItems(phones, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + phones[which]));
v.getContext().startActivity(intent);
}
});
dlg.show();
} else {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + text));
v.getContext().startActivity(intent);
}
} }
}); });
} else if (isUrl) { } else if (isUrl) {

View file

@ -30,7 +30,6 @@ import java.util.Date;
import java.util.List; import java.util.List;
public class WptPtMenuBuilder extends MenuBuilder { public class WptPtMenuBuilder extends MenuBuilder {
private final WptPt wpt; private final WptPt wpt;
public WptPtMenuBuilder(@NonNull MapActivity mapActivity, final @NonNull WptPt wpt) { public WptPtMenuBuilder(@NonNull MapActivity mapActivity, final @NonNull WptPt wpt) {
@ -72,16 +71,11 @@ public class WptPtMenuBuilder extends MenuBuilder {
null, Algorithms.capitalizeFirstLetterAndLowercase(app.getString(R.string.plugin_distance_point_hdop)) + ": " + (int)wpt.hdop, 0, null, Algorithms.capitalizeFirstLetterAndLowercase(app.getString(R.string.plugin_distance_point_hdop)) + ": " + (int)wpt.hdop, 0,
false, null, false, 0, false, null, false); false, null, false, 0, false, null, false);
} }
if (!Algorithms.isEmpty(wpt.desc)) { if (!Algorithms.isEmpty(wpt.desc)) {
final View row = buildRow(view, R.drawable.ic_action_note_dark, null, wpt.desc, 0, false, null, true, 10, false, null, false); prepareDescription(wpt, view);
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
POIMapLayer.showDescriptionDialog(row.getContext(), app, wpt.desc,
row.getResources().getString(R.string.shared_string_description));
}
});
} }
if (!Algorithms.isEmpty(wpt.comment)) { if (!Algorithms.isEmpty(wpt.comment)) {
final View rowc = buildRow(view, R.drawable.ic_action_note_dark, null, wpt.comment, 0, final View rowc = buildRow(view, R.drawable.ic_action_note_dark, null, wpt.comment, 0,
false, null, true, 10, false, null, false); false, null, true, 10, false, null, false);
@ -96,6 +90,19 @@ public class WptPtMenuBuilder extends MenuBuilder {
buildPlainMenuItems(view); buildPlainMenuItems(view);
} }
protected void prepareDescription(final WptPt wpt, View view) {
if (!Algorithms.isEmpty(wpt.desc)) {
final View row = buildRow(view, R.drawable.ic_action_note_dark, null, wpt.desc, 0, false, null, true, 10, false, null, false);
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
POIMapLayer.showDescriptionDialog(row.getContext(), app, wpt.desc,
row.getResources().getString(R.string.shared_string_description));
}
});
}
}
private void buildWaypointsView(View view) { private void buildWaypointsView(View view) {
GpxSelectionHelper gpxSelectionHelper = app.getSelectedGpxHelper(); GpxSelectionHelper gpxSelectionHelper = app.getSelectedGpxHelper();
@ -138,24 +145,32 @@ public class WptPtMenuBuilder extends MenuBuilder {
LinearLayout view = (LinearLayout) buildCollapsableContentView(context, collapsed, true); LinearLayout view = (LinearLayout) buildCollapsableContentView(context, collapsed, true);
List<WptPt> points = gpxFile.getPoints(); List<WptPt> points = gpxFile.getPoints();
for (int i = 0; i < points.size() && i < 10; i++) { String selectedCategory = selectedPoint != null && selectedPoint.category != null ? selectedPoint.category : "";
final WptPt point = points.get(i); int showCount = 0;
boolean selected = selectedPoint != null && selectedPoint.equals(point); for (final WptPt point : points) {
TextViewEx button = buildButtonInCollapsableView(context, selected, false); String currentCategory = point != null ? point.category : null;
button.setText(point.name); if (selectedCategory.equals(currentCategory)) {
showCount++;
boolean selected = selectedPoint != null && selectedPoint.equals(point);
TextViewEx button = buildButtonInCollapsableView(context, selected, false);
button.setText(point.name);
if (!selected) { if (!selected) {
button.setOnClickListener(new View.OnClickListener() { button.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LatLon latLon = new LatLon(point.getLatitude(), point.getLongitude()); LatLon latLon = new LatLon(point.getLatitude(), point.getLongitude());
PointDescription pointDescription = new PointDescription(PointDescription.POINT_TYPE_WPT, point.name); PointDescription pointDescription = new PointDescription(PointDescription.POINT_TYPE_WPT, point.name);
mapActivity.getContextMenu().setCenterMarker(true); mapActivity.getContextMenu().setCenterMarker(true);
mapActivity.getContextMenu().show(latLon, pointDescription, point); mapActivity.getContextMenu().show(latLon, pointDescription, point);
} }
}); });
}
view.addView(button);
}
if (showCount >= 10) {
break;
} }
view.addView(button);
} }
if (points.size() > 10) { if (points.size() > 10) {

View file

@ -3,7 +3,9 @@ package net.osmand.plus.mapcontextmenu.controllers;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.util.Log;
import net.osmand.GPXUtilities;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
import net.osmand.data.PointDescription; import net.osmand.data.PointDescription;
import net.osmand.GPXUtilities.WptPt; import net.osmand.GPXUtilities.WptPt;
@ -14,27 +16,32 @@ import net.osmand.plus.MapMarkersHelper.MapMarker;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.FavoriteImageDrawable; import net.osmand.plus.base.FavoriteImageDrawable;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapcontextmenu.MenuController; import net.osmand.plus.mapcontextmenu.MenuController;
import net.osmand.plus.mapcontextmenu.builders.WptPtMenuBuilder; import net.osmand.plus.mapcontextmenu.builders.WptPtMenuBuilder;
import net.osmand.plus.wikivoyage.menu.WikivoyageWptPtMenuBuilder;
import net.osmand.plus.wikivoyage.menu.WikivoyageWptPtMenuController;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import java.io.File; import java.io.File;
import java.util.Map;
public class WptPtMenuController extends MenuController { public class WptPtMenuController extends MenuController {
private WptPt wpt; private WptPt wpt;
private MapMarker mapMarker; private MapMarker mapMarker;
private MapActivity mapActivity;
public WptPtMenuController(@NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull WptPt wpt) { public WptPtMenuController(@NonNull MenuBuilder menuBuilder, @NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull final WptPt wpt) {
super(new WptPtMenuBuilder(mapActivity, wpt), pointDescription, mapActivity); super(menuBuilder, pointDescription, mapActivity);
this.wpt = wpt; this.wpt = wpt;
this.mapActivity = mapActivity;
final MapMarkersHelper markersHelper = mapActivity.getMyApplication().getMapMarkersHelper(); final MapMarkersHelper markersHelper = mapActivity.getMyApplication().getMapMarkersHelper();
mapMarker = markersHelper.getMapMarker(wpt); mapMarker = markersHelper.getMapMarker(wpt);
if (mapMarker == null) { if (mapMarker == null) {
mapMarker = markersHelper.getMapMarker(new LatLon(wpt.lat, wpt.lon)); mapMarker = markersHelper.getMapMarker(new LatLon(wpt.lat, wpt.lon));
} } else {
if (mapMarker != null) {
MapMarkerMenuController markerMenuController = MapMarkerMenuController markerMenuController =
new MapMarkerMenuController(mapActivity, mapMarker.getPointDescription(mapActivity), mapMarker); new MapMarkerMenuController(mapActivity, mapMarker.getPointDescription(mapActivity), mapMarker);
leftTitleButtonController = markerMenuController.getLeftTitleButtonController(); leftTitleButtonController = markerMenuController.getLeftTitleButtonController();
@ -138,4 +145,16 @@ public class WptPtMenuController extends MenuController {
return ""; return "";
} }
} }
}
public static WptPtMenuController getInstance(@NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull final WptPt wpt) {
SelectedGpxFile selectedGpxFile = mapActivity.getMyApplication().getSelectedGpxHelper().getSelectedGPXFile(wpt);
GPXUtilities.GPXFile gpxFile = selectedGpxFile != null ? selectedGpxFile.getGpxFile() : null;
GPXUtilities.Metadata metadata = gpxFile != null ? gpxFile.metadata : null;
Map<String, String> extensions = metadata != null ? metadata.getExtensionsToRead() : null;
String metadataDesc = extensions != null ? metadata.getExtensionsToRead().get("desc") : null;
if (metadataDesc != null && metadataDesc.contains("wikivoyage.org/")) {
return new WikivoyageWptPtMenuController(new WikivoyageWptPtMenuBuilder(mapActivity, wpt), mapActivity, pointDescription, wpt, gpxFile);
}
return new WptPtMenuController(new WptPtMenuBuilder(mapActivity, wpt), mapActivity, pointDescription, wpt);
}
}

View file

@ -0,0 +1,98 @@
package net.osmand.plus.wikivoyage.menu;
import android.support.annotation.NonNull;
import android.view.View;
import net.osmand.GPXUtilities;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.builders.WptPtMenuBuilder;
import net.osmand.util.Algorithms;
import java.util.HashMap;
public class WikivoyageWptPtMenuBuilder extends WptPtMenuBuilder {
final String KEY_PHONE = "Phone: ";
final String KEY_EMAIL = "Email: ";
final String KEY_WORKING_HOURS = "Working hours: ";
final String KEY_PRICE = "Price: ";
final String KEY_DIRECTIONS = "Directions: ";
final String KEY_OTHER_DESCRIPTION = "Other description";
public WikivoyageWptPtMenuBuilder(@NonNull MapActivity mapActivity, @NonNull GPXUtilities.WptPt wpt) {
super(mapActivity, wpt);
}
@Override
protected void prepareDescription(final GPXUtilities.WptPt wpt, View view) {
String description = wpt.desc;
if (!description.contains("\n")) {
super.prepareDescription(wpt, view);
return;
}
HashMap<String, String> descTokens = getDescriptionTokens(description, KEY_PHONE, KEY_EMAIL, KEY_WORKING_HOURS, KEY_PRICE, KEY_DIRECTIONS);
String phones = descTokens.get(KEY_PHONE);
String emails = descTokens.get(KEY_EMAIL);
String workingHours = descTokens.get(KEY_WORKING_HOURS);
String price = descTokens.get(KEY_PRICE);
String direction = descTokens.get(KEY_DIRECTIONS);
final String desc = descTokens.get(KEY_OTHER_DESCRIPTION);
if (!Algorithms.isEmpty(desc)) {
buildRow(view, R.drawable.ic_action_note_dark, null, desc, 0, false, null, true, 10, false, null, false);
}
if (!Algorithms.isEmpty(phones)) {
buildRow(view, R.drawable.ic_action_call_dark,
null, phones, 0,
false, null, false, 0, false, true, false, null, false);
}
if (!Algorithms.isEmpty(wpt.link)) {
buildRow(view, R.drawable.ic_world_globe_dark,
null, wpt.link, 0,
false, null, false, 0, true, null, false);
}
if (!Algorithms.isEmpty(emails)) {
buildRow(view, R.drawable.ic_action_message,
null, emails, 0,
false, null, false, 0, false, false, true, null, false);
}
if (!Algorithms.isEmpty(workingHours)) {
buildRow(view, R.drawable.ic_action_time,
null, workingHours, 0,
false, null, false, 0, false, null, false);
}
if (!Algorithms.isEmpty(direction)) {
buildRow(view, R.drawable.ic_action_gdirections_dark,
null, direction, 0,
false, null, false, 0, false, null, false);
}
if (!Algorithms.isEmpty(price)) {
buildRow(view, R.drawable.ic_action_price_tag,
null, price, 0,
false, null, false, 0, false, null, false);
}
}
private HashMap<String, String> getDescriptionTokens(String desc, String ... allowedKeys) {
String[] tokens = desc.split("\n");
HashMap<String, String> mTokens = new HashMap<>();
for (String token : tokens) {
boolean matched = false;
for (String key : allowedKeys) {
if (token.startsWith(key)) {
matched = true;
String value = token.substring(key.length()).trim();
mTokens.put(key, value);
}
}
if (!matched) {
String s = mTokens.get(KEY_OTHER_DESCRIPTION);
mTokens.put(KEY_OTHER_DESCRIPTION, s != null ? s + "\n" + token : token);
}
}
return mTokens;
}
}

View file

@ -0,0 +1,42 @@
package net.osmand.plus.wikivoyage.menu;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import net.osmand.GPXUtilities;
import net.osmand.data.PointDescription;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapcontextmenu.controllers.WptPtMenuController;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
import net.osmand.plus.wikivoyage.data.TravelArticle;
public class WikivoyageWptPtMenuController extends WptPtMenuController {
public WikivoyageWptPtMenuController(@NonNull MenuBuilder menuBuilder, @NonNull final MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull GPXUtilities.WptPt wpt, GPXUtilities.GPXFile gpxFile) {
super(menuBuilder, mapActivity, pointDescription, wpt);
GPXUtilities.Metadata metadata = gpxFile != null ? gpxFile.metadata : null;
final TravelArticle article = metadata != null ? getTravelArticle(metadata) : null;
if (article != null) {
leftTitleButtonController = new TitleButtonController() {
@Override
public void buttonPressed() {
WikivoyageArticleDialogFragment.showInstance(mapActivity.getMyApplication(), mapActivity.getSupportFragmentManager(), article.getTripId(), article.getLang());
}
};
leftTitleButtonController.caption = mapActivity.getString(R.string.context_menu_read_article);
leftTitleButtonController.leftIconId = R.drawable.ic_action_read_text;
}
}
private TravelArticle getTravelArticle(@NonNull GPXUtilities.Metadata metadata) {
String title = metadata.getArticleTitle();
String lang = metadata.getArticleLang();
if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(lang)) {
return getMapActivity().getMyApplication().getTravelDbHelper().getArticle(title, lang);
}
return null;
}
}