diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java index af50969038..4d280d6960 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java @@ -363,7 +363,7 @@ public class TrackDetailsMenu { } } - private void refreshChart(LineChart chart, boolean forceFit) { + public void refreshChart(LineChart chart, boolean forceFit) { MapActivity mapActivity = getMapActivity(); GpxDisplayItem gpxItem = getGpxItem(); if (mapActivity == null || gpxItem == null) { @@ -724,7 +724,7 @@ public class TrackDetailsMenu { } } - public class TrackChartPoints { + public static class TrackChartPoints { private List xAxisPoints; private LatLon highlightedPoint; private int segmentColor; diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java index e6086ee195..1f41a7ecc2 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java @@ -26,7 +26,10 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.highlight.Highlight; +import com.github.mikephil.charting.listener.ChartTouchListener; import net.osmand.AndroidUtils; import net.osmand.GPXUtilities.GPXFile; @@ -57,9 +60,11 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType; import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet; import net.osmand.plus.mapcontextmenu.InterceptorLinearLayout; import net.osmand.plus.mapcontextmenu.MenuBuilder.CollapsableView; +import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; import net.osmand.plus.render.MapRenderRepositories; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener; +import net.osmand.plus.routepreparationmenu.cards.CardChartListener; import net.osmand.plus.routepreparationmenu.cards.PublicTransportCard; import net.osmand.plus.routepreparationmenu.cards.PublicTransportCard.PublicTransportCardListener; import net.osmand.plus.routepreparationmenu.cards.RouteDirectionsCard; @@ -86,7 +91,7 @@ import java.util.ArrayList; import java.util.List; public class RouteDetailsFragment extends ContextMenuFragment implements PublicTransportCardListener, - CardListener { + CardListener, CardChartListener { public static final String ROUTE_ID_KEY = "route_id_key"; private static final float PAGE_MARGIN = 5f; @@ -106,6 +111,8 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT @Nullable private PublicTransportCard transportCard; private RouteDetailsFragmentListener routeDetailsListener; + private RouteStatisticCard statisticCard; + private TrackDetailsMenu trackDetailsMenu; public interface RouteDetailsFragmentListener { void onNavigationRequested(); @@ -142,7 +149,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { Bundle args = getArguments(); if (args != null) { routeId = args.getInt(ROUTE_ID_KEY); @@ -171,6 +178,9 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT MapActivity mapActivity = getMapActivity(); if (mapActivity != null && isPortrait()) { mapActivity.findViewById(R.id.bottom_controls_container).setVisibility(View.GONE); + if (trackDetailsMenu != null) { + trackDetailsMenu.setMapActivity(mapActivity); + } } } @@ -179,6 +189,9 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT MapActivity mapActivity = getMapActivity(); if (mapActivity != null && isPortrait()) { mapActivity.findViewById(R.id.bottom_controls_container).setVisibility(View.VISIBLE); + if (trackDetailsMenu != null) { + trackDetailsMenu.setMapActivity(null); + } } super.onPause(); } @@ -295,7 +308,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT return; } OsmandApplication app = mapActivity.getMyApplication(); - RouteStatisticCard statisticCard = new RouteStatisticCard(mapActivity, gpx, new View.OnTouchListener() { + statisticCard = new RouteStatisticCard(mapActivity, gpx, new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { InterceptorLinearLayout mainView = getMainView(); @@ -312,6 +325,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT }); statisticCard.setTransparentBackground(true); statisticCard.setListener(this); + statisticCard.setChartListener(this); menuCards.add(statisticCard); cardsContainer.addView(statisticCard.build(mapActivity)); buildRowDivider(cardsContainer, false); @@ -346,6 +360,13 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT addRouteCard(cardsContainer, routeSmoothnessCard); } } + trackDetailsMenu = new TrackDetailsMenu(); + trackDetailsMenu.setGpxItem(statisticCard.getGpxItem()); + trackDetailsMenu.setMapActivity(mapActivity); + LineChart chart = statisticCard.getChart(); + if (chart != null) { + trackDetailsMenu.refreshChart(chart, true); + } } private void createRouteDirectionsCard(LinearLayout cardsContainer) { @@ -375,7 +396,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT } private void buildSegmentItem(View view, final TransportRouteResultSegment segment, - final TransportRouteResultSegment nextSegment, int[] startTime, double walkSpeed, double boardingTime) { + final TransportRouteResultSegment nextSegment, int[] startTime, double walkSpeed, double boardingTime) { OsmandApplication app = requireMyApplication(); TransportRoute transportRoute = segment.route; List stops = segment.getTravelStops(); @@ -542,7 +563,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT TargetPointsHelper targetPointsHelper = app.getTargetPointsHelper(); TargetPoint startPoint = targetPointsHelper.getPointToStart(); TargetPoint endPoint = targetPointsHelper.getPointToNavigate(); - int[] startTime = { 0 }; + int[] startTime = {0}; List segments = routeResult.getSegments(); for (int i = 0; i < segments.size(); i++) { boolean first = i == 0; @@ -754,7 +775,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT } public void buildCollapsableRow(@NonNull View view, final Spannable title, Spannable secondaryText, boolean collapsable, - final CollapsableView collapsableView, OnClickListener onClickListener) { + final CollapsableView collapsableView, OnClickListener onClickListener) { FrameLayout baseItemView = new FrameLayout(view.getContext()); FrameLayout.LayoutParams baseViewLayoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); baseItemView.setLayoutParams(baseViewLayoutParams); @@ -1153,7 +1174,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT } public void buildDestinationRow(@NonNull View view, String timeText, final Spannable title, Spannable secondaryText, - LatLon location, LinearLayout imagesContainer, OnClickListener onClickListener) { + LatLon location, LinearLayout imagesContainer, OnClickListener onClickListener) { OsmandApplication app = requireMyApplication(); FrameLayout baseItemView = new FrameLayout(view.getContext()); FrameLayout.LayoutParams baseViewLayoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); @@ -1567,6 +1588,62 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT } } + private void refreshChart() { + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null && trackDetailsMenu != null && statisticCard != null) { + LineChart chart = statisticCard.getChart(); + if (chart != null) { + trackDetailsMenu.refreshChart(chart, false); + mapActivity.refreshMap(); + } + } + } + + @Override + public void onValueSelected(BaseCard card, Entry e, Highlight h) { + refreshChart(); + } + + @Override + public void onNothingSelected(BaseCard card) { + } + + @Override + public void onChartGestureStart(BaseCard card, MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) { + } + + @Override + public void onChartGestureEnd(BaseCard card, MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) { + } + + @Override + public void onChartLongPressed(BaseCard card, MotionEvent me) { + } + + @Override + public void onChartDoubleTapped(BaseCard card, MotionEvent me) { + } + + @Override + public void onChartSingleTapped(BaseCard card, MotionEvent me) { + } + + @Override + public void onChartFling(BaseCard card, MotionEvent me1, MotionEvent me2, float velocityX, + float velocityY) { + } + + @Override + public void onChartScale(BaseCard card, MotionEvent me, float scaleX, float scaleY) { + } + + @Override + public void onChartTranslate(BaseCard card, Highlight h, MotionEvent me, float dX, float dY) { + if (h != null) { + refreshChart(); + } + } + public static class CumulativeInfo { public int distance; public int time; @@ -1577,7 +1654,8 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT } } - public static CumulativeInfo getRouteDirectionCumulativeInfo(int position, List routeDirections) { + public static CumulativeInfo getRouteDirectionCumulativeInfo(int position, List< + RouteDirectionInfo> routeDirections) { CumulativeInfo cumulativeInfo = new CumulativeInfo(); if (position >= routeDirections.size()) { return cumulativeInfo; diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java index 599ec1727e..719cfe2fda 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java @@ -29,6 +29,7 @@ public abstract class BaseCard { protected boolean nightMode; private CardListener listener; + private CardChartListener chartListener; public interface CardListener { void onCardLayoutNeeded(@NonNull BaseCard card); @@ -66,6 +67,14 @@ public abstract class BaseCard { this.listener = listener; } + public CardChartListener getChartListener() { + return chartListener; + } + + public void setChartListener(CardChartListener chartListener) { + this.chartListener = chartListener; + } + public void setLayoutNeeded() { CardListener listener = this.listener; if (listener != null) { diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/CardChartListener.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/CardChartListener.java new file mode 100644 index 0000000000..e4a215ed83 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/CardChartListener.java @@ -0,0 +1,88 @@ +package net.osmand.plus.routepreparationmenu.cards; + +import android.view.MotionEvent; + +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.highlight.Highlight; +import com.github.mikephil.charting.listener.ChartTouchListener; + +public interface CardChartListener { + /** + * Called when a value has been selected inside the chart. + * + * @param e The selected Entry + * @param h The corresponding highlight object that contains information + * about the highlighted position such as dataSetIndex, ... + */ + void onValueSelected(BaseCard card, Entry e, Highlight h); + + /** + * Called when nothing has been selected or an "un-select" has been made. + */ + void onNothingSelected(BaseCard card); + + /** + * Callbacks when a touch-gesture has started on the chart (ACTION_DOWN) + * + * @param me + * @param lastPerformedGesture + */ + void onChartGestureStart(BaseCard card, MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture); + + /** + * Callbacks when a touch-gesture has ended on the chart (ACTION_UP, ACTION_CANCEL) + * + * @param me + * @param lastPerformedGesture + */ + void onChartGestureEnd(BaseCard card, MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture); + + /** + * Callbacks when the chart is longpressed. + * + * @param me + */ + void onChartLongPressed(BaseCard card, MotionEvent me); + + /** + * Callbacks when the chart is double-tapped. + * + * @param me + */ + void onChartDoubleTapped(BaseCard card, MotionEvent me); + + /** + * Callbacks when the chart is single-tapped. + * + * @param me + */ + void onChartSingleTapped(BaseCard card, MotionEvent me); + + /** + * Callbacks then a fling gesture is made on the chart. + * + * @param me1 + * @param me2 + * @param velocityX + * @param velocityY + */ + void onChartFling(BaseCard card, MotionEvent me1, MotionEvent me2, float velocityX, float velocityY); + + /** + * Callbacks when the chart is scaled / zoomed via pinch zoom gesture. + * + * @param me + * @param scaleX scalefactor on the x-axis + * @param scaleY scalefactor on the y-axis + */ + void onChartScale(BaseCard card, MotionEvent me, float scaleX, float scaleY); + + /** + * Callbacks when the chart is moved / translated via drag gesture. + * + * @param me + * @param dX translation distance on the x-axis + * @param dY translation distance on the y-axis + */ + void onChartTranslate(BaseCard card, Highlight h, MotionEvent me, float dX, float dY); +} diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java index 74812016dd..d699ebdaa8 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java @@ -12,15 +12,16 @@ import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.highlight.Highlight; import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; import com.github.mikephil.charting.listener.ChartTouchListener.ChartGesture; import com.github.mikephil.charting.listener.OnChartGestureListener; +import com.github.mikephil.charting.listener.OnChartValueSelectedListener; import net.osmand.AndroidUtils; import net.osmand.GPXUtilities.GPXFile; @@ -62,6 +63,16 @@ public class RouteStatisticCard extends BaseCard { makeGpxDisplayItem(); } + @Nullable + public GPXFile getGpx() { + return gpx; + } + + @Nullable + public GpxDisplayItem getGpxItem() { + return gpxItem; + } + @Override public int getCardLayoutId() { return R.layout.route_info_header; @@ -218,6 +229,11 @@ public class RouteStatisticCard extends BaseCard { } } + @Nullable + public LineChart getChart() { + return (LineChart) view.findViewById(R.id.chart); + } + private void buildHeader(GPXTrackAnalysis analysis) { final LineChart mChart = (LineChart) view.findViewById(R.id.chart); GpxUiHelper.setupGPXChart(mChart, 4, 24f, 16f, !nightMode, true); @@ -242,6 +258,24 @@ public class RouteStatisticCard extends BaseCard { LineData data = new LineData(dataSets); mChart.setData(data); + mChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() { + @Override + public void onValueSelected(Entry e, Highlight h) { + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onValueSelected(RouteStatisticCard.this, e, h); + } + } + + @Override + public void onNothingSelected() { + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onNothingSelected(RouteStatisticCard.this); + } + } + }); + mChart.setOnChartGestureListener(new OnChartGestureListener() { float highlightDrawX = -1; @@ -253,6 +287,10 @@ public class RouteStatisticCard extends BaseCard { } else { highlightDrawX = -1; } + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartGestureStart(RouteStatisticCard.this, me, lastPerformedGesture); + } } @Override @@ -264,36 +302,65 @@ public class RouteStatisticCard extends BaseCard { } else { gpxItem.chartHighlightPos = -1; } + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartGestureEnd(RouteStatisticCard.this, me, lastPerformedGesture); + } } @Override public void onChartLongPressed(MotionEvent me) { + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartLongPressed(RouteStatisticCard.this, me); + } } @Override public void onChartDoubleTapped(MotionEvent me) { + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartDoubleTapped(RouteStatisticCard.this, me); + } } @Override public void onChartSingleTapped(MotionEvent me) { + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartSingleTapped(RouteStatisticCard.this, me); + } } @Override public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) { + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartFling(RouteStatisticCard.this, me1, me2, velocityX, velocityY); + } } @Override public void onChartScale(MotionEvent me, float scaleX, float scaleY) { + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartScale(RouteStatisticCard.this, me, scaleX, scaleY); + } } @Override public void onChartTranslate(MotionEvent me, float dX, float dY) { + Highlight h = null; if (highlightDrawX != -1) { - Highlight h = mChart.getHighlightByTouchPoint(highlightDrawX, 0f); + h = mChart.getHighlightByTouchPoint(highlightDrawX, 0f); if (h != null) { mChart.highlightValue(h); } } + CardChartListener chartListener = getChartListener(); + if (chartListener != null) { + chartListener.onChartTranslate(RouteStatisticCard.this, h, me, dX, dY); + } } }); mChart.setVisibility(View.VISIBLE); diff --git a/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java b/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java index 9a6093ff97..3f2502a039 100644 --- a/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java @@ -57,8 +57,6 @@ public class MapInfoLayer extends OsmandMapLayer { private TopTextView streetNameView; private TopToolbarView topToolbarView; - private TrackChartPoints trackChartPoints; - public MapInfoLayer(MapActivity map, RouteLayer layer){ this.map = map; settings = map.getMyApplication().getSettings(); @@ -224,7 +222,6 @@ public class MapInfoLayer extends OsmandMapLayer { } public void setTrackChartPoints(TrackChartPoints trackChartPoints) { - this.trackChartPoints = trackChartPoints; routeLayer.setTrackChartPoints(trackChartPoints); }