From bf1e436f2b072377dc1cc142fdd6807cb8cd33d4 Mon Sep 17 00:00:00 2001 From: Chumva Date: Fri, 14 Dec 2018 11:16:23 +0200 Subject: [PATCH] Add transport cards initial commit --- .../osmand/router/TransportRoutePlanner.java | 10 +- OsmAnd/res/layout/transport_route_card.xml | 92 +++++++ .../transport_stop_route_item_with_icon.xml | 31 +++ .../plus/routepreparationmenu/FlowLayout.java | 118 +++++++++ .../MapRouteInfoMenu.java | 170 ++++--------- .../MapRouteInfoMenuFragment.java | 20 +- .../routeCards/BaseRouteCard.java | 54 +++++ .../routeCards/PublicTransportCard.java | 229 ++++++++++++++++++ .../routeCards/SimpleRouteCard.java | 156 ++++++++++++ 9 files changed, 742 insertions(+), 138 deletions(-) create mode 100644 OsmAnd/res/layout/transport_route_card.xml create mode 100644 OsmAnd/res/layout/transport_stop_route_item_with_icon.xml create mode 100644 OsmAnd/src/net/osmand/plus/routepreparationmenu/FlowLayout.java create mode 100644 OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/BaseRouteCard.java create mode 100644 OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/PublicTransportCard.java create mode 100644 OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/SimpleRouteCard.java diff --git a/OsmAnd-java/src/main/java/net/osmand/router/TransportRoutePlanner.java b/OsmAnd-java/src/main/java/net/osmand/router/TransportRoutePlanner.java index d93665ffca..d3303124ab 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/TransportRoutePlanner.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/TransportRoutePlanner.java @@ -335,7 +335,15 @@ public class TransportRoutePlanner { } return d; } - + + public double getFinishWalkDist() { + return finishWalkDist; + } + + public double getWalkSpeed() { + return cfg.walkSpeed; + } + public double getRouteTime() { return routeTime; } diff --git a/OsmAnd/res/layout/transport_route_card.xml b/OsmAnd/res/layout/transport_route_card.xml new file mode 100644 index 0000000000..4af59dda77 --- /dev/null +++ b/OsmAnd/res/layout/transport_route_card.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/transport_stop_route_item_with_icon.xml b/OsmAnd/res/layout/transport_stop_route_item_with_icon.xml new file mode 100644 index 0000000000..b0898ae4cc --- /dev/null +++ b/OsmAnd/res/layout/transport_stop_route_item_with_icon.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/FlowLayout.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FlowLayout.java new file mode 100644 index 0000000000..3e7d483555 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/FlowLayout.java @@ -0,0 +1,118 @@ +package net.osmand.plus.routepreparationmenu; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + + +public class FlowLayout extends ViewGroup { + + private int line_height; + + public static class LayoutParams extends ViewGroup.LayoutParams { + + public final int horizontal_spacing; + public final int vertical_spacing; + + /** + * @param horizontal_spacing Pixels between items, horizontally + * @param vertical_spacing Pixels between items, vertically + */ + public LayoutParams(int horizontal_spacing, int vertical_spacing) { + super(0, 0); + this.horizontal_spacing = horizontal_spacing; + this.vertical_spacing = vertical_spacing; + } + } + + public FlowLayout(Context context) { + super(context); + } + + public FlowLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED); + + final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); + int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom(); + final int count = getChildCount(); + int line_height = 0; + + int xpos = getPaddingLeft(); + int ypos = getPaddingTop(); + + int childHeightMeasureSpec; + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + } else { + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + } + + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec); + final int childw = child.getMeasuredWidth(); + line_height = Math.max(line_height, child.getMeasuredHeight() + lp.vertical_spacing); + + if (xpos + childw > width) { + xpos = getPaddingLeft(); + ypos += line_height; + } + + xpos += childw + lp.horizontal_spacing; + } + } + this.line_height = line_height; + + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) { + height = ypos + line_height; + + } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { + if (ypos + line_height < height) { + height = ypos + line_height; + } + } + setMeasuredDimension(width, height); + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(1, 1); // default of 1px spacing + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int count = getChildCount(); + final int width = r - l; + int xpos = getPaddingLeft(); + int ypos = getPaddingTop(); + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final int childw = child.getMeasuredWidth(); + final int childh = child.getMeasuredHeight(); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (xpos + childw > width) { + xpos = getPaddingLeft(); + ypos += line_height; + } + child.layout(xpos, ypos, xpos + childw, ypos + childh); + xpos += childw + lp.horizontal_spacing; + } + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java index e67a69e405..dac4673540 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java @@ -28,10 +28,6 @@ import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; -import com.github.mikephil.charting.charts.LineChart; -import com.github.mikephil.charting.data.LineData; -import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; - import net.osmand.AndroidUtils; import net.osmand.Location; import net.osmand.StateChangedListener; @@ -46,7 +42,6 @@ import net.osmand.plus.GeocodingLookupService; import net.osmand.plus.GeocodingLookupService.AddressLookupRequest; import net.osmand.plus.MapMarkersHelper; import net.osmand.plus.MapMarkersHelper.MapMarker; -import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.OsmandSettings.OsmandPreference; @@ -56,21 +51,23 @@ import net.osmand.plus.TargetPointsHelper.TargetPoint; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.SettingsBaseActivity; -import net.osmand.plus.activities.ShowRouteInfoDialogFragment; import net.osmand.plus.activities.actions.AppModeDialog; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.AvoidSpecificRoads; -import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.MapMarkerDialogHelper; import net.osmand.plus.helpers.WaypointHelper; import net.osmand.plus.mapcontextmenu.other.FavouritesBottomSheetMenuFragment; import net.osmand.plus.mapmarkers.MapMarkerSelectionFragment; import net.osmand.plus.poi.PoiUIFilter; +import net.osmand.plus.routepreparationmenu.routeCards.BaseRouteCard; +import net.osmand.plus.routepreparationmenu.routeCards.PublicTransportCard; +import net.osmand.plus.routepreparationmenu.routeCards.SimpleRouteCard; import net.osmand.plus.routing.IRouteInformationListener; -import net.osmand.plus.routing.RouteDirectionInfo; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.TransportRoutingHelper; import net.osmand.plus.views.MapControlsLayer; import net.osmand.router.GeneralRouter; +import net.osmand.router.TransportRoutePlanner; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -93,20 +90,23 @@ public class MapRouteInfoMenu implements IRouteInformationListener { } public static int directionInfo = -1; + private static boolean visible; public static boolean controlVisible = false; + public static final String TARGET_SELECT = "TARGET_SELECT"; + private final RoutingHelper routingHelper; + private final TransportRoutingHelper transportHelper; private final RoutingOptionsHelper routingOptionsHelper; private GeocodingLookupService geocodingLookupService; + private boolean selectFromMapTouch; private boolean selectFromMapForTarget; private boolean selectFromMapForIntermediate; private boolean showMenu = false; - private static boolean visible; private MapActivity mapActivity; private OsmandApplication app; private MapControlsLayer mapControlsLayer; - public static final String TARGET_SELECT = "TARGET_SELECT"; private boolean nightMode; private boolean switched; @@ -114,6 +114,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener { private AddressLookupRequest targetPointRequest; private List intermediateRequestsLatLon = new ArrayList<>(); private OnDismissListener onDismissListener; + private List routeCards = new ArrayList(); private OnMarkerSelectListener onMarkerSelectListener; private StateChangedListener onStateChangedListener; @@ -121,9 +122,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener { private int currentMenuState; private boolean portraitMode; - private GPXUtilities.GPXFile gpx; - private GpxUiHelper.OrderedLineDataSet elevationDataSet; - private GpxUiHelper.OrderedLineDataSet slopeDataSet; private static final long SPINNER_MY_LOCATION_ID = 1; public static final long SPINNER_FAV_ID = 2; @@ -145,8 +143,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener { this.mapActivity = mapActivity; this.app = mapActivity.getMyApplication(); this.mapControlsLayer = mapControlsLayer; - routingHelper = mapActivity.getRoutingHelper(); - routingOptionsHelper = app.getRoutingOptionsHelper(); + this.routingHelper = mapActivity.getRoutingHelper(); + this.transportHelper = routingHelper.getTransportRoutingHelper(); + this.routingOptionsHelper = app.getRoutingOptionsHelper(); + routingHelper.addListener(this); portraitMode = AndroidUiHelper.isOrientationPortrait(mapActivity); currentMenuState = getInitialMenuState(); @@ -316,6 +316,7 @@ public class MapRouteInfoMenu implements IRouteInformationListener { if (fragmentRef != null) { fragmentRef.get().hideRouteCalculationProgressBar(); fragmentRef.get().updateControlButtons(); + fragmentRef.get().updateInfo(); if (currentMenuState == MenuState.HEADER_ONLY) { fragmentRef.get().openMenuHalfScreen(); } @@ -334,6 +335,14 @@ public class MapRouteInfoMenu implements IRouteInformationListener { fragmentRef.get().updateFromIcon(); } + public void build(LinearLayout rootView) { + rootView.removeAllViews(); + for (BaseRouteCard card : routeCards) { + card.bindViewHolder(); + rootView.addView(card.getView()); + } + } + public void updateInfo(final View main) { mainView = main; nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls(); @@ -344,16 +353,32 @@ public class MapRouteInfoMenu implements IRouteInformationListener { updateApplicationModesOptions(main); updateOptionsButtons(main); + routeCards.clear(); if (isRouteCalculated()) { - makeGpx(); - updateRouteButtons(main); + GPXUtilities.GPXFile gpx = GPXUtilities.makeGpxFromRoute(routingHelper.getRoute()); + if (gpx != null) { + routeCards.add(new SimpleRouteCard(mapActivity, nightMode, gpx)); + LinearLayout bottomView = (LinearLayout) mainView.findViewById(R.id.route_menu_cards_container); + build(bottomView); + } + } else if ((routingHelper.isPublicTransportMode() && transportHelper.getRoutes() != null)) { + List routes = transportHelper.getRoutes(); + for (int i = 0; i < routes.size(); i++) { + PublicTransportCard card = new PublicTransportCard(mapActivity, nightMode, routes.get(i), i); + if (i == routes.size() - 1) { + card.setLastItem(true); + } + routeCards.add(card); + } + LinearLayout bottomView = (LinearLayout) mainView.findViewById(R.id.route_menu_cards_container); + build(bottomView); } else { updateRouteCalcProgress(main); } } public boolean isRouteCalculated() { - return routingHelper.isRouteCalculated(); + return routingHelper.getFinalLocation() != null && routingHelper.isRouteCalculated(); } private void updateApplicationModesOptions(final View parentView) { @@ -402,7 +427,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener { = mapActivity.getMyApplication().getSettings().APPLICATION_MODE; if (routingHelper.isFollowingMode() && appMode.get() == mode) { appMode.set(next); - //updateMenu(); } routingHelper.setAppMode(next); mapActivity.getMyApplication().initVoiceCommandPlayer(mapActivity, next, true, null, false, false); @@ -410,7 +434,10 @@ public class MapRouteInfoMenu implements IRouteInformationListener { } private void updateRouteCalcProgress(final View main) { - main.findViewById(R.id.route_info_details_card).setVisibility(View.GONE); + LinearLayout cardsContainer = (LinearLayout) main.findViewById(R.id.route_menu_cards_container); + if (cardsContainer != null) { + cardsContainer.removeAllViews(); + } } private void updateApplicationModes(final View parentView) { @@ -463,10 +490,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener { } } - private void makeGpx() { - gpx = GPXUtilities.makeGpxFromRoute(routingHelper.getRoute()); - } - private void updateOptionsButtons(final View main) { final boolean nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls(); final OsmandSettings settings = app.getSettings(); @@ -843,105 +866,6 @@ public class MapRouteInfoMenu implements IRouteInformationListener { } } - private void updateRouteButtons(final View mainView) { - mainView.findViewById(R.id.dividerToDropDown).setVisibility(View.VISIBLE); - mainView.findViewById(R.id.route_info_details_card).setVisibility(View.VISIBLE); - final OsmandApplication ctx = mapActivity.getMyApplication(); - - View info = mainView.findViewById(R.id.info_container); - info.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ShowRouteInfoDialogFragment.showDialog(mapActivity.getSupportFragmentManager()); - } - }); - - ImageView infoIcon = (ImageView) mainView.findViewById(R.id.InfoIcon); - ImageView durationIcon = (ImageView) mainView.findViewById(R.id.DurationIcon); - View infoDistanceView = mainView.findViewById(R.id.InfoDistance); - View infoDurationView = mainView.findViewById(R.id.InfoDuration); - if (directionInfo >= 0) { - infoIcon.setVisibility(View.GONE); - durationIcon.setVisibility(View.GONE); - infoDistanceView.setVisibility(View.GONE); - infoDurationView.setVisibility(View.GONE); - } else { - infoIcon.setImageDrawable(ctx.getUIUtilities().getIcon(R.drawable.ic_action_route_distance, R.color.route_info_unchecked_mode_icon_color)); - infoIcon.setVisibility(View.VISIBLE); - durationIcon.setImageDrawable(ctx.getUIUtilities().getIcon(R.drawable.ic_action_time_span, R.color.route_info_unchecked_mode_icon_color)); - durationIcon.setVisibility(View.VISIBLE); - infoDistanceView.setVisibility(View.VISIBLE); - infoDurationView.setVisibility(View.VISIBLE); - } - if (directionInfo >= 0 && routingHelper.getRouteDirections() != null - && directionInfo < routingHelper.getRouteDirections().size()) { - RouteDirectionInfo ri = routingHelper.getRouteDirections().get(directionInfo); - } else { - TextView distanceText = (TextView) mainView.findViewById(R.id.DistanceText); - TextView distanceTitle = (TextView) mainView.findViewById(R.id.DistanceTitle); - TextView durationText = (TextView) mainView.findViewById(R.id.DurationText); - TextView durationTitle = (TextView) mainView.findViewById(R.id.DurationTitle); - - distanceText.setText(OsmAndFormatter.getFormattedDistance(ctx.getRoutingHelper().getLeftDistance(), ctx)); - - durationText.setText(OsmAndFormatter.getFormattedDuration(ctx.getRoutingHelper().getLeftTime(), ctx)); - durationTitle.setText(ctx.getString(R.string.arrive_at_time, OsmAndFormatter.getFormattedTime(ctx.getRoutingHelper().getLeftTime(), true))); - - AndroidUtils.setTextPrimaryColor(ctx, distanceText, nightMode); - AndroidUtils.setTextSecondaryColor(ctx, distanceTitle, nightMode); - AndroidUtils.setTextPrimaryColor(ctx, durationText, nightMode); - AndroidUtils.setTextSecondaryColor(ctx, durationTitle, nightMode); - } - - FrameLayout detailsButton = mainView.findViewById(R.id.details_button); - - AndroidUtils.setBackground(app, detailsButton, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { - AndroidUtils.setBackground(app, mainView.findViewById(R.id.details_button_descr), nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); - } else { - AndroidUtils.setBackground(app, mainView.findViewById(R.id.details_button_descr), nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); - } - int color = ContextCompat.getColor(mapActivity, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light); - - ((TextView) mainView.findViewById(R.id.details_button_descr)).setTextColor(color); - - detailsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ShowRouteInfoDialogFragment.showDialog(mapActivity.getSupportFragmentManager()); - } - }); - - buildHeader(mainView); - } - - private void buildHeader(View headerView) { - OsmandApplication app = mapActivity.getMyApplication(); - final LineChart mChart = (LineChart) headerView.findViewById(R.id.chart); - final GPXUtilities.GPXTrackAnalysis analysis = gpx.getAnalysis(0); - - GpxUiHelper.setupGPXChart(mChart, 4, 4f, 4f, !nightMode, false); - if (analysis.hasElevationData) { - List dataSets = new ArrayList<>(); - elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis, - GpxUiHelper.GPXDataSetAxisType.DISTANCE, false, true); - if (elevationDataSet != null) { - dataSets.add(elevationDataSet); - } - slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis, - GpxUiHelper.GPXDataSetAxisType.DISTANCE, elevationDataSet.getValues(), true, true); - if (slopeDataSet != null) { - dataSets.add(slopeDataSet); - } - mChart.setData(new LineData(dataSets)); - mChart.setVisibility(View.VISIBLE); - } else { - elevationDataSet = null; - slopeDataSet = null; - mChart.setVisibility(View.GONE); - } - } - private void updateViaView(final View parentView) { String via = generateViaDescription(); View viaLayout = parentView.findViewById(R.id.ViaLayout); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenuFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenuFragment.java index 97ac745dd6..9a8292a1d1 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenuFragment.java @@ -55,6 +55,7 @@ public class MapRouteInfoMenuFragment extends BaseOsmAndFragment { private MapRouteInfoMenu menu; private InterceptorLinearLayout mainView; private View view; + private LinearLayout cardsContainer; private View.OnLayoutChangeListener containerLayoutListener; private boolean portrait; @@ -118,7 +119,8 @@ public class MapRouteInfoMenuFragment extends BaseOsmAndFragment { bottomContainer.setForeground(null); } - view.findViewById(R.id.route_menu_bottom_view).setBackgroundColor(getResources().getColor(nightMode ? R.color.activity_background_dark : R.color.activity_background_light)); + cardsContainer = (LinearLayout) view.findViewById(R.id.route_menu_cards_container); +// cardsContainer.setBackgroundColor(getResources().getColor(nightMode ? R.color.activity_background_dark : R.color.activity_background_light)); buildBottomView(); @@ -338,10 +340,8 @@ public class MapRouteInfoMenuFragment extends BaseOsmAndFragment { } private void buildBottomView() { - if (view != null) { - LinearLayout bottomView = view.findViewById(R.id.route_menu_bottom_view); - View view = getMapActivity().getLayoutInflater().inflate(R.layout.route_info_statistic, bottomView); - view.setBackgroundColor(ContextCompat.getColor(getMapActivity(), nightMode ? R.color.route_info_bg_dark : R.color.route_info_bg_light)); + if (cardsContainer != null) { + menu.build(cardsContainer); } } @@ -595,7 +595,7 @@ public class MapRouteInfoMenuFragment extends BaseOsmAndFragment { menuTopShadowAllHeight = newMenuTopShadowAllHeight; menuTitleHeight = menuTopShadowAllHeight + dy; - menuBottomViewHeight = view.findViewById(R.id.route_menu_bottom_view).getHeight(); + menuBottomViewHeight = view.findViewById(R.id.route_menu_cards_container).getHeight(); menuFullHeightMax = menuTitleHeight + menuBottomViewHeight; @@ -796,16 +796,8 @@ public class MapRouteInfoMenuFragment extends BaseOsmAndFragment { R.color.divider_light, R.color.divider_dark); AndroidUtils.setBackground(ctx, mainView.findViewById(R.id.app_modes_options_container), nightMode, R.drawable.route_info_trans_gradient_light, R.drawable.route_info_trans_gradient_dark); - AndroidUtils.setBackground(ctx, mainView.findViewById(R.id.dividerToDropDown), nightMode, - R.color.divider_light, R.color.divider_dark); AndroidUtils.setBackground(ctx, view.findViewById(R.id.dividerControlButtons), nightMode, R.color.divider_light, R.color.divider_dark); - AndroidUtils.setBackground(ctx, mainView.findViewById(R.id.info_divider), nightMode, - R.color.activity_background_light, R.color.route_info_cancel_button_color_dark); - AndroidUtils.setBackground(ctx, mainView.findViewById(R.id.route_info_details_card), nightMode, - R.color.activity_background_light, R.color.route_info_cancel_button_color_dark); - AndroidUtils.setBackground(ctx, mainView.findViewById(R.id.RouteInfoControls), nightMode, - R.color.route_info_bg_light, R.color.route_info_bg_dark); int color = ContextCompat.getColor(getMapActivity(), nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/BaseRouteCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/BaseRouteCard.java new file mode 100644 index 0000000000..b9fe680506 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/BaseRouteCard.java @@ -0,0 +1,54 @@ +package net.osmand.plus.routepreparationmenu.routeCards; + +import android.graphics.drawable.Drawable; +import android.support.annotation.ColorInt; +import android.support.annotation.ColorRes; +import android.support.annotation.DrawableRes; +import android.support.v4.content.ContextCompat; +import android.view.View; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; + +public abstract class BaseRouteCard { + + protected OsmandApplication app; + protected boolean nightMode; + protected View view; + protected boolean isLastItem; + + public BaseRouteCard(OsmandApplication app, boolean nightMode) { + this.app = app; + this.nightMode = nightMode; + } + + public abstract void bindViewHolder(); + + public View getView() { + return view; + } + + @ColorInt + protected int getResolvedColor(@ColorRes int colorId) { + return ContextCompat.getColor(app, colorId); + } + + protected Drawable getContentIcon(@DrawableRes int icon) { + return getColoredIcon(icon, R.color.icon_color); + } + + protected Drawable getActiveIcon(@DrawableRes int icon) { + return getColoredIcon(icon, R.color.active_buttons_and_links_light, R.color.active_buttons_and_links_dark); + } + + protected Drawable getColoredIcon(@DrawableRes int icon, @ColorRes int colorLight, @ColorRes int colorDark) { + return getColoredIcon(icon, nightMode ? colorDark : colorLight); + } + + protected Drawable getColoredIcon(@DrawableRes int icon, @ColorRes int color) { + return app.getUIUtilities().getIcon(icon, color); + } + public void setLastItem(boolean lastItem) { + isLastItem = lastItem; + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/PublicTransportCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/PublicTransportCard.java new file mode 100644 index 0000000000..4c6b0ee2d8 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/PublicTransportCard.java @@ -0,0 +1,229 @@ +package net.osmand.plus.routepreparationmenu.routeCards; + +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import net.osmand.AndroidUtils; +import net.osmand.data.TransportRoute; +import net.osmand.data.TransportStop; +import net.osmand.plus.OsmAndFormatter; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.routepreparationmenu.FlowLayout; +import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.TransportRoutingHelper; +import net.osmand.plus.transport.TransportStopRoute; +import net.osmand.plus.transport.TransportStopType; +import net.osmand.router.TransportRoutePlanner; + +import java.util.Iterator; + +public class PublicTransportCard extends BaseRouteCard { + + + private MapActivity mapActivity; + private TransportRoutePlanner.TransportRouteResult routeResult; + private final RoutingHelper routingHelper; + private final TransportRoutingHelper transportHelper; + private int routeId; + + public PublicTransportCard(MapActivity mapActivity, boolean nightMode, TransportRoutePlanner.TransportRouteResult routeResult, int routeId) { + super(mapActivity.getMyApplication(), nightMode); + this.mapActivity = mapActivity; + this.routeResult = routeResult; + routingHelper = mapActivity.getRoutingHelper(); + this.transportHelper = routingHelper.getTransportRoutingHelper(); + this.routeId = routeId; + } + + @Override + public void bindViewHolder() { + view = mapActivity.getLayoutInflater().inflate(R.layout.transport_route_card, null); + view.setBackgroundColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.route_info_bg_dark : R.color.route_info_bg_light)); + + int itemsSpacing = AndroidUtils.dpToPx(app, 6); + + FlowLayout routesBadges = (FlowLayout) view.findViewById(R.id.routes_badges); + + Iterator iterator = routeResult.getSegments().iterator(); + + while (iterator.hasNext()) { + TransportRoutePlanner.TransportRouteResultSegment s = iterator.next(); + if (s.walkDist != 0) { + double walkTime = getWalkTime(s.walkDist, routeResult.getWalkSpeed()); +// if (walkTime > 120) { + String walkTimeS = OsmAndFormatter.getFormattedDuration((int) walkTime, app); + routesBadges.addView(createWalkRouteBadge(walkTimeS), new FlowLayout.LayoutParams(itemsSpacing, itemsSpacing)); + routesBadges.addView(createArrow(), new FlowLayout.LayoutParams(itemsSpacing, itemsSpacing)); +// } + } + routesBadges.addView(createRouteBadge(s), new FlowLayout.LayoutParams(itemsSpacing, itemsSpacing)); + if (iterator.hasNext()) { + routesBadges.addView(createArrow(), new FlowLayout.LayoutParams(itemsSpacing, itemsSpacing)); + } + } + + double finishWalkDist = routeResult.getFinishWalkDist(); + if (finishWalkDist > 0) { + double walkTime2 = getWalkTime(finishWalkDist, routeResult.getWalkSpeed()); +// if (walkTime2 > 120) { + String walkTimeS = OsmAndFormatter.getFormattedDuration((int) walkTime2, app); + routesBadges.addView(createArrow(), new FlowLayout.LayoutParams(itemsSpacing, itemsSpacing)); + routesBadges.addView(createWalkRouteBadge(walkTimeS)); +// } + } + + TextView fromLine = (TextView) view.findViewById(R.id.from_line); + TextView wayLine = (TextView) view.findViewById(R.id.way_line); + + fromLine.setText(app.getString(R.string.route_from) + " " + routeResult.getSegments().get(0).getStart().getName()); + String travelTime = OsmAndFormatter.getFormattedDuration((int) routeResult.getTravelTime(), app); + String walkTime = OsmAndFormatter.getFormattedDuration((int) routeResult.getWalkTime(), app); + String walkDistance = OsmAndFormatter.getFormattedDistance((int) routeResult.getTravelDist(), app); + + wayLine.setText(app.getString(R.string.route_way) + " " + travelTime + " * walking - " + walkTime + " * " + walkDistance); + wayLine.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + } + }); + AndroidUtils.setTextSecondaryColor(app, fromLine, nightMode); + AndroidUtils.setTextSecondaryColor(app, wayLine, nightMode); + FrameLayout detailsButton = view.findViewById(R.id.details_button); + + AndroidUtils.setBackground(app, detailsButton, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + AndroidUtils.setBackground(app, view.findViewById(R.id.details_button_descr), nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); + } else { + AndroidUtils.setBackground(app, view.findViewById(R.id.details_button_descr), nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); + } + + AndroidUtils.setBackground(app, view.findViewById(R.id.top_divider), nightMode, + R.color.divider_light, R.color.divider_dark); + AndroidUtils.setBackground(app, view.findViewById(R.id.routes_info_container), nightMode, + R.color.route_info_bg_light, R.color.route_info_bg_dark); + + int color = ContextCompat.getColor(mapActivity, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light); + + ((TextView) view.findViewById(R.id.details_button_descr)).setTextColor(color); + + detailsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + transportHelper.setCurrentRoute(routeId); + } + }); + + if (isLastItem) { + view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom() + AndroidUtils.dpToPx(app, 60)); + } + } + + private View createRouteBadge(final Object object) { + LinearLayout convertView = (LinearLayout) mapActivity.getLayoutInflater().inflate(R.layout.transport_stop_route_item_with_icon, null, false); + if (object != null) { + String routeRef = ""; + int bgColor = 0; + if (object instanceof TransportRoutePlanner.TransportRouteResultSegment) { + TransportRoutePlanner.TransportRouteResultSegment segment = (TransportRoutePlanner.TransportRouteResultSegment) object; + TransportRoute transportRoute = segment.route; + + TransportStopRoute transportStopRoute = getTransportStopRoute(transportRoute, segment.getStart()); + routeRef = getAdjustedRouteRef(transportStopRoute.route.getRef()); + bgColor = transportStopRoute.getColor(app, nightMode); + } + TextView transportStopRouteTextView = (TextView) convertView.findViewById(R.id.transport_stop_route_text); + ImageView transportStopRouteImageView = (ImageView) convertView.findViewById(R.id.transport_stop_route_icon); + + transportStopRouteImageView.setImageDrawable(app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_bus_dark, UiUtilities.getContrastColor(app, bgColor, true))); + transportStopRouteTextView.setText(routeRef); + GradientDrawable gradientDrawableBg = (GradientDrawable) convertView.getBackground(); + gradientDrawableBg.setColor(bgColor); + transportStopRouteTextView.setTextColor(UiUtilities.getContrastColor(app, bgColor, true)); + + convertView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(app, object.toString(), Toast.LENGTH_LONG).show(); + } + }); + } + + return convertView; + } + + private View createWalkRouteBadge(final String walkTime) { + LinearLayout convertView = (LinearLayout) mapActivity.getLayoutInflater().inflate(R.layout.transport_stop_route_item_with_icon, null, false); + if (walkTime != null) { + int bgColor = ContextCompat.getColor(app, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light); + + TextView transportStopRouteTextView = (TextView) convertView.findViewById(R.id.transport_stop_route_text); + ImageView transportStopRouteImageView = (ImageView) convertView.findViewById(R.id.transport_stop_route_icon); + + transportStopRouteImageView.setImageDrawable(getActiveIcon(R.drawable.ic_action_pedestrian_dark)); + transportStopRouteTextView.setText(walkTime); + GradientDrawable gradientDrawableBg = (GradientDrawable) convertView.getBackground(); + gradientDrawableBg.setColor(bgColor); + transportStopRouteTextView.setTextColor(bgColor); + + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + AndroidUtils.setForeground(app, convertView, nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); + } else { + AndroidUtils.setForeground(app, convertView, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark); + } + AndroidUtils.setBackground(app, convertView, nightMode, R.drawable.btn_border_trans_light, R.drawable.ripple_dark); + + convertView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(app, walkTime, Toast.LENGTH_LONG).show(); + } + }); + } + + return convertView; + } + + private View createArrow() { + ImageView arrow = new ImageView(app); + arrow.setImageDrawable(getContentIcon(R.drawable.ic_arrow_forward)); + return arrow; + } + + private TransportStopRoute getTransportStopRoute(TransportRoute rs, TransportStop s) { + TransportStopType type = TransportStopType.findType(rs.getType()); + TransportStopRoute r = new TransportStopRoute(); + r.type = type; + r.desc = rs.getName(); + r.route = rs; + r.stop = s; + r.refStop = s; + return r; + } + + private String getAdjustedRouteRef(String ref) { + if (ref != null) { + int charPos = ref.lastIndexOf(':'); + if (charPos != -1) { + ref = ref.substring(0, charPos); + } + if (ref.length() > 4) { + ref = ref.substring(0, 4); + } + } + return ref; + } + + private double getWalkTime(double walkDist, double walkSpeed) { + return walkDist / walkSpeed; + } +} diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/SimpleRouteCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/SimpleRouteCard.java new file mode 100644 index 0000000000..73bb34e556 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/routeCards/SimpleRouteCard.java @@ -0,0 +1,156 @@ +package net.osmand.plus.routepreparationmenu.routeCards; + +import android.os.Build; +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.data.LineData; +import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; + +import net.osmand.AndroidUtils; +import net.osmand.plus.GPXUtilities; +import net.osmand.plus.OsmAndFormatter; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.activities.ShowRouteInfoDialogFragment; +import net.osmand.plus.helpers.GpxUiHelper; +import net.osmand.plus.routing.RouteDirectionInfo; +import net.osmand.plus.routing.RoutingHelper; + +import java.util.ArrayList; +import java.util.List; + +import static net.osmand.plus.routepreparationmenu.MapRouteInfoMenu.directionInfo; + +public class SimpleRouteCard extends BaseRouteCard { + + private MapActivity mapActivity; + private GPXUtilities.GPXFile gpx; + private final RoutingHelper routingHelper; + + public SimpleRouteCard(MapActivity mapActivity, boolean nightMode, GPXUtilities.GPXFile gpx) { + super(mapActivity.getMyApplication(), nightMode); + this.mapActivity = mapActivity; + this.gpx = gpx; + routingHelper = mapActivity.getRoutingHelper(); + } + + @Override + public void bindViewHolder() { + view = mapActivity.getLayoutInflater().inflate(R.layout.route_info_statistic, null); + view.setBackgroundColor(ContextCompat.getColor(mapActivity, nightMode ? R.color.route_info_bg_dark : R.color.route_info_bg_light)); + + view.findViewById(R.id.dividerToDropDown).setVisibility(View.VISIBLE); + view.findViewById(R.id.route_info_details_card).setVisibility(View.VISIBLE); + final OsmandApplication ctx = mapActivity.getMyApplication(); + + View info = view.findViewById(R.id.info_container); + info.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ShowRouteInfoDialogFragment.showDialog(mapActivity.getSupportFragmentManager()); + } + }); + + ImageView infoIcon = (ImageView) view.findViewById(R.id.InfoIcon); + ImageView durationIcon = (ImageView) view.findViewById(R.id.DurationIcon); + View infoDistanceView = view.findViewById(R.id.InfoDistance); + View infoDurationView = view.findViewById(R.id.InfoDuration); + if (directionInfo >= 0) { + infoIcon.setVisibility(View.GONE); + durationIcon.setVisibility(View.GONE); + infoDistanceView.setVisibility(View.GONE); + infoDurationView.setVisibility(View.GONE); + } else { + infoIcon.setImageDrawable(ctx.getUIUtilities().getIcon(R.drawable.ic_action_route_distance, R.color.route_info_unchecked_mode_icon_color)); + infoIcon.setVisibility(View.VISIBLE); + durationIcon.setImageDrawable(ctx.getUIUtilities().getIcon(R.drawable.ic_action_time_span, R.color.route_info_unchecked_mode_icon_color)); + durationIcon.setVisibility(View.VISIBLE); + infoDistanceView.setVisibility(View.VISIBLE); + infoDurationView.setVisibility(View.VISIBLE); + } + if (directionInfo >= 0 && routingHelper.getRouteDirections() != null + && directionInfo < routingHelper.getRouteDirections().size()) { + RouteDirectionInfo ri = routingHelper.getRouteDirections().get(directionInfo); + } else { + TextView distanceText = (TextView) view.findViewById(R.id.DistanceText); + TextView distanceTitle = (TextView) view.findViewById(R.id.DistanceTitle); + TextView durationText = (TextView) view.findViewById(R.id.DurationText); + TextView durationTitle = (TextView) view.findViewById(R.id.DurationTitle); + + distanceText.setText(OsmAndFormatter.getFormattedDistance(ctx.getRoutingHelper().getLeftDistance(), ctx)); + + durationText.setText(OsmAndFormatter.getFormattedDuration(ctx.getRoutingHelper().getLeftTime(), ctx)); + durationTitle.setText(ctx.getString(R.string.arrive_at_time, OsmAndFormatter.getFormattedTime(ctx.getRoutingHelper().getLeftTime(), true))); + + AndroidUtils.setTextPrimaryColor(ctx, distanceText, nightMode); + AndroidUtils.setTextSecondaryColor(ctx, distanceTitle, nightMode); + AndroidUtils.setTextPrimaryColor(ctx, durationText, nightMode); + AndroidUtils.setTextSecondaryColor(ctx, durationTitle, nightMode); + } + + FrameLayout detailsButton = view.findViewById(R.id.details_button); + + AndroidUtils.setBackground(app, detailsButton, nightMode, R.drawable.btn_border_trans_light, R.drawable.btn_border_trans_dark); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + AndroidUtils.setBackground(app, view.findViewById(R.id.details_button_descr), nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); + } else { + AndroidUtils.setBackground(app, view.findViewById(R.id.details_button_descr), nightMode, R.drawable.ripple_light, R.drawable.ripple_dark); + } + int color = ContextCompat.getColor(mapActivity, nightMode ? R.color.active_buttons_and_links_dark : R.color.active_buttons_and_links_light); + AndroidUtils.setBackground(ctx, view.findViewById(R.id.dividerToDropDown), nightMode, + R.color.divider_light, R.color.divider_dark); + AndroidUtils.setBackground(ctx, view.findViewById(R.id.info_divider), nightMode, + R.color.activity_background_light, R.color.route_info_cancel_button_color_dark); + + AndroidUtils.setBackground(ctx, view.findViewById(R.id.route_info_details_card), nightMode, + R.color.activity_background_light, R.color.route_info_cancel_button_color_dark); + AndroidUtils.setBackground(ctx, view.findViewById(R.id.RouteInfoControls), nightMode, + R.color.route_info_bg_light, R.color.route_info_bg_dark); + + ((TextView) view.findViewById(R.id.details_button_descr)).setTextColor(color); + + detailsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ShowRouteInfoDialogFragment.showDialog(mapActivity.getSupportFragmentManager()); + } + }); + + buildHeader(view); + } + + private void buildHeader(View headerView) { + OsmandApplication app = mapActivity.getMyApplication(); + final LineChart mChart = (LineChart) headerView.findViewById(R.id.chart); + final GPXUtilities.GPXTrackAnalysis analysis = gpx.getAnalysis(0); + + GpxUiHelper.setupGPXChart(mChart, 4, 4f, 4f, !nightMode, false); + GpxUiHelper.OrderedLineDataSet elevationDataSet; + GpxUiHelper.OrderedLineDataSet slopeDataSet; + if (analysis.hasElevationData) { + List dataSets = new ArrayList<>(); + elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis, + GpxUiHelper.GPXDataSetAxisType.DISTANCE, false, true); + if (elevationDataSet != null) { + dataSets.add(elevationDataSet); + } + slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis, + GpxUiHelper.GPXDataSetAxisType.DISTANCE, elevationDataSet.getValues(), true, true); + if (slopeDataSet != null) { + dataSets.add(slopeDataSet); + } + mChart.setData(new LineData(dataSets)); + mChart.setVisibility(View.VISIBLE); + } else { + elevationDataSet = null; + slopeDataSet = null; + mChart.setVisibility(View.GONE); + } + } +} \ No newline at end of file