From cc4af37204824f7ca283833afa8400d4c98411b1 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 26 Oct 2020 14:03:49 +0200 Subject: [PATCH 01/34] graph iteration 2 strings --- OsmAnd/res/values/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index a30f9c4fc5..be2d6126ed 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,7 @@ Thx - Hardy --> + You must add at least two points. Wait for the route recalculation.\nGraph will be available after recalculation. %1$s data available only on the roads, you need to calculate a route using “Route between points” to get it. Graph From e4fe6564e6f057d330527f3588a02fb4fa373faf Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Fri, 30 Oct 2020 19:41:12 +0200 Subject: [PATCH 02/34] Fix bugs, complete graphs logic, remove copy-paste, refactoring --- .../fragment_measurement_tool_graph.xml | 65 ++- OsmAnd/res/values/attrs.xml | 1 + OsmAnd/res/values/styles.xml | 2 + .../plus/helpers/CustomBarChartRenderer.java | 30 ++ .../net/osmand/plus/helpers/GpxUiHelper.java | 67 ++++ .../plus/measurementtool/GraphsCard.java | 371 +++++++++--------- .../MeasurementEditingContext.java | 4 + .../MeasurementToolFragment.java | 62 ++- .../graph/BaseGraphAdapter.java | 82 ++++ .../graph/CommonGraphAdapter.java | 152 +++++++ .../graph/CustomGraphAdapter.java | 187 +++++++++ .../graph/GraphAdapterHelper.java | 145 +++++++ .../plus/myplaces/TrackSegmentFragment.java | 69 +--- .../RouteDetailsFragment.java | 172 ++------ .../routepreparationmenu/cards/BaseCard.java | 9 - .../cards/RouteInfoCard.java | 142 ++----- .../cards/RouteStatisticCard.java | 131 +------ 17 files changed, 1036 insertions(+), 655 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/helpers/CustomBarChartRenderer.java create mode 100644 OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java create mode 100644 OsmAnd/src/net/osmand/plus/measurementtool/graph/CommonGraphAdapter.java create mode 100644 OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java create mode 100644 OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java diff --git a/OsmAnd/res/layout/fragment_measurement_tool_graph.xml b/OsmAnd/res/layout/fragment_measurement_tool_graph.xml index 3d14187712..45f0b484d5 100644 --- a/OsmAnd/res/layout/fragment_measurement_tool_graph.xml +++ b/OsmAnd/res/layout/fragment_measurement_tool_graph.xml @@ -51,8 +51,13 @@ android:layout_width="match_parent" android:layout_height="@dimen/route_info_chart_height" /> - + + - + android:orientation="vertical"> + + + + + + + + + + + + diff --git a/OsmAnd/res/values/attrs.xml b/OsmAnd/res/values/attrs.xml index 5ffd847b3a..8e8c8aee32 100644 --- a/OsmAnd/res/values/attrs.xml +++ b/OsmAnd/res/values/attrs.xml @@ -19,6 +19,7 @@ + diff --git a/OsmAnd/res/values/styles.xml b/OsmAnd/res/values/styles.xml index ea305b19d2..d96c5fa196 100644 --- a/OsmAnd/res/values/styles.xml +++ b/OsmAnd/res/values/styles.xml @@ -92,6 +92,7 @@ @style/Widget.Styled.ActionBarLight @color/list_background_color_light @drawable/circle_background_light + @drawable/circle_contour_bg_light @drawable/btn_round_light @drawable/btn_round_border_light @drawable/btn_round_border_light_2 @@ -394,6 +395,7 @@ @style/Widget.Styled.ActionBarDark @color/list_background_color_dark @drawable/circle_background_dark + @drawable/circle_contour_bg_dark @drawable/btn_round_dark @drawable/btn_round_border_dark @drawable/btn_round_border_dark_2 diff --git a/OsmAnd/src/net/osmand/plus/helpers/CustomBarChartRenderer.java b/OsmAnd/src/net/osmand/plus/helpers/CustomBarChartRenderer.java new file mode 100644 index 0000000000..3321399dbf --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/helpers/CustomBarChartRenderer.java @@ -0,0 +1,30 @@ +package net.osmand.plus.helpers; + +import android.graphics.RectF; + +import androidx.annotation.NonNull; + +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.highlight.Highlight; +import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer; + +import net.osmand.AndroidUtils; + +public class CustomBarChartRenderer extends HorizontalBarChartRenderer { + private float highlightHalfWidth; + + public CustomBarChartRenderer(@NonNull BarChart chart) { + this(chart, AndroidUtils.dpToPx(chart.getContext(), 1f) / 2f); + } + + public CustomBarChartRenderer(@NonNull BarChart chart, float highlightHalfWidth) { + super(chart, chart.getAnimator(), chart.getViewPortHandler()); + this.highlightHalfWidth = highlightHalfWidth; + } + + @Override + protected void setHighlightDrawPos(Highlight high, RectF bar) { + bar.left = high.getDrawX() - highlightHalfWidth; + bar.right = high.getDrawX() + highlightHalfWidth; + } +} diff --git a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java index 47650dc2ec..c563be0769 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java @@ -75,6 +75,8 @@ import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuItem; import net.osmand.plus.GPXDatabase.GpxDataItem; import net.osmand.plus.GpxDbHelper.GpxDataItemCallback; +import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; +import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.OsmAndConstants; import net.osmand.plus.OsmAndFormatter; @@ -2045,6 +2047,71 @@ public class GpxUiHelper { return gpx; } + public enum LineGraphType { + ALTITUDE, + SLOPE, + SPEED; + } + + public static List getDataSets(LineChart chart, + OsmandApplication app, + GPXTrackAnalysis analysis, + boolean calcWithoutGaps, + LineGraphType... types) { + if (app == null || chart == null || analysis == null || types == null) { + return Collections.emptyList(); + } + List dataList = new ArrayList<>(); + for (LineGraphType type : types) { + switch (type) { + case ALTITUDE: { + if (analysis.hasElevationData) { + OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, + analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps); + dataList.add(elevationDataSet); + } + break; + } + case SLOPE: + if (analysis.hasElevationData) { + OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, + analysis, GPXDataSetAxisType.DISTANCE, null, true, true, calcWithoutGaps); + dataList.add(slopeDataSet); + } + break; + case SPEED: { + if (analysis.hasSpeedData) { + OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, + analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps); + dataList.add(speedDataSet); + } + break; + } + } + } + if (dataList.size() > 0) { + Collections.sort(dataList, new Comparator() { + @Override + public int compare(OrderedLineDataSet o1, OrderedLineDataSet o2) { + return Float.compare(o1.getPriority(), o2.getPriority()); + } + }); + } + return new ArrayList(dataList); + } + + public static GpxDisplayItem makeGpxDisplayItem(OsmandApplication app, GPXUtilities.GPXFile gpx) { + GpxDisplayItem gpxItem = null; + String groupName = app.getString(R.string.current_route); + GpxDisplayGroup group = app.getSelectedGpxHelper().buildGpxDisplayGroup(gpx, 0, groupName); + if (group != null && group.getModifiableList().size() > 0) { + gpxItem = group.getModifiableList().get(0); + if (gpxItem != null) { + gpxItem.route = true; + } + } + return gpxItem; + } public static class GPXInfo { diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java index 9a5cbeffba..3ae28d83b2 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java @@ -1,10 +1,12 @@ package net.osmand.plus.measurementtool; import android.view.View; +import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -16,17 +18,25 @@ import com.github.mikephil.charting.data.ChartData; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; +import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.SettingsBaseActivity; import net.osmand.plus.helpers.GpxUiHelper; -import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet; -import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType; +import net.osmand.plus.helpers.GpxUiHelper.LineGraphType; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter; +import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener; +import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; import net.osmand.plus.measurementtool.MeasurementToolFragment.OnUpdateAdditionalInfoListener; +import net.osmand.plus.measurementtool.graph.CommonGraphAdapter; +import net.osmand.plus.measurementtool.graph.CustomGraphAdapter; +import net.osmand.plus.measurementtool.graph.CustomGraphAdapter.LegendViewType; +import net.osmand.plus.measurementtool.graph.BaseGraphAdapter; +import net.osmand.plus.measurementtool.graph.GraphAdapterHelper; import net.osmand.plus.routepreparationmenu.RouteDetailsFragment; import net.osmand.plus.routepreparationmenu.cards.BaseCard; +import net.osmand.plus.routepreparationmenu.cards.RouteStatisticCard; import net.osmand.router.RouteSegmentResult; import net.osmand.util.Algorithms; @@ -36,44 +46,52 @@ import static net.osmand.GPXUtilities.GPXFile; import static net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.Arrays; import java.util.List; public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListener { private static String GRAPH_DATA_GPX_FILE_NAME = "graph_data_tmp"; + private static int INVALID_ID = -1; private MeasurementEditingContext editingCtx; private MeasurementToolFragment fragment; - private GraphType visibleGraphType; + private GraphType visibleType; private List graphTypes = new ArrayList<>(); + private GpxDisplayItem gpxItem; private View commonGraphContainer; private View customGraphContainer; private View messageContainer; - private LineChart commonGraphChart; - private HorizontalBarChart customGraphChart; + private CommonGraphAdapter commonGraphAdapter; + private CustomGraphAdapter customGraphAdapter; private RecyclerView graphTypesMenu; - private enum CommonGraphType { - OVERVIEW(R.string.shared_string_overview, false), - ALTITUDE(R.string.altitude, true), - SLOPE(R.string.shared_string_slope, true), - SPEED(R.string.map_widget_speed, false); + private TrackDetailsMenu trackDetailsMenu; - CommonGraphType(int titleId, boolean canBeCalculated) { + private enum CommonGraphType { + OVERVIEW(R.string.shared_string_overview, true, LineGraphType.ALTITUDE, LineGraphType.SLOPE), + ALTITUDE(R.string.altitude, true, LineGraphType.ALTITUDE), + SLOPE(R.string.shared_string_slope, true, LineGraphType.SLOPE), + SPEED(R.string.map_widget_speed, false, LineGraphType.SPEED); + + CommonGraphType(int titleId, boolean canBeCalculated, LineGraphType ... lineGraphTypes) { this.titleId = titleId; this.canBeCalculated = canBeCalculated; + this.lineGraphTypes = lineGraphTypes; } final int titleId; final boolean canBeCalculated; + final LineGraphType[] lineGraphTypes; } - public GraphsCard(@NonNull MapActivity mapActivity, MeasurementToolFragment fragment) { + public GraphsCard(@NonNull MapActivity mapActivity, + TrackDetailsMenu trackDetailsMenu, + MeasurementToolFragment fragment) { super(mapActivity); + this.trackDetailsMenu = trackDetailsMenu; this.fragment = fragment; } @@ -82,19 +100,27 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen if (mapActivity == null || fragment == null) return; editingCtx = fragment.getEditingCtx(); + graphTypesMenu = view.findViewById(R.id.graph_types_recycler_view); + graphTypesMenu.setLayoutManager(new LinearLayoutManager(mapActivity, RecyclerView.HORIZONTAL, false)); commonGraphContainer = view.findViewById(R.id.common_graphs_container); customGraphContainer = view.findViewById(R.id.custom_graphs_container); messageContainer = view.findViewById(R.id.message_container); - commonGraphChart = (LineChart) view.findViewById(R.id.line_chart); - customGraphChart = (HorizontalBarChart) view.findViewById(R.id.horizontal_chart); - updateGraphData(); + LineChart lineChart = (LineChart) view.findViewById(R.id.line_chart); + HorizontalBarChart barChart = (HorizontalBarChart) view.findViewById(R.id.horizontal_chart); + commonGraphAdapter = new CommonGraphAdapter(lineChart, true); + customGraphAdapter = new CustomGraphAdapter(barChart, true); - graphTypesMenu = view.findViewById(R.id.graph_types_recycler_view); - graphTypesMenu.setLayoutManager( - new LinearLayoutManager(mapActivity, RecyclerView.HORIZONTAL, false)); + customGraphAdapter.setLegendContainer((ViewGroup) view.findViewById(R.id.route_legend)); + customGraphAdapter.setLayoutChangeListener(new BaseGraphAdapter.LayoutChangeListener() { + @Override + public void onLayoutChanged() { + setLayoutNeeded(); + } + }); - refreshGraphTypesSelectionMenu(); - updateDataView(); + GraphAdapterHelper.bindGraphAdapters(commonGraphAdapter, Arrays.asList((BaseGraphAdapter) customGraphAdapter), (ViewGroup) view); + GraphAdapterHelper.bindToMap(commonGraphAdapter, mapActivity, trackDetailsMenu); + fullUpdate(); } @Override @@ -104,15 +130,29 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen @Override public void onUpdateAdditionalInfo() { - if (!isRouteCalculating()) { - updateGraphData(); - refreshGraphTypesSelectionMenu(); - } - updateDataView(); + fullUpdate(); } - private void refreshGraphTypesSelectionMenu() { - graphTypesMenu.removeAllViews(); + private void fullUpdate() { + if (!isRouteCalculating()) { + updateData(); + updateVisibleType(); + updateTypesMenu(); + } + updateInfoView(); + } + + private void updateTypesMenu() { + if (!editingCtx.isPointsEnoughToCalculateRoute()) { + graphTypesMenu.setVisibility(View.GONE); + } else { + graphTypesMenu.setVisibility(View.VISIBLE); + graphTypesMenu.removeAllViews(); + fillInTypesMenu(); + } + } + + private void fillInTypesMenu() { OsmandApplication app = getMyApplication(); int activeColorId = nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light; final HorizontalSelectionAdapter adapter = new HorizontalSelectionAdapter(app, nightMode); @@ -127,16 +167,16 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen } } adapter.setItems(items); - String selectedItemKey = visibleGraphType.getTitle(); + String selectedItemKey = visibleType.getTitle(); adapter.setSelectedItemByTitle(selectedItemKey); - adapter.setListener(new HorizontalSelectionAdapter.HorizontalSelectionAdapterListener() { + adapter.setListener(new HorizontalSelectionAdapterListener() { @Override - public void onItemSelected(HorizontalSelectionAdapter.HorizontalSelectionItem item) { + public void onItemSelected(HorizontalSelectionItem item) { adapter.setItems(items); adapter.setSelectedItem(item); - GraphType chosenGraphType = (GraphType) item.getObject(); - if (!isCurrentVisibleType(chosenGraphType)) { - setupVisibleGraphType(chosenGraphType); + GraphType chosenType = (GraphType) item.getObject(); + if (!isCurrentVisibleType(chosenType)) { + changeVisibleType(chosenType); } } }); @@ -144,19 +184,19 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen adapter.notifyDataSetChanged(); } - private void setupVisibleGraphType(GraphType type) { - visibleGraphType = type; - updateDataView(); + private void changeVisibleType(GraphType type) { + visibleType = type; + updateInfoView(); } private boolean isCurrentVisibleType(GraphType type) { - if (visibleGraphType != null && type != null) { - return Algorithms.objectEquals(visibleGraphType.getTitle(), type.getTitle()); + if (visibleType != null && type != null) { + return Algorithms.objectEquals(visibleType.getTitle(), type.getTitle()); } return false; } - private GraphType getFirstAvailableGraphType() { + private GraphType getFirstAvailableType() { for (GraphType type : graphTypes) { if (type.isAvailable()) { return type; @@ -165,189 +205,146 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen return null; } - private void updateDataView() { - if (isRouteCalculating()) { - showProgressMessage(); - } else if (visibleGraphType.hasData()) { + private void updateInfoView() { + hideAll(); + if (!editingCtx.isPointsEnoughToCalculateRoute()) { + showMessage(app.getString(R.string.message_you_need_add_two_points_to_show_graphs)); + } else if (isRouteCalculating()) { + showMessage(app.getString(R.string.message_graph_will_be_available_after_recalculation), true); + } else if (visibleType.hasData()) { showGraph(); - } else if (visibleGraphType.canBeCalculated()) { - showMessage(); + } else if (visibleType.canBeCalculated()) { + showMessage(app.getString(R.string.message_need_calculate_route_before_show_graph, + visibleType.getTitle()), R.drawable.ic_action_altitude_average, + app.getString(R.string.route_between_points), new View.OnClickListener() { + @Override + public void onClick(View v) { + fragment.startSnapToRoad(false); + } + }); } } - private void showProgressMessage() { + private void hideAll() { commonGraphContainer.setVisibility(View.GONE); customGraphContainer.setVisibility(View.GONE); + messageContainer.setVisibility(View.GONE); + } + + private void showMessage(String text) { + showMessage(text, INVALID_ID, false, null, null); + } + + private void showMessage(String text, @DrawableRes int iconResId, String btnTitle, View.OnClickListener btnListener) { + showMessage(text, iconResId, false, btnTitle, btnListener); + } + + private void showMessage(String text, boolean showProgressBar) { + showMessage(text, INVALID_ID, showProgressBar, null, null); + } + + private void showMessage(@NonNull String text, + @DrawableRes int iconResId, + boolean showProgressBar, + String btnTitle, + View.OnClickListener btnListener) { messageContainer.setVisibility(View.VISIBLE); TextView tvMessage = messageContainer.findViewById(R.id.message_text); + tvMessage.setText(text); ImageView icon = messageContainer.findViewById(R.id.message_icon); + if (iconResId != INVALID_ID) { + icon.setVisibility(View.VISIBLE); + icon.setImageResource(iconResId); + } else { + icon.setVisibility(View.GONE); + } ProgressBar pb = messageContainer.findViewById(R.id.progress_bar); - pb.setVisibility(View.VISIBLE); - icon.setVisibility(View.GONE); - tvMessage.setText(R.string.message_graph_will_be_available_after_recalculation); + pb.setVisibility(showProgressBar ? View.VISIBLE : View.GONE); + View btnContainer = messageContainer.findViewById(R.id.btn_container); + if (btnTitle != null) { + TextView tvBtnTitle = btnContainer.findViewById(R.id.btn_text); + tvBtnTitle.setText(btnTitle); + btnContainer.setVisibility(View.VISIBLE); + } else { + btnContainer.setVisibility(View.GONE); + } + if (btnListener != null) { + btnContainer.setOnClickListener(btnListener); + } } private void showGraph() { - if (visibleGraphType.isCustom()) { - customGraphChart.clear(); - commonGraphContainer.setVisibility(View.GONE); + if (visibleType.isCustom()) { + CustomGraphType customGraphType = (CustomGraphType) visibleType; customGraphContainer.setVisibility(View.VISIBLE); - messageContainer.setVisibility(View.GONE); - prepareCustomGraphView((BarData) visibleGraphType.getGraphData()); + customGraphAdapter.setLegendViewType(LegendViewType.ONE_ELEMENT); + customGraphAdapter.fullUpdate((BarData) customGraphType.getGraphData(), customGraphType.getStatistics()); } else { - commonGraphChart.clear(); commonGraphContainer.setVisibility(View.VISIBLE); - customGraphContainer.setVisibility(View.GONE); - messageContainer.setVisibility(View.GONE); - prepareCommonGraphView((LineData) visibleGraphType.getGraphData()); + customGraphAdapter.setLegendViewType(LegendViewType.GONE); + commonGraphAdapter.fullUpdate((LineData) visibleType.getGraphData(), gpxItem); } } - private void showMessage() { - commonGraphContainer.setVisibility(View.GONE); - customGraphContainer.setVisibility(View.GONE); - messageContainer.setVisibility(View.VISIBLE); - TextView tvMessage = messageContainer.findViewById(R.id.message_text); - ImageView icon = messageContainer.findViewById(R.id.message_icon); - ProgressBar pb = messageContainer.findViewById(R.id.progress_bar); - pb.setVisibility(View.GONE); - icon.setVisibility(View.VISIBLE); - tvMessage.setText(app.getString( - R.string.message_need_calculate_route_before_show_graph, - visibleGraphType.getTitle())); - icon.setImageResource(R.drawable.ic_action_altitude_average); - } - - private void prepareCommonGraphView(LineData data) { - GpxUiHelper.setupGPXChart(commonGraphChart, 4, 24f, 16f, !nightMode, true); - commonGraphChart.setData(data); - } - - private void prepareCustomGraphView(BarData data) { - OsmandApplication app = getMyApplication(); - if (app == null) return; - - GpxUiHelper.setupHorizontalGPXChart(app, customGraphChart, 5, 9, 24, true, nightMode); - customGraphChart.setExtraRightOffset(16); - customGraphChart.setExtraLeftOffset(16); - customGraphChart.setData(data); - } - - private void updateGraphData() { + private void updateData() { graphTypes.clear(); OsmandApplication app = getMyApplication(); - GPXTrackAnalysis analysis = createGpxTrackAnalysis(); + GPXFile gpxFile = getGpxFile(); + GPXTrackAnalysis analysis = gpxFile != null ? gpxFile.getAnalysis(0) : null; + gpxItem = gpxFile != null ? GpxUiHelper.makeGpxDisplayItem(app, gpxFile) : null; + if (gpxItem != null) { + trackDetailsMenu.setGpxItem(gpxItem); + } // update common graph data for (CommonGraphType commonType : CommonGraphType.values()) { - List dataSets = getDataSets(commonType, commonGraphChart, analysis); - LineData data = null; - if (!Algorithms.isEmpty(dataSets)) { - data = new LineData(dataSets); - } + List dataSets = GpxUiHelper.getDataSets(commonGraphAdapter.getChart(), + app, analysis, false, commonType.lineGraphTypes); + LineData data = !Algorithms.isEmpty(dataSets) ? new LineData(dataSets) : null; String title = app.getString(commonType.titleId); - graphTypes.add(new GraphType(title, false, commonType.canBeCalculated, data)); + graphTypes.add(new GraphType(title, commonType.canBeCalculated, data)); } // update custom graph data - List routeSegments = editingCtx.getAllRouteSegments(); - List routeStatistics = calculateRouteStatistics(routeSegments); + List routeStatistics = calculateRouteStatistics(); if (analysis != null && routeStatistics != null) { for (RouteStatistics statistics : routeStatistics) { String title = SettingsBaseActivity.getStringRouteInfoPropertyValue(app, statistics.name); BarData data = null; if (!Algorithms.isEmpty(statistics.elements)) { - data = GpxUiHelper.buildStatisticChart( - app, customGraphChart, statistics, analysis, true, nightMode); + data = GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(), + statistics, analysis, true, nightMode); } - graphTypes.add(new GraphType(title, true, false, data)); + graphTypes.add(new CustomGraphType(title, false, data, statistics)); } } + } - // update current visible graph type - if (visibleGraphType == null) { - visibleGraphType = getFirstAvailableGraphType(); + private void updateVisibleType() { + if (visibleType == null) { + visibleType = getFirstAvailableType(); } else { for (GraphType type : graphTypes) { if (isCurrentVisibleType(type)) { - visibleGraphType = type.isAvailable() ? type : getFirstAvailableGraphType(); + visibleType = type.isAvailable() ? type : getFirstAvailableType(); break; } } } } - private List getDataSets(CommonGraphType type, LineChart chart, GPXTrackAnalysis analysis) { - List dataSets = new ArrayList<>(); - if (chart != null && analysis != null) { - OsmandApplication app = getMyApplication(); - switch (type) { - case OVERVIEW: { - List dataList = new ArrayList<>(); - if (analysis.hasSpeedData) { - OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, true, true, false); - dataList.add(speedDataSet); - } - if (analysis.hasElevationData) { - OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, false); - dataList.add(elevationDataSet); - OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, null, true, true, false); - dataList.add(slopeDataSet); - } - if (dataList.size() > 0) { - Collections.sort(dataList, new Comparator() { - @Override - public int compare(OrderedLineDataSet o1, OrderedLineDataSet o2) { - return Float.compare(o1.getPriority(), o2.getPriority()); - } - }); - } - dataSets.addAll(dataList); - break; - } - case ALTITUDE: { - if (analysis.hasElevationData) { - OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, false);//calcWithoutGaps); - dataSets.add(elevationDataSet); - } - break; - } - case SLOPE: - if (analysis.hasElevationData) { - OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, null, true, true, false); - dataSets.add(slopeDataSet); - } - break; - case SPEED: { - if (analysis.hasSpeedData) { - OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, false);//calcWithoutGaps); - dataSets.add(speedDataSet); - } - break; - } - } - } - return dataSets; - } - - private GPXTrackAnalysis createGpxTrackAnalysis() { - GPXFile gpx; - if (editingCtx.getGpxData() != null) { - gpx = editingCtx.getGpxData().getGpxFile(); + private GPXFile getGpxFile() { + if (fragment.isTrackReadyToCalculate()) { + return editingCtx.exportRouteAsGpx(GRAPH_DATA_GPX_FILE_NAME); } else { - gpx = editingCtx.exportRouteAsGpx(GRAPH_DATA_GPX_FILE_NAME); + GpxData gpxData = editingCtx.getGpxData(); + return gpxData != null ? gpxData.getGpxFile() : null; } - return gpx != null ? gpx.getAnalysis(0) : null; } - private List calculateRouteStatistics(List route) { + private List calculateRouteStatistics() { OsmandApplication app = getMyApplication(); + List route = editingCtx.getAllRouteSegments(); if (route == null || app == null) return null; return RouteDetailsFragment.calculateRouteStatistics(app, route, nightMode); } @@ -356,15 +353,13 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen return fragment.isProgressBarVisible(); } - private static class GraphType { + private class GraphType { private String title; - private boolean isCustom; private boolean canBeCalculated; private ChartData graphData; - public GraphType(String title, boolean isCustom, boolean canBeCalculated, ChartData graphData) { + public GraphType(String title, boolean canBeCalculated, ChartData graphData) { this.title = title; - this.isCustom = isCustom; this.canBeCalculated = canBeCalculated; this.graphData = graphData; } @@ -374,11 +369,15 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen } public boolean isCustom() { - return isCustom; + return this instanceof CustomGraphType; } public boolean isAvailable() { - return hasData() || canBeCalculated(); + return isPointsCountEnoughToCalculateRoute() && (hasData() || canBeCalculated()); + } + + private boolean isPointsCountEnoughToCalculateRoute() { + return editingCtx.getPointsCount() >= 2; } public boolean canBeCalculated() { @@ -393,4 +392,18 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen return graphData; } } + + private class CustomGraphType extends GraphType { + + private RouteStatistics statistics; + + public CustomGraphType(String title, boolean canBeCalculated, ChartData graphData, RouteStatistics statistics) { + super(title, canBeCalculated, graphData); + this.statistics = statistics; + } + + public RouteStatistics getStatistics() { + return statistics; + } + } } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java index 307d89d501..ad6c5f4c4f 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java @@ -313,6 +313,10 @@ public class MeasurementEditingContext { return before.points.size(); } + public boolean isPointsEnoughToCalculateRoute() { + return getPointsCount() >= 2; + } + public List getAllRouteSegments() { List allSegments = new ArrayList<>(); for (Pair key : getOrderedRoadSegmentDataKeys()) { diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java index c40e7b70ca..9e6ecef9e3 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java @@ -52,6 +52,7 @@ import net.osmand.plus.activities.TrackActivity; import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.base.ContextMenuFragment.MenuState; import net.osmand.plus.helpers.AndroidUiHelper; +import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; import net.osmand.plus.measurementtool.GpxApproximationFragment.GpxApproximationFragmentListener; import net.osmand.plus.measurementtool.GpxData.ActionType; import net.osmand.plus.measurementtool.OptionsBottomSheetDialogFragment.OptionsFragmentListener; @@ -116,8 +117,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route private TextView distanceToCenterTv; private String pointsSt; private View additionalInfoContainer; - private ViewGroup additionalInfoCardsContainer; - private BaseCard visibleAdditionalInfoCard; + private ViewGroup cardsContainer; + private BaseCard visibleCard; + private PointsCard pointsCard; + private GraphsCard graphsCard; private LinearLayout customRadioButton; private View mainView; private ImageView upDownBtn; @@ -145,6 +148,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route private int cachedMapPosition; private MeasurementEditingContext editingCtx = new MeasurementEditingContext(); + private GraphDetailsMenu detailsMenu; private LatLon initialPoint; @@ -164,6 +168,19 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route GRAPH } + private class GraphDetailsMenu extends TrackDetailsMenu { + + @Override + protected int getFragmentWidth() { + return mainView.getWidth(); + } + + @Override + protected int getFragmentHeight() { + return mainView.getHeight(); + } + } + private void setEditingCtx(MeasurementEditingContext editingCtx) { this.editingCtx = editingCtx; } @@ -257,8 +274,9 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route mainView = view.findViewById(R.id.main_view); AndroidUtils.setBackground(mapActivity, mainView, nightMode, R.drawable.bg_bottom_menu_light, R.drawable.bg_bottom_menu_dark); + detailsMenu = new GraphDetailsMenu(); additionalInfoContainer = mainView.findViewById(R.id.additional_info_container); - additionalInfoCardsContainer = mainView.findViewById(R.id.cards_container); + cardsContainer = mainView.findViewById(R.id.cards_container); if (portrait) { customRadioButton = mainView.findViewById(R.id.custom_radio_buttons); @@ -282,6 +300,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } }); } + pointsCard = new PointsCard(mapActivity, this); + graphsCard = new GraphsCard(mapActivity, detailsMenu, this); if (progressBarVisible) { showProgressBar(); @@ -517,29 +537,28 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (!additionalInfoExpanded || !isCurrentAdditionalInfoType(type)) { MapActivity ma = getMapActivity(); if (ma == null) return; - currentAdditionalInfoType = type; - updateUpDownBtn(); + OsmandApplication app = ma.getMyApplication(); - BaseCard additionalInfoCard = null; if (AdditionalInfoType.POINTS == type) { - additionalInfoCard = new PointsCard(ma, this); + visibleCard = pointsCard; UiUtilities.updateCustomRadioButtons(app, customRadioButton, nightMode, START); } else if (AdditionalInfoType.GRAPH == type) { - additionalInfoCard = new GraphsCard(ma, this); + visibleCard = graphsCard; UiUtilities.updateCustomRadioButtons(app, customRadioButton, nightMode, END); } - if (additionalInfoCard != null) { - visibleAdditionalInfoCard = additionalInfoCard; - additionalInfoCardsContainer.removeAllViews(); - additionalInfoCardsContainer.addView(additionalInfoCard.build(ma)); - additionalInfoExpanded = true; - } + cardsContainer.removeAllViews(); + View cardView = visibleCard.getView() != null ? visibleCard.getView() : visibleCard.build(ma); + cardsContainer.addView(cardView); + + currentAdditionalInfoType = type; + additionalInfoExpanded = true; + updateUpDownBtn(); } } private void updateAdditionalInfoView() { - if (visibleAdditionalInfoCard instanceof OnUpdateAdditionalInfoListener) { - ((OnUpdateAdditionalInfoListener) visibleAdditionalInfoCard).onUpdateAdditionalInfo(); + if (visibleCard instanceof OnUpdateAdditionalInfoListener) { + ((OnUpdateAdditionalInfoListener) visibleCard).onUpdateAdditionalInfo(); } } @@ -597,6 +616,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route super.onResume(); MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { + detailsMenu.setMapActivity(mapActivity); mapActivity.getMapLayers().getMapControlsLayer().addThemeInfoProviderTag(TAG); mapActivity.getMapLayers().getMapControlsLayer().showMapControlsIfHidden(); cachedMapPosition = mapActivity.getMapView().getMapPosition(); @@ -612,6 +632,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route if (mapActivity != null) { mapActivity.getMapLayers().getMapControlsLayer().removeThemeInfoProviderTag(TAG); } + detailsMenu.onDismiss(); + detailsMenu.setMapActivity(null); setMapPosition(cachedMapPosition); } @@ -687,7 +709,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } } - private void startSnapToRoad(boolean rememberPreviousTitle) { + public void startSnapToRoad(boolean rememberPreviousTitle) { MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { if (rememberPreviousTitle) { @@ -1219,7 +1241,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route final ApplicationMode appMode = editingCtx.getAppMode(); if (mapActivity != null) { Drawable icon; - if (editingCtx.isTrackSnappedToRoad() || editingCtx.isNewData() || approximationApplied) { + if (isTrackReadyToCalculate()) { if (appMode == MeasurementEditingContext.DEFAULT_APP_MODE) { icon = getActiveIcon(R.drawable.ic_action_split_interval); } else { @@ -1234,6 +1256,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } } + public boolean isTrackReadyToCalculate() { + return editingCtx.isTrackSnappedToRoad() || editingCtx.isNewData() || approximationApplied; + } + private void hideSnapToRoadIcon() { MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java new file mode 100644 index 0000000000..dc83460a3f --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java @@ -0,0 +1,82 @@ +package net.osmand.plus.measurementtool.graph; + +import android.view.MotionEvent; + +import com.github.mikephil.charting.charts.Chart; +import com.github.mikephil.charting.data.ChartData; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.highlight.Highlight; +import com.github.mikephil.charting.listener.ChartTouchListener; + +import net.osmand.plus.OsmandApplication; + +public abstract class BaseGraphAdapter { + + private Highlight lastKnownHighlight; + protected CHART mChart; + protected CHART_DATA mChartData; + protected DATA mAdditionalData; + protected boolean usedOnMap; + + public BaseGraphAdapter(CHART chart, boolean usedOnMap) { + this.mChart = chart; + this.usedOnMap = usedOnMap; + prepareCharterView(); + } + + protected void prepareCharterView() { + mChart.setExtraRightOffset(16); + mChart.setExtraLeftOffset(16); + } + + public CHART getChart() { + return mChart; + } + + protected void updateHighlight() { + highlight(lastKnownHighlight); + } + + public void highlight(Highlight h) { + this.lastKnownHighlight = h; + } + + public void fullUpdate(CHART_DATA chartData, DATA data) { + updateData(chartData, data); + updateView(); + } + + public void updateData(CHART_DATA chartData, DATA data) { + this.mChartData = chartData; + this.mAdditionalData = data; + } + + public abstract void updateView(); + + protected boolean isNightMode() { + OsmandApplication app = getMyApplication(); + if (app != null) { + return usedOnMap ? app.getDaynightHelper().isNightModeForMapControls() + : !app.getSettings().isLightContent(); + } + return false; + } + + protected OsmandApplication getMyApplication() { + return (OsmandApplication) mChart.getContext().getApplicationContext(); + } + + public interface ExternalValueSelectedListener { + void onValueSelected(Entry e, Highlight h); + void onNothingSelected(); + } + + public interface ExternalGestureListener { + void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture); + void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture, boolean hasTranslated); + } + + public interface LayoutChangeListener { + void onLayoutChanged(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/CommonGraphAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CommonGraphAdapter.java new file mode 100644 index 0000000000..693b5669e7 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CommonGraphAdapter.java @@ -0,0 +1,152 @@ +package net.osmand.plus.measurementtool.graph; + +import android.graphics.Matrix; +import android.view.MotionEvent; + +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.listener.ChartTouchListener; +import com.github.mikephil.charting.listener.OnChartGestureListener; +import com.github.mikephil.charting.listener.OnChartValueSelectedListener; + +import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; +import net.osmand.plus.helpers.GpxUiHelper; + +import java.util.HashMap; +import java.util.Map; + +public class CommonGraphAdapter extends BaseGraphAdapter { + + private Highlight highlight; + private Map externalValueSelectedListeners = new HashMap<>(); + private ExternalGestureListener externalGestureListener; + + public CommonGraphAdapter(LineChart chart, boolean usedOnMap) { + super(chart, usedOnMap); + } + + @Override + protected void prepareCharterView() { + super.prepareCharterView(); + + mChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() { + @Override + public void onValueSelected(Entry e, Highlight h) { + highlight = h; + for (ExternalValueSelectedListener listener : externalValueSelectedListeners.values()) { + listener.onValueSelected(e, h); + } + } + + @Override + public void onNothingSelected() { + for (ExternalValueSelectedListener listener : externalValueSelectedListeners.values()) { + listener.onNothingSelected(); + } + } + }); + + mChart.setOnChartGestureListener(new OnChartGestureListener() { + boolean hasTranslated = false; + float highlightDrawX = -1; + + @Override + public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) { + hasTranslated = false; + if (mChart.getHighlighted() != null && mChart.getHighlighted().length > 0) { + highlightDrawX = mChart.getHighlighted()[0].getDrawX(); + } else { + highlightDrawX = -1; + } + if (externalGestureListener != null) { + externalGestureListener.onChartGestureStart(me, lastPerformedGesture); + } + } + + @Override + public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) { + GpxDisplayItem gpxItem = getGpxItem(); + gpxItem.chartMatrix = new Matrix(mChart.getViewPortHandler().getMatrixTouch()); + Highlight[] highlights = mChart.getHighlighted(); + if (highlights != null && highlights.length > 0) { + gpxItem.chartHighlightPos = highlights[0].getX(); + } else { + gpxItem.chartHighlightPos = -1; + } + if (externalGestureListener != null) { + externalGestureListener.onChartGestureEnd(me, lastPerformedGesture, hasTranslated); + } + } + + @Override + public void onChartLongPressed(MotionEvent me) { + } + + @Override + public void onChartDoubleTapped(MotionEvent me) { + } + + @Override + public void onChartSingleTapped(MotionEvent me) { + } + + @Override + public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) { + } + + @Override + public void onChartScale(MotionEvent me, float scaleX, float scaleY) { + } + + @Override + public void onChartTranslate(MotionEvent me, float dX, float dY) { + hasTranslated = true; + if (highlightDrawX != -1) { + Highlight h = mChart.getHighlightByTouchPoint(highlightDrawX, 0f); + if (h != null) { + /* + ILineDataSet set = mChart.getLineData().getDataSetByIndex(h.getDataSetIndex()); + if (set != null && set.isHighlightEnabled()) { + Entry e = set.getEntryForXValue(h.getX(), h.getY()); + MPPointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelForValues(e.getX(), e.getY()); + h.setDraw((float) pix.x, (float) pix.y); + } + */ + mChart.highlightValue(h, true); + } + } + } + }); + } + + public void addValueSelectedListener(String key, ExternalValueSelectedListener listener) { + this.externalValueSelectedListeners.put(key, listener); + } + + public void removeValueSelectedListener(String key) { + this.externalValueSelectedListeners.remove(key); + } + + public void setExternalGestureListener(ExternalGestureListener listener) { + this.externalGestureListener = listener; + } + + @Override + public void updateView() { + GpxUiHelper.setupGPXChart(mChart, 4, 24f, 16f, !isNightMode(), true); + mChart.setData(mChartData); + updateHighlight(); + } + + @Override + public void highlight(Highlight h) { + super.highlight(h); + mChart.highlightValue(highlight); + } + + public GpxDisplayItem getGpxItem() { + return mAdditionalData; + } +} diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java new file mode 100644 index 0000000000..aded2e0fbe --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java @@ -0,0 +1,187 @@ +package net.osmand.plus.measurementtool.graph; + +import android.graphics.drawable.Drawable; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.StyleSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.core.graphics.ColorUtils; + +import com.github.mikephil.charting.charts.HorizontalBarChart; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.highlight.Highlight; +import com.github.mikephil.charting.listener.OnChartValueSelectedListener; + +import net.osmand.AndroidUtils; +import net.osmand.plus.OsmAndFormatter; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.SettingsNavigationActivity; +import net.osmand.plus.helpers.CustomBarChartRenderer; +import net.osmand.plus.helpers.GpxUiHelper; +import net.osmand.router.RouteStatisticsHelper; +import net.osmand.router.RouteStatisticsHelper.RouteStatistics; +import net.osmand.router.RouteStatisticsHelper.RouteSegmentAttribute; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CustomGraphAdapter extends BaseGraphAdapter { + + private static final int MINIMUM_CONTRAST_RATIO = 3; + + private String selectedPropertyName; + private ViewGroup legendContainer; + private LegendViewType legendViewType; + private LayoutChangeListener layoutChangeListener; + + public enum LegendViewType { + ONE_ELEMENT, + ALL_AS_LIST, + GONE + } + + public CustomGraphAdapter(HorizontalBarChart chart, boolean usedOnMap) { + super(chart, usedOnMap); + } + + @Override + protected void prepareCharterView() { + super.prepareCharterView(); + legendViewType = LegendViewType.GONE; + mChart.setRenderer(new CustomBarChartRenderer(mChart)); + mChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() { + @Override + public void onValueSelected(Entry e, Highlight h) { + if (getStatistics() == null) return; + + List elems = getStatistics().elements; + int i = h.getStackIndex(); + if (i >= 0 && elems.size() > i) { + selectedPropertyName = elems.get(i).getPropertyName(); + updateLegend(); + } + } + + @Override + public void onNothingSelected() { + selectedPropertyName = null; + updateLegend(); + } + }); + } + + @Override + public void updateView() { + mChart.clear(); + GpxUiHelper.setupHorizontalGPXChart(getMyApplication(), mChart, 5, 9, 24, true, isNightMode()); + mChart.setData(mChartData); + updateHighlight(); + updateLegend(); + } + + public void setLegendContainer(ViewGroup legendContainer) { + this.legendContainer = legendContainer; + } + + public void setLegendViewType(LegendViewType legendViewType) { + this.legendViewType = legendViewType; + } + + public void setLayoutChangeListener(LayoutChangeListener layoutChangeListener) { + this.layoutChangeListener = layoutChangeListener; + } + + public void highlight(Highlight h) { + super.highlight(h); + Highlight bh = h != null ? mChart.getHighlighter().getHighlight(1, h.getXPx()) : null; + if (bh != null) { + bh.setDraw(h.getXPx(), 0); + } + mChart.highlightValue(bh, true); + } + + private void updateLegend() { + if (legendContainer == null) return; + + legendContainer.removeAllViews(); + attachLegend(); + if (layoutChangeListener != null) { + layoutChangeListener.onLayoutChanged(); + } + } + + private void attachLegend() { + if (getSegmentsList() == null) return; + + switch (legendViewType) { + case ONE_ELEMENT: + for (RouteSegmentAttribute segment : getSegmentsList()) { + if (segment.getPropertyName().equals(selectedPropertyName)) { + attachLegend(Arrays.asList(segment), null); + break; + } + } + break; + case ALL_AS_LIST: + attachLegend(getSegmentsList(), selectedPropertyName); + break; + } + } + + private void attachLegend(List list, + String propertyNameToFullSpan) { + OsmandApplication app = getMyApplication(); + LayoutInflater inflater = LayoutInflater.from(app); + for (RouteStatisticsHelper.RouteSegmentAttribute segment : list) { + View view = inflater.inflate(R.layout.route_details_legend, legendContainer, false); + int segmentColor = segment.getColor(); + Drawable circle = app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, segmentColor); + ImageView legendIcon = (ImageView) view.findViewById(R.id.legend_icon_color); + legendIcon.setImageDrawable(circle); + double contrastRatio = ColorUtils.calculateContrast(segmentColor, + AndroidUtils.getColorFromAttr(app, R.attr.card_and_list_background_basic)); + if (contrastRatio < MINIMUM_CONTRAST_RATIO) { + legendIcon.setBackgroundResource(AndroidUtils.resolveAttribute(app, R.attr.bg_circle_contour)); + } + String propertyName = segment.getUserPropertyName(); + String name = SettingsNavigationActivity.getStringPropertyName(app, propertyName, propertyName.replaceAll("_", " ")); + boolean selected = segment.getPropertyName().equals(propertyNameToFullSpan); + Spannable text = getSpanLegend(name, segment, selected); + TextView legend = (TextView) view.findViewById(R.id.legend_text); + legend.setText(text); + + legendContainer.addView(view); + } + } + + private Spannable getSpanLegend(String title, + RouteSegmentAttribute segment, + boolean fullSpan) { + String formattedDistance = OsmAndFormatter.getFormattedDistance(segment.getDistance(), getMyApplication()); + title = Algorithms.capitalizeFirstLetter(title); + SpannableStringBuilder spannable = new SpannableStringBuilder(title); + spannable.append(": "); + int startIndex = fullSpan ? -0 : spannable.length(); + spannable.append(formattedDistance); + spannable.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), + startIndex, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return spannable; + } + + private List getSegmentsList() { + return getStatistics() != null ? new ArrayList<>(getStatistics().partition.values()) : null; + } + + private RouteStatistics getStatistics() { + return mAdditionalData; + } +} diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java new file mode 100644 index 0000000000..efacad9d50 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java @@ -0,0 +1,145 @@ +package net.osmand.plus.measurementtool.graph; + +import android.annotation.SuppressLint; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import com.github.mikephil.charting.charts.BarChart; +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.plus.OsmandApplication; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; + +import java.util.List; + +public class GraphAdapterHelper { + + public static final String BIND_GRAPH_ADAPTERS_KEY = "bind_graph_adapters_key"; + public static final String BIND_TO_MAP_KEY = "bind_to_map_key"; + + public static void bindGraphAdapters(final CommonGraphAdapter mainGraphAdapter, + final List otherGraphAdapters, + final ViewGroup mainView) { + if (mainGraphAdapter == null || mainGraphAdapter.getChart() == null + || otherGraphAdapters == null || otherGraphAdapters.size() == 0) { + return; + } + + final LineChart mainChart = mainGraphAdapter.getChart(); + View.OnTouchListener mainChartTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent ev) { + if (mainView != null) { + mainView.requestDisallowInterceptTouchEvent(true); + } + for (BaseGraphAdapter adapter : otherGraphAdapters) { + if (adapter.getChart() != null) { + final MotionEvent event = MotionEvent.obtainNoHistory(ev); + event.setSource(0); + adapter.getChart().dispatchTouchEvent(event); + } + } + return false; + } + }; + mainChart.setOnTouchListener(mainChartTouchListener); + + mainGraphAdapter.addValueSelectedListener(BIND_GRAPH_ADAPTERS_KEY, + new CommonGraphAdapter.ExternalValueSelectedListener() { + @Override + public void onValueSelected(Entry e, Highlight h) { + for (BaseGraphAdapter adapter : otherGraphAdapters) { + adapter.highlight(h); + } + } + + @Override + public void onNothingSelected() { + for (BaseGraphAdapter adapter : otherGraphAdapters) { + adapter.highlight(null); + } + } + } + ); + + View.OnTouchListener otherChartsTouchListener = new View.OnTouchListener() { + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View v, MotionEvent ev) { + if (ev.getSource() != 0) { + final MotionEvent event = MotionEvent.obtainNoHistory(ev); + event.setSource(0); + mainChart.dispatchTouchEvent(event); + return true; + } + return false; + } + }; + + for (BaseGraphAdapter adapter : otherGraphAdapters) { + if (adapter.getChart() != null) { + if (adapter.getChart() instanceof BarChart) { + // maybe we should find min and max axis from all charters + BarChart barChart = (BarChart) adapter.getChart(); + barChart.getAxisRight().setAxisMinimum(mainChart.getXChartMin()); + barChart.getAxisRight().setAxisMaximum(mainChart.getXChartMax()); + barChart.setHighlightPerDragEnabled(false); + barChart.setHighlightPerTapEnabled(false); + } + adapter.getChart().setOnTouchListener(otherChartsTouchListener); + } + } + } + + public static void bindToMap(final CommonGraphAdapter graphAdapter, + final MapActivity mapActivity, + final TrackDetailsMenu detailsMenu) { + graphAdapter.addValueSelectedListener(BIND_TO_MAP_KEY, + new CommonGraphAdapter.ExternalValueSelectedListener() { + + @Override + public void onValueSelected(Entry e, Highlight h) { + refreshChart(mapActivity, graphAdapter.getChart(), detailsMenu, false); + } + + @Override + public void onNothingSelected() { + } + }); + + graphAdapter.setExternalGestureListener(new CommonGraphAdapter.ExternalGestureListener() { + @Override + public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) { + } + + @Override + public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture, boolean hasTranslated) { + if ((lastPerformedGesture == ChartTouchListener.ChartGesture.DRAG && hasTranslated) || + lastPerformedGesture == ChartTouchListener.ChartGesture.X_ZOOM || + lastPerformedGesture == ChartTouchListener.ChartGesture.Y_ZOOM || + lastPerformedGesture == ChartTouchListener.ChartGesture.PINCH_ZOOM || + lastPerformedGesture == ChartTouchListener.ChartGesture.DOUBLE_TAP || + lastPerformedGesture == ChartTouchListener.ChartGesture.ROTATE) { + refreshChart(mapActivity, graphAdapter.getChart(), detailsMenu, true); + } + } + }); + } + + public static void refreshChart(MapActivity mapActivity, + LineChart chart, + TrackDetailsMenu menu, + boolean forceFit) { + if (mapActivity == null || chart == null || menu == null) return; + OsmandApplication app = mapActivity.getMyApplication(); + if (!app.getRoutingHelper().isFollowingMode()) { + menu.refreshChart(chart, forceFit); + mapActivity.refreshMap(); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java index 94b3f9bfa3..2fa80d9fa0 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java @@ -87,6 +87,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.ALTITUDE; +import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SPEED; + public class TrackSegmentFragment extends OsmAndListFragment implements TrackBitmapDrawerListener { private OsmandApplication app; @@ -425,64 +428,16 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit } } - private List getDataSets(GPXTabItemType tabType, LineChart chart) { + private List getDataSets(LineChart chart, + GPXTabItemType tabType, + GpxUiHelper.LineGraphType... types) { List dataSets = dataSetsMap.get(tabType); if (dataSets == null && chart != null) { - dataSets = new ArrayList<>(); GPXTrackAnalysis analysis = gpxItem.analysis; GpxDataItem gpxDataItem = getGpxDataItem(); boolean calcWithoutGaps = gpxItem.isGeneralTrack() && gpxDataItem != null && !gpxDataItem.isJoinSegments(); - switch (tabType) { - case GPX_TAB_ITEM_GENERAL: { - OrderedLineDataSet speedDataSet = null; - OrderedLineDataSet elevationDataSet = null; - if (analysis.hasSpeedData) { - speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, true, true, calcWithoutGaps); - } - if (analysis.hasElevationData) { - elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps); - } - if (speedDataSet != null) { - dataSets.add(speedDataSet); - if (elevationDataSet != null) { - dataSets.add(elevationDataSet.getPriority() < speedDataSet.getPriority() - ? 1 : 0, elevationDataSet); - } - } else if (elevationDataSet != null) { - dataSets.add(elevationDataSet); - } - dataSetsMap.put(GPXTabItemType.GPX_TAB_ITEM_GENERAL, dataSets); - break; - } - case GPX_TAB_ITEM_ALTITUDE: { - OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps); - if (elevationDataSet != null) { - dataSets.add(elevationDataSet); - } - if (analysis.hasElevationData) { - List eleValues = elevationDataSet != null && !gpxItem.isGeneralTrack() ? elevationDataSet.getValues() : null; - OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, eleValues, true, true, calcWithoutGaps); - if (slopeDataSet != null) { - dataSets.add(slopeDataSet); - } - } - dataSetsMap.put(GPXTabItemType.GPX_TAB_ITEM_ALTITUDE, dataSets); - break; - } - case GPX_TAB_ITEM_SPEED: { - OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps); - if (speedDataSet != null) { - dataSets.add(speedDataSet); - } - dataSetsMap.put(GPXTabItemType.GPX_TAB_ITEM_SPEED, dataSets); - break; - } - } + dataSets = GpxUiHelper.getDataSets(chart, app, analysis, calcWithoutGaps, types); + dataSetsMap.put(tabType, dataSets); } return dataSets; } @@ -703,7 +658,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit if (analysis != null) { if (analysis.hasElevationData || analysis.hasSpeedData) { GpxUiHelper.setupGPXChart(app, chart, 4); - chart.setData(new LineData(getDataSets(GPXTabItemType.GPX_TAB_ITEM_GENERAL, chart))); + chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_GENERAL, SPEED, ALTITUDE))); updateChart(chart); chart.setVisibility(View.VISIBLE); } else { @@ -821,7 +776,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit if (analysis != null) { if (analysis.hasElevationData) { GpxUiHelper.setupGPXChart(app, chart, 4); - chart.setData(new LineData(getDataSets(GPXTabItemType.GPX_TAB_ITEM_ALTITUDE, chart))); + chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_ALTITUDE, ALTITUDE))); updateChart(chart); chart.setVisibility(View.VISIBLE); } else { @@ -923,7 +878,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit if (analysis != null && analysis.isSpeedSpecified()) { if (analysis.hasSpeedData) { GpxUiHelper.setupGPXChart(app, chart, 4); - chart.setData(new LineData(getDataSets(GPXTabItemType.GPX_TAB_ITEM_SPEED, chart))); + chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_SPEED, SPEED))); updateChart(chart); chart.setVisibility(View.VISIBLE); } else { @@ -1189,7 +1144,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit LatLon location = null; WptPt wpt = null; gpxItem.chartTypes = null; - List ds = getDataSets(tabType, null); + List ds = getDataSets(null, tabType); if (ds != null && ds.size() > 0) { gpxItem.chartTypes = new GPXDataSetType[ds.size()]; for (int i = 0; i < ds.size(); i++) { diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java index 1f29dfd1b7..81c3f232d8 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java @@ -2,7 +2,6 @@ package net.osmand.plus.routepreparationmenu; import android.annotation.SuppressLint; import android.content.Context; -import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -14,11 +13,9 @@ import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.view.Gravity; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; -import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; @@ -30,15 +27,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; -import com.github.mikephil.charting.animation.ChartAnimator; -import com.github.mikephil.charting.charts.HorizontalBarChart; 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.interfaces.dataprovider.BarDataProvider; -import com.github.mikephil.charting.listener.ChartTouchListener.ChartGesture; -import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer; -import com.github.mikephil.charting.utils.ViewPortHandler; import net.osmand.AndroidUtils; import net.osmand.GPXUtilities.GPXFile; @@ -68,10 +57,12 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType; import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet; import net.osmand.plus.mapcontextmenu.CollapsableView; import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; +import net.osmand.plus.measurementtool.graph.BaseGraphAdapter; +import net.osmand.plus.measurementtool.graph.CommonGraphAdapter; +import net.osmand.plus.measurementtool.graph.GraphAdapterHelper; 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; @@ -98,8 +89,8 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -public class RouteDetailsFragment extends ContextMenuFragment implements PublicTransportCardListener, - CardListener, CardChartListener { +public class RouteDetailsFragment extends ContextMenuFragment + implements PublicTransportCardListener, CardListener { public static final String ROUTE_ID_KEY = "route_id_key"; private static final float PAGE_MARGIN = 5f; @@ -311,24 +302,7 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT return; } OsmandApplication app = mapActivity.getMyApplication(); - statisticCard = new RouteStatisticCard(mapActivity, gpx, new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent ev) { - LinearLayout mainView = getMainView(); - if (mainView != null) { - mainView.requestDisallowInterceptTouchEvent(true); - } - for (RouteInfoCard card : routeInfoCards) { - final HorizontalBarChart ch = card.getChart(); - if (ch != null) { - final MotionEvent event = MotionEvent.obtainNoHistory(ev); - event.setSource(0); - ch.dispatchTouchEvent(event); - } - } - return false; - } - }, new OnClickListener() { + statisticCard = new RouteStatisticCard(mapActivity, gpx, new OnClickListener() { @Override public void onClick(View v) { openDetails(); @@ -336,7 +310,6 @@ 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); @@ -359,13 +332,25 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT routeDetailsMenu.setGpxItem(gpxItem); } routeDetailsMenu.setMapActivity(mapActivity); - LineChart chart = statisticCard.getChart(); - if (chart != null) { - chart.setExtraRightOffset(16); - chart.setExtraLeftOffset(16); + + CommonGraphAdapter mainGraphAdapter = statisticCard.getGraphAdapter(); + if (mainGraphAdapter != null) { + GraphAdapterHelper.bindGraphAdapters(mainGraphAdapter, getRouteInfoCardsGraphAdapters(), getMainView()); + GraphAdapterHelper.bindToMap(mainGraphAdapter, mapActivity, routeDetailsMenu); } } + private List getRouteInfoCardsGraphAdapters() { + List adapters = new ArrayList<>(); + for (RouteInfoCard card : routeInfoCards) { + BaseGraphAdapter adapter = card.getGraphAdapter(); + if (adapter != null) { + adapters.add(adapter); + } + } + return adapters; + } + public static List calculateRouteStatistics(OsmandApplication app, List route, boolean nightMode) { @@ -384,7 +369,12 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT protected void calculateLayout(View view, boolean initLayout) { super.calculateLayout(view, initLayout); if (!initLayout && getCurrentMenuState() != MenuState.FULL_SCREEN) { - refreshChart(false); + MapActivity mapActivity = getMapActivity(); + CommonGraphAdapter mainGraphAdapter = statisticCard.getGraphAdapter(); + if (mainGraphAdapter != null) { + LineChart chart = mainGraphAdapter.getChart(); + GraphAdapterHelper.refreshChart(mapActivity, chart, routeDetailsMenu, false); + } } } @@ -401,48 +391,15 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT buildRowDivider(cardsContainer, false); } - private OnTouchListener getChartTouchListener() { - return new OnTouchListener() { - @SuppressLint("ClickableViewAccessibility") - @Override - public boolean onTouch(View v, MotionEvent ev) { - if (ev.getSource() != 0 && v instanceof HorizontalBarChart) { - if (statisticCard != null) { - LineChart ch = statisticCard.getChart(); - if (ch != null) { - final MotionEvent event = MotionEvent.obtainNoHistory(ev); - event.setSource(0); - ch.dispatchTouchEvent(event); - } - } - return true; - } - return false; - } - }; - } - @SuppressLint("ClickableViewAccessibility") - private void addRouteCard(final LinearLayout cardsContainer, RouteInfoCard routeInfoCard) { + private void addRouteCard(LinearLayout cardsContainer, + RouteInfoCard routeInfoCard) { OsmandApplication app = requireMyApplication(); menuCards.add(routeInfoCard); routeInfoCard.setListener(this); cardsContainer.addView(routeInfoCard.build(app)); buildRowDivider(cardsContainer, false); - routeInfoCards.add(routeInfoCard); - HorizontalBarChart chart = routeInfoCard.getChart(); - if (chart != null) { - LineChart mainChart = statisticCard.getChart(); - if (mainChart != null) { - chart.getAxisRight().setAxisMinimum(mainChart.getXChartMin()); - chart.getAxisRight().setAxisMaximum(mainChart.getXChartMax()); - } - chart.setRenderer(new CustomBarChartRenderer(chart, chart.getAnimator(), chart.getViewPortHandler(), AndroidUtils.dpToPx(app, 1f) / 2f)); - chart.setHighlightPerDragEnabled(false); - chart.setHighlightPerTapEnabled(false); - chart.setOnTouchListener(getChartTouchListener()); - } } public Drawable getCollapseIcon(boolean collapsed) { @@ -1615,59 +1572,6 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT } } - private void refreshChart(boolean forceFit) { - MapActivity mapActivity = getMapActivity(); - if (mapActivity != null && routeDetailsMenu != null && statisticCard != null && - !mapActivity.getMyApplication().getRoutingHelper().isFollowingMode()) { - LineChart chart = statisticCard.getChart(); - if (chart != null) { - routeDetailsMenu.refreshChart(chart, forceFit); - mapActivity.refreshMap(); - } - } - } - - private void highlightRouteInfoCharts(@Nullable Highlight h) { - for (RouteInfoCard rc : routeInfoCards) { - HorizontalBarChart chart = rc.getChart(); - if (chart != null) { - Highlight bh = h != null ? chart.getHighlighter().getHighlight(1, h.getXPx()) : null; - if (bh != null) { - bh.setDraw(h.getXPx(), 0); - } - chart.highlightValue(bh, true); - } - } - } - - @Override - public void onValueSelected(BaseCard card, Entry e, Highlight h) { - refreshChart(false); - highlightRouteInfoCharts(h); - } - - @Override - public void onNothingSelected(BaseCard card) { - highlightRouteInfoCharts(null); - } - - @Override - public void onChartGestureStart(BaseCard card, MotionEvent me, ChartGesture lastPerformedGesture) { - } - - @Override - public void onChartGestureEnd(BaseCard card, MotionEvent me, ChartGesture lastPerformedGesture, boolean hasTranslated) { - if ((lastPerformedGesture == ChartGesture.DRAG && hasTranslated) || - lastPerformedGesture == ChartGesture.X_ZOOM || - lastPerformedGesture == ChartGesture.Y_ZOOM || - lastPerformedGesture == ChartGesture.PINCH_ZOOM || - lastPerformedGesture == ChartGesture.DOUBLE_TAP || - lastPerformedGesture == ChartGesture.ROTATE) { - - refreshChart(true); - } - } - public static class CumulativeInfo { public int distance; public int time; @@ -1696,20 +1600,4 @@ public class RouteDetailsFragment extends ContextMenuFragment implements PublicT final int timeInSeconds = model.getExpectedTime(); return Algorithms.formatDuration(timeInSeconds, app.accessibilityEnabled()); } - - private static class CustomBarChartRenderer extends HorizontalBarChartRenderer { - - private float highlightHalfWidth; - - CustomBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, float highlightHalfWidth) { - super(chart, animator, viewPortHandler); - this.highlightHalfWidth = highlightHalfWidth; - } - - @Override - protected void setHighlightDrawPos(Highlight high, RectF bar) { - bar.left = high.getDrawX() - highlightHalfWidth; - bar.right = high.getDrawX() + highlightHalfWidth; - } - } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java index 245412fe34..d4101e58ec 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/BaseCard.java @@ -31,7 +31,6 @@ public abstract class BaseCard { protected boolean nightMode; private CardListener listener; - private CardChartListener chartListener; public interface CardListener { void onCardLayoutNeeded(@NonNull BaseCard card); @@ -78,14 +77,6 @@ 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/RouteInfoCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java index ef02b16734..d50f0dfdc8 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java @@ -1,55 +1,33 @@ package net.osmand.plus.routepreparationmenu.cards; import android.graphics.drawable.Drawable; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.style.StyleSpan; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.annotation.Nullable; -import androidx.appcompat.view.ContextThemeWrapper; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.ColorUtils; - import com.github.mikephil.charting.charts.HorizontalBarChart; import com.github.mikephil.charting.data.BarData; -import com.github.mikephil.charting.data.Entry; -import com.github.mikephil.charting.highlight.Highlight; -import com.github.mikephil.charting.listener.OnChartValueSelectedListener; import net.osmand.GPXUtilities.GPXTrackAnalysis; -import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.SettingsBaseActivity; -import net.osmand.plus.activities.SettingsNavigationActivity; import net.osmand.plus.helpers.GpxUiHelper; -import net.osmand.router.RouteStatisticsHelper.RouteSegmentAttribute; +import net.osmand.plus.measurementtool.graph.CustomGraphAdapter; +import net.osmand.plus.measurementtool.graph.CustomGraphAdapter.LegendViewType; import net.osmand.router.RouteStatisticsHelper.RouteStatistics; -import net.osmand.util.Algorithms; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; public class RouteInfoCard extends BaseCard { - - private static final int MINIMUM_CONTRAST_RATIO = 3; - - private RouteStatistics routeStatistics; + private RouteStatistics statistics; private GPXTrackAnalysis analysis; - private String selectedPropertyName; + private CustomGraphAdapter graphAdapter; private boolean showLegend; - public RouteInfoCard(MapActivity mapActivity, RouteStatistics routeStatistics, GPXTrackAnalysis analysis) { + public RouteInfoCard(MapActivity mapActivity, RouteStatistics statistics, GPXTrackAnalysis analysis) { super(mapActivity); - this.routeStatistics = routeStatistics; + this.statistics = statistics; this.analysis = analysis; } @@ -60,112 +38,46 @@ public class RouteInfoCard extends BaseCard { @Override protected void updateContent() { - updateContent(routeStatistics); - } - - @Nullable - public HorizontalBarChart getChart() { - return (HorizontalBarChart) view.findViewById(R.id.chart); - } - - private void updateContent(final RouteStatistics routeStatistics) { updateHeader(); - final HorizontalBarChart chart = (HorizontalBarChart) view.findViewById(R.id.chart); - GpxUiHelper.setupHorizontalGPXChart(app, chart, 5, 9, 24, true, nightMode); - chart.setExtraRightOffset(16); - chart.setExtraLeftOffset(16); - BarData barData = GpxUiHelper.buildStatisticChart(app, chart, routeStatistics, analysis, true, nightMode); - chart.setData(barData); - chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() { - @Override - public void onValueSelected(Entry e, Highlight h) { - List elems = routeStatistics.elements; - int i = h.getStackIndex(); - if (i >= 0 && elems.size() > i) { - selectedPropertyName = elems.get(i).getPropertyName(); - if (showLegend) { - updateLegend(routeStatistics); - } - } - } - - @Override - public void onNothingSelected() { - selectedPropertyName = null; - if (showLegend) { - updateLegend(routeStatistics); - } - } - }); LinearLayout container = (LinearLayout) view.findViewById(R.id.route_items); - container.removeAllViews(); - if (showLegend) { - attachLegend(container, routeStatistics); - } - final ImageView iconViewCollapse = (ImageView) view.findViewById(R.id.up_down_icon); - iconViewCollapse.setImageDrawable(getCollapseIcon(!showLegend)); + HorizontalBarChart chart = (HorizontalBarChart) view.findViewById(R.id.chart); + BarData barData = GpxUiHelper.buildStatisticChart(app, chart, statistics, analysis, true, nightMode); + graphAdapter = new CustomGraphAdapter(chart, true); + graphAdapter.setLegendContainer(container); + graphAdapter.updateData(barData, statistics); + updateView(); + view.findViewById(R.id.info_type_details_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showLegend = !showLegend; - updateContent(); + updateView(); setLayoutNeeded(); } }); } - protected void updateLegend(RouteStatistics routeStatistics) { - LinearLayout container = (LinearLayout) view.findViewById(R.id.route_items); - container.removeAllViews(); - attachLegend(container, routeStatistics); - setLayoutNeeded(); - } - - private Drawable getCollapseIcon(boolean collapsed) { - return collapsed ? getContentIcon(R.drawable.ic_action_arrow_down) : getActiveIcon(R.drawable.ic_action_arrow_up); + private void updateView() { + updateCollapseIcon(); + graphAdapter.setLegendViewType(showLegend ? LegendViewType.ALL_AS_LIST : LegendViewType.GONE); + graphAdapter.updateView(); } private void updateHeader() { TextView title = (TextView) view.findViewById(R.id.info_type_title); - String name = SettingsBaseActivity.getStringRouteInfoPropertyValue(app, routeStatistics.name); + String name = SettingsBaseActivity.getStringRouteInfoPropertyValue(app, statistics.name); title.setText(name); } - private void attachLegend(ViewGroup container, RouteStatistics routeStatistics) { - Map partition = routeStatistics.partition; - List> list = new ArrayList<>(partition.entrySet()); - ContextThemeWrapper ctx = new ContextThemeWrapper(mapActivity, !nightMode ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme); - LayoutInflater inflater = LayoutInflater.from(ctx); - for (Map.Entry entry : list) { - RouteSegmentAttribute segment = entry.getValue(); - View view = inflater.inflate(R.layout.route_details_legend, container, false); - int segmentColor = segment.getColor(); - Drawable circle = app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, segmentColor); - ImageView legendIcon = (ImageView) view.findViewById(R.id.legend_icon_color); - legendIcon.setImageDrawable(circle); - double contrastRatio = ColorUtils.calculateContrast(segmentColor, ContextCompat.getColor(app, nightMode ? R.color.card_and_list_background_dark : R.color.card_and_list_background_light)); - if (contrastRatio < MINIMUM_CONTRAST_RATIO) { - legendIcon.setBackgroundResource(nightMode ? R.drawable.circle_contour_bg_dark : R.drawable.circle_contour_bg_light); - } - String propertyName = segment.getUserPropertyName(); - String name = SettingsNavigationActivity.getStringPropertyName(app, propertyName, propertyName.replaceAll("_", " ")); - Spannable text = getSpanLegend(name, segment, segment.getUserPropertyName().equals(selectedPropertyName)); - TextView legend = (TextView) view.findViewById(R.id.legend_text); - legend.setText(text); - - container.addView(view); - } + private void updateCollapseIcon() { + ImageView ivCollapse = (ImageView) view.findViewById(R.id.up_down_icon); + Drawable drawable = showLegend ? + getContentIcon(R.drawable.ic_action_arrow_down) : + getActiveIcon(R.drawable.ic_action_arrow_up); + ivCollapse.setImageDrawable(drawable); } - private Spannable getSpanLegend(String title, RouteSegmentAttribute segment, boolean selected) { - String formattedDistance = OsmAndFormatter.getFormattedDistance(segment.getDistance(), getMyApplication()); - title = Algorithms.capitalizeFirstLetter(title); - SpannableStringBuilder spannable = new SpannableStringBuilder(title); - spannable.append(": "); - int startIndex = selected ? -0 : spannable.length(); - spannable.append(formattedDistance); - spannable.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), startIndex, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - - return spannable; + public CustomGraphAdapter getGraphAdapter() { + return graphAdapter; } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java index ef37797f0a..bb6483155b 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java @@ -1,13 +1,10 @@ package net.osmand.plus.routepreparationmenu.cards; -import android.graphics.Matrix; import android.os.Build; import android.text.SpannableStringBuilder; import android.text.style.ForegroundColorSpan; -import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; -import android.view.View.OnTouchListener; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -16,18 +13,12 @@ import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; 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; import net.osmand.GPXUtilities.GPXTrackAnalysis; -import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; @@ -36,6 +27,7 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType; import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet; +import net.osmand.plus.measurementtool.graph.CommonGraphAdapter; import net.osmand.plus.routing.RoutingHelper; import java.util.ArrayList; @@ -52,16 +44,15 @@ public class RouteStatisticCard extends BaseCard { private OrderedLineDataSet slopeDataSet; @Nullable private OrderedLineDataSet elevationDataSet; - private OnTouchListener onTouchListener; private OnClickListener onAnalyseClickListener; + private CommonGraphAdapter graphAdapter; - public RouteStatisticCard(MapActivity mapActivity, GPXFile gpx, OnTouchListener onTouchListener, + public RouteStatisticCard(MapActivity mapActivity, GPXFile gpx, OnClickListener onAnalyseClickListener) { super(mapActivity); this.gpx = gpx; - this.onTouchListener = onTouchListener; this.onAnalyseClickListener = onAnalyseClickListener; - makeGpxDisplayItem(); + this.gpxItem = GpxUiHelper.makeGpxDisplayItem(app, gpx); } @Nullable @@ -219,26 +210,14 @@ public class RouteStatisticCard extends BaseCard { return elevationDataSet; } - private void makeGpxDisplayItem() { - String groupName = getMyApplication().getString(R.string.current_route); - GpxSelectionHelper.GpxDisplayGroup group = getMyApplication().getSelectedGpxHelper().buildGpxDisplayGroup(gpx, 0, groupName); - if (group != null && group.getModifiableList().size() > 0) { - gpxItem = group.getModifiableList().get(0); - if (gpxItem != null) { - gpxItem.route = true; - } - } - } - @Nullable - public LineChart getChart() { - return (LineChart) view.findViewById(R.id.chart); + public CommonGraphAdapter getGraphAdapter() { + return graphAdapter; } private void buildHeader(GPXTrackAnalysis analysis) { - final LineChart mChart = (LineChart) view.findViewById(R.id.chart); - GpxUiHelper.setupGPXChart(mChart, 4, 24f, 16f, !nightMode, true); - mChart.setOnTouchListener(onTouchListener); + LineChart mChart = (LineChart) view.findViewById(R.id.chart); + graphAdapter = new CommonGraphAdapter(mChart, true); if (analysis.hasElevationData) { List dataSets = new ArrayList<>(); @@ -256,99 +235,7 @@ public class RouteStatisticCard extends BaseCard { this.elevationDataSet = elevationDataSet; this.slopeDataSet = slopeDataSet; - 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() { - boolean hasTranslated = false; - float highlightDrawX = -1; - - @Override - public void onChartGestureStart(MotionEvent me, ChartGesture lastPerformedGesture) { - hasTranslated = false; - if (mChart.getHighlighted() != null && mChart.getHighlighted().length > 0) { - highlightDrawX = mChart.getHighlighted()[0].getDrawX(); - } else { - highlightDrawX = -1; - } - CardChartListener chartListener = getChartListener(); - if (chartListener != null) { - chartListener.onChartGestureStart(RouteStatisticCard.this, me, lastPerformedGesture); - } - } - - @Override - public void onChartGestureEnd(MotionEvent me, ChartGesture lastPerformedGesture) { - gpxItem.chartMatrix = new Matrix(mChart.getViewPortHandler().getMatrixTouch()); - Highlight[] highlights = mChart.getHighlighted(); - if (highlights != null && highlights.length > 0) { - gpxItem.chartHighlightPos = highlights[0].getX(); - } else { - gpxItem.chartHighlightPos = -1; - } - CardChartListener chartListener = getChartListener(); - if (chartListener != null) { - chartListener.onChartGestureEnd(RouteStatisticCard.this, me, lastPerformedGesture, hasTranslated); - } - } - - @Override - public void onChartLongPressed(MotionEvent me) { - } - - @Override - public void onChartDoubleTapped(MotionEvent me) { - } - - @Override - public void onChartSingleTapped(MotionEvent me) { - } - - @Override - public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) { - } - - @Override - public void onChartScale(MotionEvent me, float scaleX, float scaleY) { - } - - @Override - public void onChartTranslate(MotionEvent me, float dX, float dY) { - hasTranslated = true; - if (highlightDrawX != -1) { - Highlight h = mChart.getHighlightByTouchPoint(highlightDrawX, 0f); - if (h != null) { - /* - ILineDataSet set = mChart.getLineData().getDataSetByIndex(h.getDataSetIndex()); - if (set != null && set.isHighlightEnabled()) { - Entry e = set.getEntryForXValue(h.getX(), h.getY()); - MPPointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelForValues(e.getX(), e.getY()); - h.setDraw((float) pix.x, (float) pix.y); - } - */ - mChart.highlightValue(h, true); - } - } - } - }); + graphAdapter.fullUpdate(new LineData(dataSets), gpxItem); mChart.setVisibility(View.VISIBLE); } else { mChart.setVisibility(View.GONE); From 4e80496d1e7046d0886e57954994069ba0c3475f Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Sun, 1 Nov 2020 16:42:54 +0200 Subject: [PATCH 03/34] remove unnecessary import --- OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java | 1 - 1 file changed, 1 deletion(-) diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java index 3ae28d83b2..36c8e797f1 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java @@ -36,7 +36,6 @@ import net.osmand.plus.measurementtool.graph.BaseGraphAdapter; import net.osmand.plus.measurementtool.graph.GraphAdapterHelper; import net.osmand.plus.routepreparationmenu.RouteDetailsFragment; import net.osmand.plus.routepreparationmenu.cards.BaseCard; -import net.osmand.plus.routepreparationmenu.cards.RouteStatisticCard; import net.osmand.router.RouteSegmentResult; import net.osmand.util.Algorithms; From ca6e5413d1e5418c72e321da42eb750e643f3078 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Mon, 2 Nov 2020 13:52:16 +0200 Subject: [PATCH 04/34] small fixes after SettingsBaseActivity removed --- OsmAnd/res/values/strings.xml | 1 + .../plus/measurementtool/graph/CustomGraphAdapter.java | 7 +++---- .../plus/routepreparationmenu/cards/RouteInfoCard.java | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 7861393b31..91eec18222 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,7 @@ Thx - Hardy --> + You must add at least two points. Travel Emergency Sport diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java index aded2e0fbe..e62047c151 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java @@ -22,7 +22,6 @@ import net.osmand.AndroidUtils; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; -import net.osmand.plus.activities.SettingsNavigationActivity; import net.osmand.plus.helpers.CustomBarChartRenderer; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.router.RouteStatisticsHelper; @@ -34,9 +33,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class CustomGraphAdapter extends BaseGraphAdapter { +import static net.osmand.plus.track.ColorsCard.MINIMUM_CONTRAST_RATIO; - private static final int MINIMUM_CONTRAST_RATIO = 3; +public class CustomGraphAdapter extends BaseGraphAdapter { private String selectedPropertyName; private ViewGroup legendContainer; @@ -153,7 +152,7 @@ public class CustomGraphAdapter extends BaseGraphAdapter Date: Mon, 2 Nov 2020 21:59:42 +0200 Subject: [PATCH 05/34] Fix hillshade, slope localization, map sorting --- .../plus/download/DownloadActivityType.java | 8 ++++---- .../helpers/FileNameTranslationHelper.java | 20 +++++++++++++------ .../backend/backup/SettingsHelper.java | 20 +++++++++++++++++++ 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java index 95631c9c8c..b516d73d2c 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadActivityType.java @@ -342,7 +342,7 @@ public class DownloadActivityType { return FileNameTranslationHelper.getFontName(ctx, getBasename(indexItem)); } final String basename = getBasename(indexItem); - if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)){ + if (basename.endsWith(FileNameTranslationHelper.WIKI_NAME)) { return FileNameTranslationHelper.getWikiName(ctx, basename); } // if (this == HILLSHADE_FILE){ @@ -357,7 +357,7 @@ public class DownloadActivityType { final int ind = basename.indexOf("addresses-nationwide"); String downloadName = basename.substring(0, ind - 1) + basename.substring(ind + "addresses-nationwide".length()); return osmandRegions.getLocaleName(downloadName, includingParent) + - " "+ ctx.getString(R.string.index_item_nation_addresses); + " " + ctx.getString(R.string.index_item_nation_addresses); } else if (basename.startsWith("Depth_")) { final int extInd = basename.indexOf("osmand_ext"); String downloadName = extInd == -1 ? basename.substring(6, basename.length()).replace('_', ' ') @@ -438,11 +438,11 @@ public class DownloadActivityType { } if (this == HILLSHADE_FILE) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()) - .replace(FileNameTranslationHelper.HILL_SHADE, ""); + .replace(FileNameTranslationHelper.HILL_SHADE + "_", ""); } if (this == SLOPE_FILE) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()) - .replace(FileNameTranslationHelper.SLOPE, ""); + .replace(FileNameTranslationHelper.SLOPE + "_", ""); } if (fileName.endsWith(IndexConstants.SQLITE_EXT)) { return fileName.substring(0, fileName.length() - IndexConstants.SQLITE_EXT.length()); diff --git a/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java b/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java index 229003050e..e366d1e8bb 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/FileNameTranslationHelper.java @@ -4,6 +4,7 @@ import android.content.Context; import net.osmand.IndexConstants; import net.osmand.PlatformUtil; import net.osmand.map.OsmandRegions; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.download.DownloadResources; @@ -18,10 +19,14 @@ import java.lang.reflect.Field; public class FileNameTranslationHelper { private static final Log LOG = PlatformUtil.getLog(FileNameTranslationHelper.class); public static final String WIKI_NAME = "_wiki"; - public static final String HILL_SHADE = "Hillshade_"; - public static final String SLOPE = "Slope_"; + public static final String HILL_SHADE = "Hillshade"; + public static final String SLOPE = "Slope"; public static final String SEA_DEPTH = "Depth_"; + public static String getFileNameWithRegion(OsmandApplication app, String fileName) { + return getFileName(app, app.getResourceManager().getOsmandRegions(), fileName); + } + public static String getFileName(Context ctx, OsmandRegions regions, String fileName) { String basename = getBasename(fileName); if (basename.endsWith(WIKI_NAME)) { //wiki files @@ -30,13 +35,15 @@ public class FileNameTranslationHelper { return getVoiceName(ctx, fileName); } else if (fileName.endsWith(IndexConstants.FONT_INDEX_EXT)) { //otf files return getFontName(ctx, basename); - } else if (fileName.startsWith(HILL_SHADE)){ + } else if (fileName.startsWith(HILL_SHADE)) { + basename = basename.replace(HILL_SHADE + " ", ""); return getTerrainName(ctx, regions, basename, R.string.download_hillshade_maps); } else if (fileName.startsWith(SLOPE)) { + basename = basename.replace(SLOPE + " ", ""); return getTerrainName(ctx, regions, basename, R.string.download_slope_maps); } else if (fileName.length() == 2) { //voice recorded files try { - Field f = R.string.class.getField("lang_"+fileName); + Field f = R.string.class.getField("lang_" + fileName); if (f != null) { Integer in = (Integer) f.get(null); return ctx.getString(in); @@ -62,9 +69,10 @@ public class FileNameTranslationHelper { public static String getTerrainName(Context ctx, OsmandRegions regions, String basename, int terrainNameRes) { - String terrain = ctx.getString(terrainNameRes) + " "; + basename = basename.replace(" ", "_"); + String terrain = ctx.getString(terrainNameRes); String locName = regions.getLocaleName(basename.trim(), true); - return terrain + locName; + return ctx.getString(R.string.ltr_or_rtl_combine_via_space, locName, "(" + terrain + ")"); } public static String getWikiName(Context ctx, String basename){ diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java index f3821505a2..f6cbdb4b43 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -7,7 +7,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import net.osmand.AndroidUtils; +import net.osmand.Collator; import net.osmand.IndexConstants; +import net.osmand.OsmAndCollator; import net.osmand.PlatformUtil; import net.osmand.data.LatLon; import net.osmand.map.ITileSource; @@ -23,6 +25,7 @@ import net.osmand.plus.audionotes.AudioVideoNotesPlugin; import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording; import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask; import net.osmand.plus.helpers.AvoidSpecificRoads.AvoidRoadInfo; +import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper.GPXInfo; import net.osmand.plus.osmedit.OpenstreetmapPoint; @@ -42,6 +45,8 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -542,6 +547,7 @@ public class SettingsHelper { files = getFilesByType(localIndexInfoList, LocalIndexType.MAP_DATA, LocalIndexType.TILES_DATA, LocalIndexType.SRTM_DATA, LocalIndexType.WIKI_DATA); if (!files.isEmpty()) { + sortData(files); dataList.put(ExportSettingsType.OFFLINE_MAPS, files); } files = getFilesByType(localIndexInfoList, LocalIndexType.TTS_VOICE_DATA); @@ -801,4 +807,18 @@ public class SettingsHelper { } return settingsToOperate; } + + public void sortData(List files) { + final Collator collator = OsmAndCollator.primaryCollator(); + Collections.sort(files, new Comparator() { + @Override + public int compare(File lhs, File rhs) { + return collator.compare(getNameToDisplay(lhs), getNameToDisplay(rhs)); + } + + private String getNameToDisplay(File item) { + return FileNameTranslationHelper.getFileNameWithRegion(app, item.getName()); + } + }); + } } \ No newline at end of file From 38ebaccc288f3ee08bc84ef809b4740fe0ed2153 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Tue, 3 Nov 2020 11:30:53 +0200 Subject: [PATCH 06/34] fix "Plan Route: Graphs" bugs and refactoring --- .../fragment_measurement_tool_graph.xml | 122 ++++++++------ .../net/osmand/plus/helpers/GpxUiHelper.java | 108 ++++++++---- .../plus/measurementtool/GraphsCard.java | 157 ++++++++++-------- .../graph/BaseGraphAdapter.java | 34 ++-- .../graph/CommonGraphAdapter.java | 40 ++--- .../graph/CustomGraphAdapter.java | 31 ++-- .../plus/myplaces/TrackSegmentFragment.java | 5 +- .../RouteDetailsFragment.java | 9 +- .../cards/RouteInfoCard.java | 1 + .../cards/RouteStatisticCard.java | 3 +- 10 files changed, 289 insertions(+), 221 deletions(-) diff --git a/OsmAnd/res/layout/fragment_measurement_tool_graph.xml b/OsmAnd/res/layout/fragment_measurement_tool_graph.xml index 45f0b484d5..555c1b6928 100644 --- a/OsmAnd/res/layout/fragment_measurement_tool_graph.xml +++ b/OsmAnd/res/layout/fragment_measurement_tool_graph.xml @@ -26,9 +26,9 @@ android:id="@+id/common_graphs_container" android:layout_width="match_parent" android:layout_height="wrap_content" + android:orientation="vertical" android:visibility="gone" - tools:visibility="visible" - android:orientation="vertical"> + tools:visibility="visible"> + tools:visibility="visible"> + android:background="?attr/list_divider" /> - - - - + tools:visibility="visible"> + android:layout_marginStart="@dimen/content_padding" + android:layout_marginLeft="@dimen/content_padding" + android:layout_marginTop="@dimen/content_padding_small" + android:layout_marginEnd="@dimen/content_padding" + android:layout_marginRight="@dimen/content_padding" + android:orientation="horizontal"> - + + + + + + + + + + + + + + + @@ -134,8 +158,8 @@ android:id="@+id/btn_text" android:layout_width="match_parent" android:layout_height="0dp" - android:layout_weight="1" android:layout_gravity="start|center_vertical" + android:layout_weight="1" android:gravity="start|center_vertical" android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier" android:textColor="@color/preference_category_title" diff --git a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java index edcf3dc07f..dd2a35a9a4 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java @@ -2057,47 +2057,85 @@ public class GpxUiHelper { OsmandApplication app, GPXTrackAnalysis analysis, boolean calcWithoutGaps, - LineGraphType... types) { + LineGraphType ... types) { if (app == null || chart == null || analysis == null || types == null) { - return Collections.emptyList(); + return new ArrayList<>(); } - List dataList = new ArrayList<>(); - for (LineGraphType type : types) { - switch (type) { - case ALTITUDE: { - if (analysis.hasElevationData) { - OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps); - dataList.add(elevationDataSet); - } - break; + if (types.length > 1) { + return getDataSetsImpl(chart, app, analysis, calcWithoutGaps, types[0], types[1]); + } else { + return getDataSetsImpl(chart, app, analysis, calcWithoutGaps, types[0]); + } + } + + private static List getDataSetsImpl(@NonNull LineChart chart, + @NonNull OsmandApplication app, + @NonNull GPXTrackAnalysis analysis, + boolean calcWithoutGaps, + @NonNull LineGraphType type) { + List result = new ArrayList<>(); + ILineDataSet dataSet = getDataSet(chart, app, analysis, calcWithoutGaps, false, type); + if (dataSet != null) { + result.add(dataSet); + } + return result; + } + + private static List getDataSetsImpl(@NonNull LineChart chart, + @NonNull OsmandApplication app, + @NonNull GPXTrackAnalysis analysis, + boolean calcWithoutGaps, + @NonNull LineGraphType type1, + @NonNull LineGraphType type2) { + List result = new ArrayList<>(); + OrderedLineDataSet dataSet1 = getDataSet(chart, app, analysis, calcWithoutGaps, false, type1); + OrderedLineDataSet dataSet2 = getDataSet(chart, app, analysis, calcWithoutGaps, true, type2); + if (dataSet1 == null && dataSet2 == null) { + return new ArrayList<>(); + } else if (dataSet1 == null) { + result.add(dataSet2); + } else if (dataSet2 == null) { + result.add(dataSet1); + } else if (dataSet1.getPriority() < dataSet2.getPriority()) { + result.add(dataSet2); + result.add(dataSet1); + } else { + result.add(dataSet1); + result.add(dataSet2); + } + return result; + } + + private static OrderedLineDataSet getDataSet(@NonNull LineChart chart, + @NonNull OsmandApplication app, + @NonNull GPXTrackAnalysis analysis, + boolean calcWithoutGaps, + boolean useRightAxis, + @NonNull LineGraphType type) { + OrderedLineDataSet dataSet = null; + switch (type) { + case ALTITUDE: { + if (analysis.hasElevationData) { + dataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, + analysis, GPXDataSetAxisType.DISTANCE, useRightAxis, true, calcWithoutGaps); } - case SLOPE: - if (analysis.hasElevationData) { - OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, null, true, true, calcWithoutGaps); - dataList.add(slopeDataSet); - } - break; - case SPEED: { - if (analysis.hasSpeedData) { - OrderedLineDataSet speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, - analysis, GPXDataSetAxisType.DISTANCE, false, true, calcWithoutGaps); - dataList.add(speedDataSet); - } - break; + break; + } + case SLOPE: + if (analysis.hasElevationData) { + dataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, + analysis, GPXDataSetAxisType.DISTANCE, null, useRightAxis, true, calcWithoutGaps); } + break; + case SPEED: { + if (analysis.hasSpeedData) { + dataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, + analysis, GPXDataSetAxisType.DISTANCE, useRightAxis, true, calcWithoutGaps); + } + break; } } - if (dataList.size() > 0) { - Collections.sort(dataList, new Comparator() { - @Override - public int compare(OrderedLineDataSet o1, OrderedLineDataSet o2) { - return Float.compare(o1.getPriority(), o2.getPriority()); - } - }); - } - return new ArrayList(dataList); + return dataSet; } public static GpxDisplayItem makeGpxDisplayItem(OsmandApplication app, GPXUtilities.GPXFile gpx) { diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java index a7f35b4d0a..69277f19a6 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java @@ -25,8 +25,6 @@ import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.helpers.GpxUiHelper.LineGraphType; -import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType; -import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener; import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; @@ -47,6 +45,9 @@ import java.util.List; import static net.osmand.GPXUtilities.GPXFile; import static net.osmand.GPXUtilities.GPXTrackAnalysis; +import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.ALTITUDE; +import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SLOPE; +import static net.osmand.plus.helpers.GpxUiHelper.LineGraphType.SPEED; import static net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem; import static net.osmand.router.RouteStatisticsHelper.RouteStatistics; @@ -57,9 +58,9 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private MeasurementEditingContext editingCtx; private MeasurementToolFragment fragment; - - private GraphType visibleType; - private List graphTypes = new ArrayList<>(); + private TrackDetailsMenu trackDetailsMenu; + private GPXFile gpxFile; + private GPXTrackAnalysis analysis; private GpxDisplayItem gpxItem; private View commonGraphContainer; @@ -69,24 +70,8 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private CustomGraphAdapter customGraphAdapter; private RecyclerView graphTypesMenu; - private TrackDetailsMenu trackDetailsMenu; - - private enum CommonGraphType { - OVERVIEW(R.string.shared_string_overview, true, LineGraphType.ALTITUDE, LineGraphType.SLOPE), - ALTITUDE(R.string.altitude, true, LineGraphType.ALTITUDE), - SLOPE(R.string.shared_string_slope, true, LineGraphType.SLOPE), - SPEED(R.string.map_widget_speed, false, LineGraphType.SPEED); - - CommonGraphType(int titleId, boolean canBeCalculated, LineGraphType ... lineGraphTypes) { - this.titleId = titleId; - this.canBeCalculated = canBeCalculated; - this.lineGraphTypes = lineGraphTypes; - } - - final int titleId; - final boolean canBeCalculated; - final LineGraphType[] lineGraphTypes; - } + private GraphType visibleType; + private List graphTypes = new ArrayList<>(); public GraphsCard(@NonNull MapActivity mapActivity, TrackDetailsMenu trackDetailsMenu, @@ -137,23 +122,23 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private void fullUpdate() { if (!isRouteCalculating()) { updateData(); - updateVisibleType(); - updateTypesMenu(); + setupVisibleType(); + updateMenu(); } - updateInfoView(); + updateView(); } - private void updateTypesMenu() { + private void updateMenu() { if (!editingCtx.isPointsEnoughToCalculateRoute()) { graphTypesMenu.setVisibility(View.GONE); } else { graphTypesMenu.setVisibility(View.VISIBLE); graphTypesMenu.removeAllViews(); - fillInTypesMenu(); + fillInMenu(); } } - private void fillInTypesMenu() { + private void fillInMenu() { OsmandApplication app = getMyApplication(); int activeColorId = nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light; final HorizontalSelectionAdapter adapter = new HorizontalSelectionAdapter(app, nightMode); @@ -176,7 +161,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen adapter.setItems(items); adapter.setSelectedItem(item); GraphType chosenType = (GraphType) item.getObject(); - if (!isCurrentVisibleType(chosenType)) { + if (!isVisibleType(chosenType)) { changeVisibleType(chosenType); } } @@ -187,10 +172,10 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private void changeVisibleType(GraphType type) { visibleType = type; - updateInfoView(); + updateView(); } - private boolean isCurrentVisibleType(GraphType type) { + private boolean isVisibleType(GraphType type) { if (visibleType != null && type != null) { return Algorithms.objectEquals(visibleType.getTitle(), type.getTitle()); } @@ -206,7 +191,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen return null; } - private void updateInfoView() { + private void updateView() { hideAll(); if (!editingCtx.isPointsEnoughToCalculateRoute()) { showMessage(app.getString(R.string.message_you_need_add_two_points_to_show_graphs)); @@ -279,54 +264,59 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen CustomGraphType customGraphType = (CustomGraphType) visibleType; customGraphContainer.setVisibility(View.VISIBLE); customGraphAdapter.setLegendViewType(LegendViewType.ONE_ELEMENT); - customGraphAdapter.fullUpdate((BarData) customGraphType.getGraphData(), customGraphType.getStatistics()); + customGraphAdapter.updateContent(customGraphType.getChartData(), customGraphType.getStatistics()); } else { + CommonGraphType commonGraphType = (CommonGraphType) visibleType; commonGraphContainer.setVisibility(View.VISIBLE); customGraphAdapter.setLegendViewType(LegendViewType.GONE); - commonGraphAdapter.fullUpdate((LineData) visibleType.getGraphData(), gpxItem); + commonGraphAdapter.updateContent(commonGraphType.getChartData(), gpxItem); } } private void updateData() { graphTypes.clear(); OsmandApplication app = getMyApplication(); - GPXFile gpxFile = getGpxFile(); - GPXTrackAnalysis analysis = gpxFile != null ? gpxFile.getAnalysis(0) : null; + gpxFile = getGpxFile(); + analysis = gpxFile != null ? gpxFile.getAnalysis(0) : null; gpxItem = gpxFile != null ? GpxUiHelper.makeGpxDisplayItem(app, gpxFile) : null; if (gpxItem != null) { trackDetailsMenu.setGpxItem(gpxItem); } + if (analysis == null) return; // update common graph data - for (CommonGraphType commonType : CommonGraphType.values()) { - List dataSets = GpxUiHelper.getDataSets(commonGraphAdapter.getChart(), - app, analysis, false, commonType.lineGraphTypes); - LineData data = !Algorithms.isEmpty(dataSets) ? new LineData(dataSets) : null; - String title = app.getString(commonType.titleId); - graphTypes.add(new GraphType(title, commonType.canBeCalculated, data)); - } + boolean hasElevationData = analysis.hasElevationData; + boolean hasSpeedData = analysis.isSpeedSpecified(); + addCommonType(R.string.shared_string_overview, true, hasElevationData, ALTITUDE, SLOPE); + addCommonType(R.string.altitude, true, hasElevationData, ALTITUDE); + addCommonType(R.string.shared_string_slope, true, hasElevationData, SLOPE); + addCommonType(R.string.map_widget_speed, false, hasSpeedData, SPEED); // update custom graph data List routeStatistics = calculateRouteStatistics(); if (analysis != null && routeStatistics != null) { for (RouteStatistics statistics : routeStatistics) { String title = AndroidUtils.getStringRouteInfoPropertyValue(app, statistics.name); - BarData data = null; - if (!Algorithms.isEmpty(statistics.elements)) { - data = GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(), - statistics, analysis, true, nightMode); - } - graphTypes.add(new CustomGraphType(title, false, data, statistics)); + graphTypes.add(new CustomGraphType(title, statistics)); } } } - private void updateVisibleType() { + private void addCommonType(int titleId, + boolean canBeCalculated, + boolean hasData, + LineGraphType ... lineGraphTypes) { + OsmandApplication app = getMyApplication(); + String title = app.getString(titleId); + graphTypes.add(new CommonGraphType(title, canBeCalculated, hasData, lineGraphTypes)); + } + + private void setupVisibleType() { if (visibleType == null) { visibleType = getFirstAvailableType(); } else { for (GraphType type : graphTypes) { - if (isCurrentVisibleType(type)) { + if (isVisibleType(type)) { visibleType = type.isAvailable() ? type : getFirstAvailableType(); break; } @@ -346,23 +336,23 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private List calculateRouteStatistics() { OsmandApplication app = getMyApplication(); List route = editingCtx.getAllRouteSegments(); - if (route == null || app == null) return null; - return RouteDetailsFragment.calculateRouteStatistics(app, route, nightMode); + if (route != null && app != null) { + return RouteDetailsFragment.calculateRouteStatistics(app, route, nightMode); + } + return null; } private boolean isRouteCalculating() { return fragment.isProgressBarVisible(); } - private class GraphType { + private abstract class GraphType { private String title; private boolean canBeCalculated; - private ChartData graphData; - public GraphType(String title, boolean canBeCalculated, ChartData graphData) { + public GraphType(String title, boolean canBeCalculated) { this.title = title; this.canBeCalculated = canBeCalculated; - this.graphData = graphData; } public String getTitle() { @@ -385,26 +375,63 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen return canBeCalculated; } - public boolean hasData() { - return getGraphData() != null; + public abstract boolean hasData(); + + public abstract T getChartData(); + } + + private class CommonGraphType extends GraphType { + + private boolean hasData; + private LineGraphType[] lineGraphTypes; + + public CommonGraphType(String title, boolean canBeCalculated, boolean hasData, LineGraphType ... lineGraphTypes) { + super(title, canBeCalculated); + this.hasData = hasData; + this.lineGraphTypes = lineGraphTypes; } - public ChartData getGraphData() { - return graphData; + @Override + public boolean hasData() { + return hasData; + } + + @Override + public LineData getChartData() { + GpxUiHelper.setupGPXChart(commonGraphAdapter.getChart(), 4, 24f, 16f, !nightMode, true); + List dataSets = GpxUiHelper.getDataSets(commonGraphAdapter.getChart(), + app, analysis, false, lineGraphTypes); + return !Algorithms.isEmpty(dataSets) ? new LineData(dataSets) : null; } } - private class CustomGraphType extends GraphType { + private class CustomGraphType extends GraphType { private RouteStatistics statistics; - public CustomGraphType(String title, boolean canBeCalculated, ChartData graphData, RouteStatistics statistics) { - super(title, canBeCalculated, graphData); + public CustomGraphType(String title, RouteStatistics statistics) { + super(title, false); this.statistics = statistics; } public RouteStatistics getStatistics() { return statistics; } + + @Override + public boolean hasData() { + return !Algorithms.isEmpty(statistics.elements); + } + + @Override + public BarData getChartData() { + GpxUiHelper.setupHorizontalGPXChart(app, customGraphAdapter.getChart(), 5, 9, 24, true, nightMode); + BarData data = null; + if (!Algorithms.isEmpty(statistics.elements)) { + data = GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(), + statistics, analysis, true, nightMode); + } + return data; + } } } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java index dc83460a3f..5f9e1fdc29 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/BaseGraphAdapter.java @@ -10,27 +10,27 @@ import com.github.mikephil.charting.listener.ChartTouchListener; import net.osmand.plus.OsmandApplication; -public abstract class BaseGraphAdapter { +public abstract class BaseGraphAdapter<_Chart extends Chart, _ChartData extends ChartData, _Data> { private Highlight lastKnownHighlight; - protected CHART mChart; - protected CHART_DATA mChartData; - protected DATA mAdditionalData; + protected _Chart chart; + protected _ChartData chartData; + protected _Data additionalData; protected boolean usedOnMap; - public BaseGraphAdapter(CHART chart, boolean usedOnMap) { - this.mChart = chart; + public BaseGraphAdapter(_Chart chart, boolean usedOnMap) { + this.chart = chart; this.usedOnMap = usedOnMap; - prepareCharterView(); + prepareChartView(); } - protected void prepareCharterView() { - mChart.setExtraRightOffset(16); - mChart.setExtraLeftOffset(16); + protected void prepareChartView() { + chart.setExtraRightOffset(16); + chart.setExtraLeftOffset(16); } - public CHART getChart() { - return mChart; + public _Chart getChart() { + return chart; } protected void updateHighlight() { @@ -41,14 +41,14 @@ public abstract class BaseGraphAdapter 0) { - highlightDrawX = mChart.getHighlighted()[0].getDrawX(); + if (chart.getHighlighted() != null && chart.getHighlighted().length > 0) { + highlightDrawX = chart.getHighlighted()[0].getDrawX(); } else { highlightDrawX = -1; } @@ -68,8 +67,8 @@ public class CommonGraphAdapter extends BaseGraphAdapter 0) { gpxItem.chartHighlightPos = highlights[0].getX(); } else { @@ -104,17 +103,9 @@ public class CommonGraphAdapter extends BaseGraphAdapter 0) { - gpxItem = group.getModifiableList().get(0); - if (gpxItem != null) { - gpxItem.route = true; - } - } + gpxItem = GpxUiHelper.makeGpxDisplayItem(app, gpx); } void openDetails() { diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java index c2cbec6f7b..124687f2f7 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java @@ -41,6 +41,7 @@ public class RouteInfoCard extends BaseCard { updateHeader(); LinearLayout container = (LinearLayout) view.findViewById(R.id.route_items); HorizontalBarChart chart = (HorizontalBarChart) view.findViewById(R.id.chart); + GpxUiHelper.setupHorizontalGPXChart(getMyApplication(), chart, 5, 9, 24, true, nightMode); BarData barData = GpxUiHelper.buildStatisticChart(app, chart, statistics, analysis, true, nightMode); graphAdapter = new CustomGraphAdapter(chart, true); graphAdapter.setLegendContainer(container); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java index bb6483155b..e25c242469 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteStatisticCard.java @@ -217,6 +217,7 @@ public class RouteStatisticCard extends BaseCard { private void buildHeader(GPXTrackAnalysis analysis) { LineChart mChart = (LineChart) view.findViewById(R.id.chart); + GpxUiHelper.setupGPXChart(mChart, 4, 24f, 16f, !nightMode, true); graphAdapter = new CommonGraphAdapter(mChart, true); if (analysis.hasElevationData) { @@ -235,7 +236,7 @@ public class RouteStatisticCard extends BaseCard { this.elevationDataSet = elevationDataSet; this.slopeDataSet = slopeDataSet; - graphAdapter.fullUpdate(new LineData(dataSets), gpxItem); + graphAdapter.updateContent(new LineData(dataSets), gpxItem); mChart.setVisibility(View.VISIBLE); } else { mChart.setVisibility(View.GONE); From 7d9dbb09ff84ffac2368a4ef41ac54780990b648 Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Tue, 3 Nov 2020 17:29:56 +0200 Subject: [PATCH 07/34] Fix import duplicates --- .../plus/activities/LocalIndexHelper.java | 2 +- .../backend/backup/DataSettingsItem.java | 2 +- .../backend/backup/FavoritesSettingsItem.java | 3 +- .../backend/backup/FileSettingsItem.java | 138 ++++++++++-------- .../backup/OsmandSettingsItemReader.java | 3 +- .../backend/backup/SettingsExporter.java | 1 - .../backend/backup/SettingsHelper.java | 7 +- .../backend/backup/SettingsImporter.java | 2 +- .../settings/backend/backup/SettingsItem.java | 2 +- .../backend/backup/SettingsItemReader.java | 3 +- .../fragments/DuplicatesSettingsAdapter.java | 28 ++-- .../ExportImportSettingsAdapter.java | 20 +-- .../fragments/ImportDuplicatesFragment.java | 51 ++++++- 13 files changed, 149 insertions(+), 113 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java index 1e53f97603..7c64e3a669 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalIndexHelper.java @@ -214,7 +214,7 @@ public class LocalIndexHelper { return result; } - public void loadVoiceData(File voiceDir, List result, boolean backup, AbstractLoadLocalIndexTask loadTask) { + private void loadVoiceData(File voiceDir, List result, boolean backup, AbstractLoadLocalIndexTask loadTask) { if (voiceDir.canRead()) { //First list TTS files, they are preferred for (File voiceF : listFilesSorted(voiceDir)) { diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java index 75529aa543..d040f20411 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/DataSettingsItem.java @@ -64,7 +64,7 @@ public class DataSettingsItem extends StreamSettingsItem { SettingsItemReader getReader() { return new StreamSettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[SettingsHelper.BUFFER]; diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java index a035ae0146..817ec38a49 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FavoritesSettingsItem.java @@ -16,7 +16,6 @@ import net.osmand.plus.R; import org.json.JSONException; import org.json.JSONObject; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -146,7 +145,7 @@ public class FavoritesSettingsItem extends CollectionSettingsItem return new SettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IllegalArgumentException { GPXFile gpxFile = GPXUtilities.loadGPXFile(inputStream); if (gpxFile.error != null) { warnings.add(app.getString(R.string.settings_item_read_error, String.valueOf(getType()))); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java index 3b4f8568e1..62cd9df7d5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java @@ -1,5 +1,6 @@ package net.osmand.plus.settings.backend.backup; +import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -23,36 +24,34 @@ import java.util.zip.ZipOutputStream; public class FileSettingsItem extends StreamSettingsItem { public enum FileSubtype { - UNKNOWN("", null), - OTHER("other", ""), - ROUTING_CONFIG("routing_config", IndexConstants.ROUTING_PROFILES_DIR), - RENDERING_STYLE("rendering_style", IndexConstants.RENDERERS_DIR), - WIKI_MAP("wiki_map", IndexConstants.WIKI_INDEX_DIR), - SRTM_MAP("srtm_map", IndexConstants.SRTM_INDEX_DIR), - OBF_MAP("obf_map", IndexConstants.MAPS_PATH), - TILES_MAP("tiles_map", IndexConstants.TILES_INDEX_DIR), - GPX("gpx", IndexConstants.GPX_INDEX_DIR), - TTS_VOICE("tts_voice", IndexConstants.VOICE_INDEX_DIR), - VOICE("voice", IndexConstants.VOICE_INDEX_DIR), - TRAVEL("travel", IndexConstants.WIKIVOYAGE_INDEX_DIR), - MULTIMEDIA_NOTES("multimedia_notes", IndexConstants.AV_INDEX_DIR); + UNKNOWN("", null, -1), + OTHER("other", "", -1), + ROUTING_CONFIG("routing_config", IndexConstants.ROUTING_PROFILES_DIR, R.drawable.ic_action_route_distance), + RENDERING_STYLE("rendering_style", IndexConstants.RENDERERS_DIR, R.drawable.ic_action_map_style), + WIKI_MAP("wiki_map", IndexConstants.WIKI_INDEX_DIR, R.drawable.ic_plugin_wikipedia), + SRTM_MAP("srtm_map", IndexConstants.SRTM_INDEX_DIR, R.drawable.ic_plugin_srtm), + OBF_MAP("obf_map", IndexConstants.MAPS_PATH, R.drawable.ic_map), + TILES_MAP("tiles_map", IndexConstants.TILES_INDEX_DIR, R.drawable.ic_map), + GPX("gpx", IndexConstants.GPX_INDEX_DIR, R.drawable.ic_action_route_distance), + TTS_VOICE("tts_voice", IndexConstants.VOICE_INDEX_DIR, R.drawable.ic_action_volume_up), + VOICE("voice", IndexConstants.VOICE_INDEX_DIR, R.drawable.ic_action_volume_up), + TRAVEL("travel", IndexConstants.WIKIVOYAGE_INDEX_DIR, R.drawable.ic_plugin_wikipedia), + MULTIMEDIA_NOTES("multimedia_notes", IndexConstants.AV_INDEX_DIR, R.drawable.ic_action_photo_dark); - private String subtypeName; - private String subtypeFolder; + private final String subtypeName; + private final String subtypeFolder; + private final int iconId; - FileSubtype(String subtypeName, String subtypeFolder) { + FileSubtype(@NonNull String subtypeName, String subtypeFolder, @DrawableRes int iconId) { this.subtypeName = subtypeName; this.subtypeFolder = subtypeFolder; + this.iconId = iconId; } public boolean isMap() { return this == OBF_MAP || this == WIKI_MAP || this == SRTM_MAP || this == TILES_MAP; } - public boolean isDirectory() { - return this == TTS_VOICE || this == VOICE; - } - public String getSubtypeName() { return subtypeName; } @@ -61,6 +60,10 @@ public class FileSettingsItem extends StreamSettingsItem { return subtypeFolder; } + public int getIconId() { + return iconId; + } + public static FileSubtype getSubtypeByName(@NonNull String name) { for (FileSubtype subtype : FileSubtype.values()) { if (name.equals(subtype.subtypeName)) { @@ -227,15 +230,30 @@ public class FileSettingsItem extends StreamSettingsItem { return file.exists(); } - private File renameFile(File file) { + private File renameFile(File oldFile) { int number = 0; - String path = file.getAbsolutePath(); + String oldPath = oldFile.getAbsolutePath(); + String suffix; + String prefix; + if (file.isDirectory()) { + prefix = file.getAbsolutePath(); + suffix = oldPath.replace(file.getAbsolutePath(), ""); + } else if (oldPath.endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { + prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)); + suffix = IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; + } else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { + prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)); + suffix = IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; + } else { + prefix = oldPath.substring(0, oldPath.lastIndexOf(".")); + suffix = "." + Algorithms.getFileExtension(oldFile); + } while (true) { number++; - String copyName = path.replaceAll(file.getName(), file.getName().replaceFirst("[.]", "_" + number + ".")); - File copyFile = new File(copyName); - if (!copyFile.exists()) { - return copyFile; + String newName = prefix + "_" + number + suffix; + File newFile = new File(newName); + if (!newFile.exists()) { + return newFile; } } } @@ -245,8 +263,12 @@ public class FileSettingsItem extends StreamSettingsItem { SettingsItemReader getReader() { return new StreamSettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File dest) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { OutputStream output; + File dest = FileSettingsItem.this.getFile(); + if (dest.isDirectory()) { + dest = new File(dest, entryName.substring(fileName.length())); + } if (dest.exists() && !shouldReplace) { dest = renameFile(dest); } @@ -271,46 +293,42 @@ public class FileSettingsItem extends StreamSettingsItem { @Nullable @Override public SettingsItemWriter getWriter() { - try { - if (!file.isDirectory()) { + if (!file.isDirectory()) { + try { setInputStream(new FileInputStream(file)); + } catch (FileNotFoundException e) { + warnings.add(app.getString(R.string.settings_item_read_error, file.getName())); + SettingsHelper.LOG.error("Failed to set input stream from file: " + file.getName(), e); } - } catch (FileNotFoundException e) { - warnings.add(app.getString(R.string.settings_item_read_error, file.getName())); - SettingsHelper.LOG.error("Failed to set input stream from file: " + file.getName(), e); - } - return new StreamSettingsItemWriter(this) { + return super.getWriter(); + } else { + return new StreamSettingsItemWriter(this) { - @Override - public void writeEntry(String fileName, @NonNull ZipOutputStream zos) throws IOException { - if (getSubtype().isDirectory()) { - File file = getFile(); + @Override + public void writeEntry(String fileName, @NonNull ZipOutputStream zos) throws IOException { zipDirsWithFiles(file, zos); - } else { - super.writeEntry(fileName, zos); } - } - public void zipDirsWithFiles(File f, ZipOutputStream zos) - throws IOException { - if (f == null) { - return; - } - if (f.isDirectory()) { - File[] fs = f.listFiles(); - if (fs != null) { - for (File c : fs) { - zipDirsWithFiles(c, zos); - } + public void zipDirsWithFiles(File file, ZipOutputStream zos) throws IOException { + if (file == null) { + return; + } + if (file.isDirectory()) { + File[] fs = file.listFiles(); + if (fs != null) { + for (File c : fs) { + zipDirsWithFiles(c, zos); + } + } + } else { + String zipEntryName = Algorithms.isEmpty(getSubtype().getSubtypeFolder()) + ? file.getName() + : file.getPath().substring(file.getPath().indexOf(getSubtype().getSubtypeFolder()) - 1); + setInputStream(new FileInputStream(file)); + super.writeEntry(zipEntryName, zos); } - } else { - String zipEntryName = Algorithms.isEmpty(getSubtype().getSubtypeFolder()) - ? f.getName() - : f.getPath().substring(f.getPath().indexOf(getSubtype().getSubtypeFolder()) - 1); - setInputStream(new FileInputStream(f)); - super.writeEntry(zipEntryName, zos); } - } - }; + }; + } } } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java index df68e8a3e3..1fd27e192f 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OsmandSettingsItemReader.java @@ -10,7 +10,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -30,7 +29,7 @@ public abstract class OsmandSettingsItemReader ext @NonNull JSONObject json) throws JSONException; @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { StringBuilder buf = new StringBuilder(); try { BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java index 3a697b77c0..5b27f2afb4 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java @@ -72,7 +72,6 @@ class SettingsExporter { } } - private JSONObject createItemsJson() throws JSONException { JSONObject json = new JSONObject(); json.put("version", SettingsHelper.VERSION); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java index f6cbdb4b43..469e9ebde0 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -542,9 +542,8 @@ public class SettingsHelper { if (!favoriteGroups.isEmpty()) { dataList.put(ExportSettingsType.FAVORITES, favoriteGroups); } - List localIndexInfoList = getVoiceIndexInfo(); - List files; - files = getFilesByType(localIndexInfoList, LocalIndexType.MAP_DATA, LocalIndexType.TILES_DATA, + List localIndexInfoList = getLocalIndexData(); + List files = getFilesByType(localIndexInfoList, LocalIndexType.MAP_DATA, LocalIndexType.TILES_DATA, LocalIndexType.SRTM_DATA, LocalIndexType.WIKI_DATA); if (!files.isEmpty()) { sortData(files); @@ -561,7 +560,7 @@ public class SettingsHelper { return dataList; } - private List getVoiceIndexInfo() { + private List getLocalIndexData() { return new LocalIndexHelper(app).getLocalIndexData(new AbstractLoadLocalIndexTask() { @Override public void loadFile(LocalIndexInfo... loaded) { diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java index fcc1fba2f7..7f72761066 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsImporter.java @@ -124,7 +124,7 @@ class SettingsImporter { try { SettingsItemReader reader = item.getReader(); if (reader != null) { - reader.readFromStream(ois, app.getAppPath(fileName)); + reader.readFromStream(ois, fileName); } } catch (IllegalArgumentException e) { item.warnings.add(app.getString(R.string.settings_item_read_error, item.getName())); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java index 815710b94c..afe776db09 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItem.java @@ -169,7 +169,7 @@ public abstract class SettingsItem { SettingsItemReader getJsonReader() { return new SettingsItemReader(this) { @Override - public void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException { + public void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException { StringBuilder buf = new StringBuilder(); try { BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java index 2e38e04f08..12af0ee3c5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsItemReader.java @@ -2,7 +2,6 @@ package net.osmand.plus.settings.backend.backup; import androidx.annotation.NonNull; -import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -14,5 +13,5 @@ public abstract class SettingsItemReader { this.item = item; } - public abstract void readFromStream(@NonNull InputStream inputStream, File destination) throws IOException, IllegalArgumentException; + public abstract void readFromStream(@NonNull InputStream inputStream, String entryName) throws IOException, IllegalArgumentException; } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java index d90f4b7429..efda7de984 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/DuplicatesSettingsAdapter.java @@ -15,6 +15,7 @@ import net.osmand.PlatformUtil; import net.osmand.map.ITileSource; import net.osmand.plus.FavouritesDbHelper.FavoriteGroup; import net.osmand.plus.audionotes.AudioVideoNotesPlugin; +import net.osmand.plus.helpers.FileNameTranslationHelper; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; @@ -34,6 +35,8 @@ import org.apache.commons.logging.Log; import java.io.File; import java.util.List; +import static net.osmand.plus.settings.backend.backup.FileSettingsItem.*; + public class DuplicatesSettingsAdapter extends RecyclerView.Adapter { private static final Log LOG = PlatformUtil.getLog(DuplicatesSettingsAdapter.class.getName()); @@ -75,12 +78,11 @@ public class DuplicatesSettingsAdapter extends RecyclerView.Adapter trackFilesList = new ArrayList<>(); List avoidRoads = new ArrayList<>(); List favoriteGroups = new ArrayList<>(); + List osmNotesPointList = new ArrayList<>(); + List osmEditsPointList = new ArrayList<>(); + List ttsVoiceFilesList = new ArrayList<>(); + List voiceFilesList = new ArrayList<>(); + List mapFilesList = new ArrayList<>(); for (Object object : duplicatesList) { if (object instanceof ApplicationMode.ApplicationModeBean) { @@ -208,19 +212,30 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment { tileSources.add((ITileSource) object); } else if (object instanceof File) { File file = (File) object; - if (file.getAbsolutePath().contains(RENDERERS_DIR)) { + FileSubtype fileSubtype = FileSubtype.getSubtypeByPath(app, file.getPath()); + if (fileSubtype == FileSubtype.RENDERING_STYLE) { renderFilesList.add(file); - } else if (file.getAbsolutePath().contains(ROUTING_PROFILES_DIR)) { + } else if (fileSubtype == FileSubtype.ROUTING_CONFIG) { routingFilesList.add(file); - } else if (file.getAbsolutePath().contains(AV_INDEX_DIR)) { + } else if (fileSubtype == FileSubtype.MULTIMEDIA_NOTES) { multimediaFilesList.add(file); - } else if (file.getAbsolutePath().contains(GPX_INDEX_DIR)) { + } else if (fileSubtype == FileSubtype.GPX) { trackFilesList.add(file); + } else if (fileSubtype.isMap()) { + mapFilesList.add(file); + } else if (fileSubtype == FileSubtype.TTS_VOICE) { + ttsVoiceFilesList.add(file); + } else if (fileSubtype == FileSubtype.VOICE) { + voiceFilesList.add(file); } } else if (object instanceof AvoidRoadInfo) { avoidRoads.add((AvoidRoadInfo) object); } else if (object instanceof FavoriteGroup) { favoriteGroups.add((FavoriteGroup) object); + } else if (object instanceof OsmNotesPoint) { + osmNotesPointList.add((OsmNotesPoint) object); + } else if (object instanceof OpenstreetmapPoint) { + osmEditsPointList.add((OpenstreetmapPoint) object); } } if (!profiles.isEmpty()) { @@ -263,6 +278,26 @@ public class ImportDuplicatesFragment extends BaseOsmAndFragment { duplicates.add(getString(R.string.shared_string_favorites)); duplicates.addAll(favoriteGroups); } + if (!osmNotesPointList.isEmpty()) { + duplicates.add(getString(R.string.osm_notes)); + duplicates.addAll(osmNotesPointList); + } + if (!osmEditsPointList.isEmpty()) { + duplicates.add(getString(R.string.osm_edits)); + duplicates.addAll(osmEditsPointList); + } + if (!mapFilesList.isEmpty()) { + duplicates.add(getString(R.string.shared_string_maps)); + duplicates.addAll(mapFilesList); + } + if (!ttsVoiceFilesList.isEmpty()) { + duplicates.add(getString(R.string.local_indexes_cat_tts)); + duplicates.addAll(ttsVoiceFilesList); + } + if (!voiceFilesList.isEmpty()) { + duplicates.add(getString(R.string.local_indexes_cat_voice)); + duplicates.addAll(voiceFilesList); + } return duplicates; } From 258410823c1842d6e1ade5b0316f4a8c09c01380 Mon Sep 17 00:00:00 2001 From: iman Date: Tue, 3 Nov 2020 20:49:34 +0000 Subject: [PATCH 08/34] Translated using Weblate (Persian) Currently translated at 36.2% (1389 of 3830 strings) --- OsmAnd/res/values-fa/phrases.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/OsmAnd/res/values-fa/phrases.xml b/OsmAnd/res/values-fa/phrases.xml index dd6c374db3..28eb63e08b 100644 --- a/OsmAnd/res/values-fa/phrases.xml +++ b/OsmAnd/res/values-fa/phrases.xml @@ -226,14 +226,14 @@ صندوق بازنشستگی سازمان مهاجرت اداره مالیات - دفتر اجرایی + اداره حکومتی گمرک شهر شهر روستا دهکده سکونتگاه دورافتاده - حومه شهر + منطقه شهری محله محل @@ -346,7 +346,7 @@ اثر هنری مرکز باستان شناسی میدان جنگ - سنگ یادبود + سنگ مرز توپ تاریخی قلعه دروازه شهر @@ -1452,4 +1452,5 @@ دسترسی اتوبوس بله منطقهٔ حفاظت‌شده + بدمینتون \ No newline at end of file From 4a327a983478595c1ca1b3a2d24e76080a14ce4b Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Wed, 4 Nov 2020 15:36:44 +0100 Subject: [PATCH 09/34] Clean up gradle tasks / formatting --- .../src/main/java/net/osmand/TspAnt.java | 8 +++++--- OsmAnd/build.gradle | 20 +++---------------- .../builders/cards/ImageCard.java | 2 +- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/TspAnt.java b/OsmAnd-java/src/main/java/net/osmand/TspAnt.java index 815bddb7ef..6964a3facd 100644 --- a/OsmAnd-java/src/main/java/net/osmand/TspAnt.java +++ b/OsmAnd-java/src/main/java/net/osmand/TspAnt.java @@ -106,9 +106,11 @@ public class TspAnt { // Allocates all memory. // Adds 1 to edge lengths to ensure no zero length edges. public TspAnt readGraph(List intermediates, LatLon start, LatLon end) { - boolean keepEndPoint = end != null; - List l = new ArrayList(); - l.add(start); + boolean keepEndPoint = end != null; + List l = new ArrayList(); + if (start != null) { + l.add(start); + } l.addAll(intermediates); if (keepEndPoint) { l.add(end); diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle index 3638a103ca..ea1b4ef294 100644 --- a/OsmAnd/build.gradle +++ b/OsmAnd/build.gradle @@ -188,38 +188,24 @@ android { dimension "version" applicationId "net.osmand" } - freeres { - dimension "version" - applicationId "net.osmand" - resConfig "en" - } - freecustom { - dimension "version" - applicationId "net.osmand.freecustom" - } full { dimension "version" applicationId "net.osmand.plus" } - fulldev { - dimension "version" - applicationId "net.osmand.plus" - resConfig "en" - // resConfigs "xxhdpi", "nodpi" - } freehuawei { dimension "version" applicationId "net.osmand.huawei" } // CoreVersion + // Build that doesn't include 3D OpenGL legacy { dimension "coreversion" } - + // Build that includes 3D OpenGL release qtcore { dimension "coreversion" } - + // Build that includes 3D OpenGL debug qtcoredebug { dimension "coreversion" } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ImageCard.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ImageCard.java index c3da090ef9..26c81f03a7 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ImageCard.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ImageCard.java @@ -495,7 +495,7 @@ public abstract class ImageCard extends AbstractCard { } } } catch (Exception e) { - e.printStackTrace(); + LOG.error(e); } if (listener != null) { listener.onPostProcess(result); From 11d997f55bac169ee14e370372cca7ed8d04f960 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Wed, 4 Nov 2020 15:48:32 +0100 Subject: [PATCH 10/34] Clean up gradle tasks / formatting --- OsmAnd/AndroidManifest-freecustom.xml | 25 ------------------------- OsmAnd/build.gradle | 4 ---- 2 files changed, 29 deletions(-) delete mode 100644 OsmAnd/AndroidManifest-freecustom.xml diff --git a/OsmAnd/AndroidManifest-freecustom.xml b/OsmAnd/AndroidManifest-freecustom.xml deleted file mode 100644 index 66ced1602a..0000000000 --- a/OsmAnd/AndroidManifest-freecustom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle index ea1b4ef294..8272b7aab5 100644 --- a/OsmAnd/build.gradle +++ b/OsmAnd/build.gradle @@ -130,10 +130,6 @@ android { java.srcDirs = ["src-google"] manifest.srcFile "AndroidManifest-freedev.xml" } - freecustom { - java.srcDirs = ["src-google"] - manifest.srcFile "AndroidManifest-freecustom.xml" - } freehuawei { java.srcDirs = ["src-huawei"] manifest.srcFile "AndroidManifest-freehuawei.xml" From eb760bf9532396a5b1d6d71663eb753812338ab3 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Wed, 4 Nov 2020 15:49:48 +0100 Subject: [PATCH 11/34] Clean up gradle tasks / formatting --- OsmAnd/build.gradle | 8 -------- 1 file changed, 8 deletions(-) diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle index 8272b7aab5..79a71bb781 100644 --- a/OsmAnd/build.gradle +++ b/OsmAnd/build.gradle @@ -119,22 +119,14 @@ android { full { java.srcDirs = ["src-google"] } - fulldev { - java.srcDirs = ["src-google"] - } free { java.srcDirs = ["src-google"] manifest.srcFile "AndroidManifest-free.xml" } - freedev { - java.srcDirs = ["src-google"] - manifest.srcFile "AndroidManifest-freedev.xml" - } freehuawei { java.srcDirs = ["src-huawei"] manifest.srcFile "AndroidManifest-freehuawei.xml" } - legacy { jniLibs.srcDirs = ["libc++"] } From 6f540bfe8a547fa3bb7a737a40bac41488ab4f06 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Wed, 4 Nov 2020 15:50:24 +0100 Subject: [PATCH 12/34] Clean up gradle tasks / formatting --- OsmAnd/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle index 79a71bb781..9b89c97850 100644 --- a/OsmAnd/build.gradle +++ b/OsmAnd/build.gradle @@ -123,10 +123,15 @@ android { java.srcDirs = ["src-google"] manifest.srcFile "AndroidManifest-free.xml" } + freedev { + java.srcDirs = ["src-google"] + manifest.srcFile "AndroidManifest-freedev.xml" + } freehuawei { java.srcDirs = ["src-huawei"] manifest.srcFile "AndroidManifest-freehuawei.xml" } + legacy { jniLibs.srcDirs = ["libc++"] } From 312027db3c90a4f013a1fffd42cd9e63ea7add33 Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Wed, 4 Nov 2020 22:29:21 +0200 Subject: [PATCH 13/34] Add export progress & cancel --- .../backend/backup/FileSettingsItem.java | 3 +- .../backend/backup/SettingsExporter.java | 23 +++++++- .../backend/backup/SettingsHelper.java | 50 +++++++++++++--- .../fragments/ExportProfileBottomSheet.java | 57 ++++++++++++++++++- .../fragments/ProfileAppearanceFragment.java | 5 ++ 5 files changed, 124 insertions(+), 14 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java index 62cd9df7d5..fd28e05adc 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java @@ -208,7 +208,7 @@ public class FileSettingsItem extends StreamSettingsItem { } public long getSize() { - return size; + return file != null && !file.isDirectory() ? file.length() : size; } public void setSize(long size) { @@ -273,6 +273,7 @@ public class FileSettingsItem extends StreamSettingsItem { dest = renameFile(dest); } if (dest.getParentFile() != null && !dest.getParentFile().exists()) { + //noinspection ResultOfMethodCallIgnored dest.getParentFile().mkdirs(); } output = new FileOutputStream(dest); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java index 5b27f2afb4..e97a109561 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java @@ -21,6 +21,7 @@ class SettingsExporter { private Map items; private Map additionalParams; private boolean exportItemsFiles; + private boolean exportCancel; SettingsExporter(boolean exportItemsFiles) { this.exportItemsFiles = exportItemsFiles; @@ -35,11 +36,15 @@ class SettingsExporter { items.put(item.getName(), item); } + public void setExportCancel(boolean exportCancel) { + this.exportCancel = exportCancel; + } + void addAdditionalParam(String key, String value) { additionalParams.put(key, value); } - void exportSettings(File file) throws JSONException, IOException { + void exportSettings(File file, SettingsHelper.ExportProgress exportProgress) throws JSONException, IOException { JSONObject json = createItemsJson(); OutputStream os = new BufferedOutputStream(new FileOutputStream(file), SettingsHelper.BUFFER); ZipOutputStream zos = new ZipOutputStream(os); @@ -49,7 +54,7 @@ class SettingsExporter { zos.write(json.toString(2).getBytes("UTF-8")); zos.closeEntry(); if (exportItemsFiles) { - writeItemFiles(zos); + writeItemFiles(zos, exportProgress); } zos.flush(); zos.finish(); @@ -59,7 +64,8 @@ class SettingsExporter { } } - private void writeItemFiles(ZipOutputStream zos) throws IOException { + private void writeItemFiles(ZipOutputStream zos, SettingsHelper.ExportProgress exportProgress) throws IOException { + int progress = 0; for (SettingsItem item : items.values()) { SettingsItemWriter writer = item.getWriter(); if (writer != null) { @@ -69,6 +75,17 @@ class SettingsExporter { } writer.writeEntry(fileName, zos); } + if (exportCancel) { + exportCancel = false; + return; + } + if (item instanceof FileSettingsItem) { + int size = (int) ((FileSettingsItem) item).getSize() / 1000000; + progress += size; + if (exportProgress != null) { + exportProgress.setProgress(progress); + } + } } } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java index 469e9ebde0..09389bcefa 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -111,6 +111,8 @@ public class SettingsHelper { public interface SettingsExportListener { void onSettingsExportFinished(@NonNull File file, boolean succeed); + + void onSettingsExportProgressUpdate(int value); } public enum ImportType { @@ -139,6 +141,10 @@ public class SettingsHelper { return importTask == null || importTask.isImportDone(); } + public ExportAsyncTask getExportAsyncTask(File file) { + return exportAsyncTasks.get(file); + } + public boolean isFileExporting(File file) { return exportAsyncTasks.containsKey(file); } @@ -200,28 +206,41 @@ public class SettingsHelper { } } - @SuppressLint("StaticFieldLeak") - private class ExportAsyncTask extends AsyncTask { + public interface ExportProgress { + void setProgress(int value); + } - private SettingsExporter exporter; - private File file; + @SuppressLint("StaticFieldLeak") + public class ExportAsyncTask extends AsyncTask { + + private final SettingsExporter exporter; + private final File file; private SettingsExportListener listener; + private final ExportProgress exportProgress; + ExportAsyncTask(@NonNull File settingsFile, - @Nullable SettingsExportListener listener, - @NonNull List items, boolean exportItemsFiles) { + @Nullable SettingsExportListener listener, + @NonNull List items, boolean exportItemsFiles) { this.file = settingsFile; this.listener = listener; this.exporter = new SettingsExporter(exportItemsFiles); for (SettingsItem item : items) { exporter.addSettingsItem(item); } + exportProgress = new ExportProgress() { + @Override + public void setProgress(int value) { + exporter.setExportCancel(isCancelled()); + publishProgress(value); + } + }; } @Override protected Boolean doInBackground(Void... voids) { try { - exporter.exportSettings(file); + exporter.exportSettings(file, exportProgress); return true; } catch (JSONException e) { LOG.error("Failed to export items to: " + file.getName(), e); @@ -231,6 +250,14 @@ public class SettingsHelper { return false; } + @Override + protected void onProgressUpdate(Integer... values) { + super.onProgressUpdate(values); + if (listener != null) { + listener.onSettingsExportProgressUpdate(values[0]); + } + } + @Override protected void onPostExecute(Boolean success) { exportAsyncTasks.remove(file); @@ -238,6 +265,13 @@ public class SettingsHelper { listener.onSettingsExportFinished(file, success); } } + + @Override + protected void onCancelled() { + super.onCancelled(); + //noinspection ResultOfMethodCallIgnored + file.delete(); + } } @SuppressLint("StaticFieldLeak") @@ -416,6 +450,8 @@ public class SettingsHelper { public void exportSettings(@NonNull File fileDir, @NonNull String fileName, @Nullable SettingsExportListener listener, @NonNull List items, boolean exportItemsFiles) { File file = new File(fileDir, fileName + OSMAND_SETTINGS_FILE_EXT); ExportAsyncTask exportAsyncTask = new ExportAsyncTask(file, listener, items, exportItemsFiles); + + exportAsyncTasks.put(file, exportAsyncTask); exportAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java index 0d621b6b50..2657e58d2a 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java @@ -2,6 +2,7 @@ package net.osmand.plus.settings.fragments; import android.app.ProgressDialog; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.res.ColorStateList; import android.graphics.drawable.ColorDrawable; @@ -33,6 +34,7 @@ import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ExportSettingsType; +import net.osmand.plus.settings.backend.backup.FileSettingsItem; import net.osmand.plus.settings.backend.backup.GlobalSettingsItem; import net.osmand.plus.settings.backend.backup.ProfileSettingsItem; import net.osmand.plus.settings.backend.backup.SettingsHelper.SettingsExportListener; @@ -47,6 +49,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { @@ -60,8 +63,10 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { private static final String EXPORTING_PROFILE_KEY = "exporting_profile_key"; private static final String INCLUDE_ADDITIONAL_DATA_KEY = "include_additional_data_key"; private static final String INCLUDE_GLOBAL_SETTINGS_KEY = "include_global_settings_key"; + private static final String PROGRESS_MAX_KEY = "progress_max_key"; + private static final String PROGRESS_VALUE_KEY = "progress_value_key"; - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yy"); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yy", Locale.US); private OsmandApplication app; private Map> dataList = new HashMap<>(); @@ -69,6 +74,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { private SettingsExportListener exportListener; private ProgressDialog progress; + int progressMax; + int progressValue; private long exportStartTime; @@ -87,6 +94,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { includeAdditionalData = savedInstanceState.getBoolean(INCLUDE_ADDITIONAL_DATA_KEY); includeGlobalSettings = savedInstanceState.getBoolean(INCLUDE_GLOBAL_SETTINGS_KEY); exportStartTime = savedInstanceState.getLong(EXPORT_START_TIME_KEY); + progressMax = savedInstanceState.getInt(PROGRESS_MAX_KEY); + progressValue = savedInstanceState.getInt(PROGRESS_VALUE_KEY); } dataList = app.getSettingsHelper().getAdditionalData(globalExport); } @@ -99,6 +108,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { outState.putBoolean(INCLUDE_ADDITIONAL_DATA_KEY, includeAdditionalData); outState.putBoolean(INCLUDE_GLOBAL_SETTINGS_KEY, includeGlobalSettings); outState.putLong(EXPORT_START_TIME_KEY, exportStartTime); + outState.putInt(PROGRESS_MAX_KEY, progress.getMax()); + outState.putInt(PROGRESS_VALUE_KEY, progress.getProgress()); } @Override @@ -271,10 +282,22 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { showExportProgressDialog(); File tempDir = FileUtils.getTempDir(app); String fileName = getFileName(); - app.getSettingsHelper().exportSettings(tempDir, fileName, getSettingsExportListener(), prepareSettingsItemsForExport(), true); + List items = prepareSettingsItemsForExport(); + progress.setMax(getMaxProgress(items)); + app.getSettingsHelper().exportSettings(tempDir, fileName, getSettingsExportListener(), items, true); } } + private int getMaxProgress(List items) { + long maxProgress = 0; + for (SettingsItem item : items) { + if (item instanceof FileSettingsItem) { + maxProgress += ((FileSettingsItem) item).getSize(); + } + } + return (int) maxProgress / 1000000; + } + private String getFileName() { if (globalExport) { if (exportStartTime == 0) { @@ -295,12 +318,33 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { progress.dismiss(); } progress = new ProgressDialog(context); + progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progress.setCancelable(true); progress.setTitle(app.getString(R.string.shared_string_export)); progress.setMessage(app.getString(R.string.shared_string_preparing)); - progress.setCancelable(false); + progress.setButton(DialogInterface.BUTTON_NEGATIVE, app.getString(R.string.shared_string_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + cancelExport(); + } + }); + progress.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + cancelExport(); + } + }); progress.show(); } + private void cancelExport() { + app.getSettingsHelper().getExportAsyncTask(getExportFile()).cancel(true); + //noinspection ResultOfMethodCallIgnored + getExportFile().delete(); + progress.dismiss(); + dismiss(); + } + private SettingsExportListener getSettingsExportListener() { if (exportListener == null) { exportListener = new SettingsExportListener() { @@ -315,6 +359,11 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { app.showToastMessage(R.string.export_profile_failed); } } + + @Override + public void onSettingsExportProgressUpdate(int value) { + progress.setProgress(value); + } }; } return exportListener; @@ -326,6 +375,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { boolean fileExporting = app.getSettingsHelper().isFileExporting(file); if (fileExporting) { showExportProgressDialog(); + progress.setMax(progressMax); + progress.setProgress(progressValue); app.getSettingsHelper().updateExportListener(file, getSettingsExportListener()); } else if (file.exists()) { dismissExportProgressDialog(); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java index 1bdbc38b19..bc3092d963 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java @@ -735,6 +735,11 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment { app.showToastMessage(R.string.profile_backup_failed); } } + + @Override + public void onSettingsExportProgressUpdate(int value) { + + } }; } return exportListener; From beddaf82090a381b8ac244a18df90aee2399e94b Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Thu, 5 Nov 2020 01:02:16 +0200 Subject: [PATCH 14/34] Fix chart on map --- .../other/TrackDetailsMenu.java | 11 ++++-- .../plus/measurementtool/GraphsCard.java | 21 +++++++++- .../MeasurementToolFragment.java | 13 ++++++- .../plus/measurementtool/PointsCard.java | 4 +- .../graph/GraphAdapterHelper.java | 38 +++++++++++-------- .../RouteDetailsFragment.java | 11 ++---- .../osmand/plus/views/layers/RouteLayer.java | 16 +++++++- 7 files changed, 82 insertions(+), 32 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java index 1e441071a4..a45bfb27e8 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java @@ -125,8 +125,7 @@ public class TrackDetailsMenu { hidding = true; fragment.dismiss(backPressed); } else { - segment = null; - trackChartPoints = null; + reset(); } } @@ -274,8 +273,7 @@ public class TrackDetailsMenu { if (hidding) { hidding = false; visible = false; - segment = null; - trackChartPoints = null; + reset(); } } @@ -532,6 +530,11 @@ public class TrackDetailsMenu { fitTrackOnMap(chart, location, forceFit); } + public void reset() { + segment = null; + trackChartPoints = null; + } + private List getXAxisPoints(LineChart chart) { float[] entries = chart.getXAxis().mEntries; LineData lineData = chart.getLineData(); diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java index 69277f19a6..3b2e979f55 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java @@ -34,6 +34,7 @@ import net.osmand.plus.measurementtool.graph.CustomGraphAdapter; import net.osmand.plus.measurementtool.graph.CustomGraphAdapter.LegendViewType; import net.osmand.plus.measurementtool.graph.BaseGraphAdapter; import net.osmand.plus.measurementtool.graph.GraphAdapterHelper; +import net.osmand.plus.measurementtool.graph.GraphAdapterHelper.RefreshMapCallback; import net.osmand.plus.routepreparationmenu.RouteDetailsFragment; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.router.RouteSegmentResult; @@ -59,6 +60,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private MeasurementEditingContext editingCtx; private MeasurementToolFragment fragment; private TrackDetailsMenu trackDetailsMenu; + private RefreshMapCallback refreshMapCallback; private GPXFile gpxFile; private GPXTrackAnalysis analysis; private GpxDisplayItem gpxItem; @@ -105,7 +107,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen }); GraphAdapterHelper.bindGraphAdapters(commonGraphAdapter, Arrays.asList((BaseGraphAdapter) customGraphAdapter), (ViewGroup) view); - GraphAdapterHelper.bindToMap(commonGraphAdapter, mapActivity, trackDetailsMenu); + refreshMapCallback = GraphAdapterHelper.bindToMap(commonGraphAdapter, mapActivity, trackDetailsMenu); fullUpdate(); } @@ -116,7 +118,9 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen @Override public void onUpdateAdditionalInfo() { - fullUpdate(); + if (editingCtx != null) { + fullUpdate(); + } } private void fullUpdate() { @@ -126,6 +130,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen updateMenu(); } updateView(); + updateChartOnMap(); } private void updateMenu() { @@ -302,6 +307,13 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen } } + private void updateChartOnMap() { + if (hasVisibleGraph()) { + trackDetailsMenu.reset(); + refreshMapCallback.refreshMap(false); + } + } + private void addCommonType(int titleId, boolean canBeCalculated, boolean hasData, @@ -346,6 +358,11 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen return fragment.isProgressBarVisible(); } + public boolean hasVisibleGraph() { + return (commonGraphContainer != null && commonGraphContainer.getVisibility() == View.VISIBLE) + || (customGraphContainer != null && customGraphContainer.getVisibility() == View.VISIBLE); + } + private abstract class GraphType { private String title; private boolean canBeCalculated; diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java index c92d028f02..16c8e2309c 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolFragment.java @@ -553,8 +553,13 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route } private void updateAdditionalInfoView() { - if (visibleCard instanceof OnUpdateAdditionalInfoListener) { - ((OnUpdateAdditionalInfoListener) visibleCard).onUpdateAdditionalInfo(); + updateAdditionalInfoView(pointsCard); + updateAdditionalInfoView(graphsCard); + } + + private void updateAdditionalInfoView(OnUpdateAdditionalInfoListener listener) { + if (listener != null) { + listener.onUpdateAdditionalInfo(); } } @@ -1514,6 +1519,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route return type.equals(currentAdditionalInfoType); } + public boolean hasVisibleGraph() { + return graphsCard != null && graphsCard.hasVisibleGraph(); + } + private String getSuggestedFileName() { GpxData gpxData = editingCtx.getGpxData(); String displayedName = null; diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java index 9d14598856..f3b55473bc 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/PointsCard.java @@ -24,7 +24,9 @@ public class PointsCard extends BaseCard implements OnUpdateAdditionalInfoListen @Override public void onUpdateAdditionalInfo() { - adapter.notifyDataSetChanged(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } } @Override diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java index efacad9d50..69eb02eec7 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/GraphAdapterHelper.java @@ -5,6 +5,8 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; + import com.github.mikephil.charting.charts.BarChart; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.data.Entry; @@ -96,15 +98,27 @@ public class GraphAdapterHelper { } } - public static void bindToMap(final CommonGraphAdapter graphAdapter, - final MapActivity mapActivity, - final TrackDetailsMenu detailsMenu) { + public static RefreshMapCallback bindToMap(@NonNull final CommonGraphAdapter graphAdapter, + @NonNull final MapActivity mapActivity, + @NonNull final TrackDetailsMenu detailsMenu) { + final RefreshMapCallback refreshMapCallback = new RefreshMapCallback() { + @Override + public void refreshMap(boolean forceFit) { + LineChart chart = graphAdapter.getChart(); + OsmandApplication app = mapActivity.getMyApplication(); + if (!app.getRoutingHelper().isFollowingMode()) { + detailsMenu.refreshChart(chart, forceFit); + mapActivity.refreshMap(); + } + } + }; + graphAdapter.addValueSelectedListener(BIND_TO_MAP_KEY, new CommonGraphAdapter.ExternalValueSelectedListener() { @Override public void onValueSelected(Entry e, Highlight h) { - refreshChart(mapActivity, graphAdapter.getChart(), detailsMenu, false); + refreshMapCallback.refreshMap(false); } @Override @@ -125,21 +139,15 @@ public class GraphAdapterHelper { lastPerformedGesture == ChartTouchListener.ChartGesture.PINCH_ZOOM || lastPerformedGesture == ChartTouchListener.ChartGesture.DOUBLE_TAP || lastPerformedGesture == ChartTouchListener.ChartGesture.ROTATE) { - refreshChart(mapActivity, graphAdapter.getChart(), detailsMenu, true); + refreshMapCallback.refreshMap(true); } } }); + + return refreshMapCallback; } - public static void refreshChart(MapActivity mapActivity, - LineChart chart, - TrackDetailsMenu menu, - boolean forceFit) { - if (mapActivity == null || chart == null || menu == null) return; - OsmandApplication app = mapActivity.getMyApplication(); - if (!app.getRoutingHelper().isFollowingMode()) { - menu.refreshChart(chart, forceFit); - mapActivity.refreshMap(); - } + public interface RefreshMapCallback { + void refreshMap(boolean forceFit); } } diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java index c6dcac20a6..780186b068 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/RouteDetailsFragment.java @@ -60,6 +60,7 @@ import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; import net.osmand.plus.measurementtool.graph.BaseGraphAdapter; import net.osmand.plus.measurementtool.graph.CommonGraphAdapter; import net.osmand.plus.measurementtool.graph.GraphAdapterHelper; +import net.osmand.plus.measurementtool.graph.GraphAdapterHelper.RefreshMapCallback; import net.osmand.plus.render.MapRenderRepositories; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener; @@ -113,6 +114,7 @@ public class RouteDetailsFragment extends ContextMenuFragment private RouteStatisticCard statisticCard; private List routeInfoCards = new ArrayList<>(); private RouteDetailsMenu routeDetailsMenu; + private RefreshMapCallback refreshMapCallback; public interface RouteDetailsFragmentListener { void onNavigationRequested(); @@ -336,7 +338,7 @@ public class RouteDetailsFragment extends ContextMenuFragment CommonGraphAdapter mainGraphAdapter = statisticCard.getGraphAdapter(); if (mainGraphAdapter != null) { GraphAdapterHelper.bindGraphAdapters(mainGraphAdapter, getRouteInfoCardsGraphAdapters(), getMainView()); - GraphAdapterHelper.bindToMap(mainGraphAdapter, mapActivity, routeDetailsMenu); + refreshMapCallback = GraphAdapterHelper.bindToMap(mainGraphAdapter, mapActivity, routeDetailsMenu); } } @@ -369,12 +371,7 @@ public class RouteDetailsFragment extends ContextMenuFragment protected void calculateLayout(View view, boolean initLayout) { super.calculateLayout(view, initLayout); if (!initLayout && getCurrentMenuState() != MenuState.FULL_SCREEN) { - MapActivity mapActivity = getMapActivity(); - CommonGraphAdapter mainGraphAdapter = statisticCard.getGraphAdapter(); - if (mainGraphAdapter != null) { - LineChart chart = mainGraphAdapter.getChart(); - GraphAdapterHelper.refreshChart(mapActivity, chart, routeDetailsMenu, false); - } + refreshMapCallback.refreshMap(false); } } diff --git a/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java index 8491f24a67..f966b7d897 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java @@ -26,7 +26,9 @@ import net.osmand.data.QuadRect; import net.osmand.data.RotatedTileBox; import net.osmand.data.TransportStop; import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; import net.osmand.plus.mapcontextmenu.other.TrackChartPoints; +import net.osmand.plus.measurementtool.MeasurementToolFragment; import net.osmand.plus.profiles.LocationIcon; import net.osmand.plus.routing.RouteCalculationResult; import net.osmand.plus.routing.RouteDirectionInfo; @@ -158,7 +160,8 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont @Override public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { if ((helper.isPublicTransportMode() && transportHelper.getRoutes() != null) || - (helper.getFinalLocation() != null && helper.getRoute().isCalculated())) { + (helper.getFinalLocation() != null && helper.getRoute().isCalculated()) || + isPlanRouteGraphsAvailable()) { updateAttrs(settings, tileBox); @@ -202,6 +205,17 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont } + private boolean isPlanRouteGraphsAvailable() { + if (view.getContext() instanceof MapActivity) { + MapActivity mapActivity = (MapActivity) view.getContext(); + MeasurementToolFragment fragment = mapActivity.getMeasurementToolFragment(); + if (fragment != null) { + return fragment.hasVisibleGraph(); + } + } + return false; + } + private void updateAttrs(DrawSettings settings, RotatedTileBox tileBox) { boolean updatePaints = attrs.updatePaints(view.getApplication(), settings, tileBox); attrs.isPaint3 = false; From bd45e5aba8464835fdacc69c7b10d1b8e3e62a79 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Thu, 5 Nov 2020 01:37:05 +0200 Subject: [PATCH 15/34] Show only two graphs on chart, refactor getDataSets --- .../net/osmand/plus/helpers/GpxUiHelper.java | 66 +++++++------------ .../plus/measurementtool/GraphsCard.java | 22 ++++--- .../plus/myplaces/TrackSegmentFragment.java | 10 +-- 3 files changed, 43 insertions(+), 55 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java index dd2a35a9a4..2b91e0a6b7 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java @@ -2056,52 +2056,34 @@ public class GpxUiHelper { public static List getDataSets(LineChart chart, OsmandApplication app, GPXTrackAnalysis analysis, - boolean calcWithoutGaps, - LineGraphType ... types) { - if (app == null || chart == null || analysis == null || types == null) { + @NonNull LineGraphType firstType, + @Nullable LineGraphType secondType, + boolean calcWithoutGaps) { + if (app == null || chart == null || analysis == null) { return new ArrayList<>(); } - if (types.length > 1) { - return getDataSetsImpl(chart, app, analysis, calcWithoutGaps, types[0], types[1]); - } else { - return getDataSetsImpl(chart, app, analysis, calcWithoutGaps, types[0]); - } - } - - private static List getDataSetsImpl(@NonNull LineChart chart, - @NonNull OsmandApplication app, - @NonNull GPXTrackAnalysis analysis, - boolean calcWithoutGaps, - @NonNull LineGraphType type) { List result = new ArrayList<>(); - ILineDataSet dataSet = getDataSet(chart, app, analysis, calcWithoutGaps, false, type); - if (dataSet != null) { - result.add(dataSet); - } - return result; - } - - private static List getDataSetsImpl(@NonNull LineChart chart, - @NonNull OsmandApplication app, - @NonNull GPXTrackAnalysis analysis, - boolean calcWithoutGaps, - @NonNull LineGraphType type1, - @NonNull LineGraphType type2) { - List result = new ArrayList<>(); - OrderedLineDataSet dataSet1 = getDataSet(chart, app, analysis, calcWithoutGaps, false, type1); - OrderedLineDataSet dataSet2 = getDataSet(chart, app, analysis, calcWithoutGaps, true, type2); - if (dataSet1 == null && dataSet2 == null) { - return new ArrayList<>(); - } else if (dataSet1 == null) { - result.add(dataSet2); - } else if (dataSet2 == null) { - result.add(dataSet1); - } else if (dataSet1.getPriority() < dataSet2.getPriority()) { - result.add(dataSet2); - result.add(dataSet1); + if (secondType == null) { + ILineDataSet dataSet = getDataSet(chart, app, analysis, calcWithoutGaps, false, firstType); + if (dataSet != null) { + result.add(dataSet); + } } else { - result.add(dataSet1); - result.add(dataSet2); + OrderedLineDataSet dataSet1 = getDataSet(chart, app, analysis, calcWithoutGaps, false, firstType); + OrderedLineDataSet dataSet2 = getDataSet(chart, app, analysis, calcWithoutGaps, true, secondType); + if (dataSet1 == null && dataSet2 == null) { + return new ArrayList<>(); + } else if (dataSet1 == null) { + result.add(dataSet2); + } else if (dataSet2 == null) { + result.add(dataSet1); + } else if (dataSet1.getPriority() < dataSet2.getPriority()) { + result.add(dataSet2); + result.add(dataSet1); + } else { + result.add(dataSet1); + result.add(dataSet2); + } } return result; } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java index 3b2e979f55..9a64d77433 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java @@ -8,6 +8,7 @@ import android.widget.TextView; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -293,9 +294,9 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen boolean hasElevationData = analysis.hasElevationData; boolean hasSpeedData = analysis.isSpeedSpecified(); addCommonType(R.string.shared_string_overview, true, hasElevationData, ALTITUDE, SLOPE); - addCommonType(R.string.altitude, true, hasElevationData, ALTITUDE); - addCommonType(R.string.shared_string_slope, true, hasElevationData, SLOPE); - addCommonType(R.string.map_widget_speed, false, hasSpeedData, SPEED); + addCommonType(R.string.altitude, true, hasElevationData, ALTITUDE, null); + addCommonType(R.string.shared_string_slope, true, hasElevationData, SLOPE, null); + addCommonType(R.string.map_widget_speed, false, hasSpeedData, SPEED, null); // update custom graph data List routeStatistics = calculateRouteStatistics(); @@ -317,10 +318,11 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private void addCommonType(int titleId, boolean canBeCalculated, boolean hasData, - LineGraphType ... lineGraphTypes) { + LineGraphType firstType, + LineGraphType secondType) { OsmandApplication app = getMyApplication(); String title = app.getString(titleId); - graphTypes.add(new CommonGraphType(title, canBeCalculated, hasData, lineGraphTypes)); + graphTypes.add(new CommonGraphType(title, canBeCalculated, hasData, firstType, secondType)); } private void setupVisibleType() { @@ -400,12 +402,14 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen private class CommonGraphType extends GraphType { private boolean hasData; - private LineGraphType[] lineGraphTypes; + private LineGraphType firstType; + private LineGraphType secondType; - public CommonGraphType(String title, boolean canBeCalculated, boolean hasData, LineGraphType ... lineGraphTypes) { + public CommonGraphType(String title, boolean canBeCalculated, boolean hasData, @NonNull LineGraphType firstType, @Nullable LineGraphType secondType) { super(title, canBeCalculated); this.hasData = hasData; - this.lineGraphTypes = lineGraphTypes; + this.firstType = firstType; + this.secondType = secondType; } @Override @@ -417,7 +421,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen public LineData getChartData() { GpxUiHelper.setupGPXChart(commonGraphAdapter.getChart(), 4, 24f, 16f, !nightMode, true); List dataSets = GpxUiHelper.getDataSets(commonGraphAdapter.getChart(), - app, analysis, false, lineGraphTypes); + app, analysis, firstType, secondType, false); return !Algorithms.isEmpty(dataSets) ? new LineData(dataSets) : null; } } diff --git a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java index 7a7178c578..e53b51cf39 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java @@ -62,6 +62,7 @@ import net.osmand.plus.activities.TrackActivity; import net.osmand.plus.base.OsmAndListFragment; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.GpxUiHelper; +import net.osmand.plus.helpers.GpxUiHelper.LineGraphType; import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType; import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType; import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet; @@ -430,13 +431,14 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit private List getDataSets(LineChart chart, GPXTabItemType tabType, - GpxUiHelper.LineGraphType... types) { + LineGraphType firstType, + LineGraphType secondType) { List dataSets = dataSetsMap.get(tabType); if (dataSets == null && chart != null) { GPXTrackAnalysis analysis = gpxItem.analysis; GpxDataItem gpxDataItem = getGpxDataItem(); boolean calcWithoutGaps = gpxItem.isGeneralTrack() && gpxDataItem != null && !gpxDataItem.isJoinSegments(); - dataSets = GpxUiHelper.getDataSets(chart, app, analysis, calcWithoutGaps, types); + dataSets = GpxUiHelper.getDataSets(chart, app, analysis, firstType, secondType, calcWithoutGaps); dataSetsMap.put(tabType, dataSets); } return dataSets; @@ -878,7 +880,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit if (analysis != null && analysis.isSpeedSpecified()) { if (analysis.hasSpeedData) { GpxUiHelper.setupGPXChart(app, chart, 4); - chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_SPEED, SPEED))); + chart.setData(new LineData(getDataSets(chart, GPXTabItemType.GPX_TAB_ITEM_SPEED, SPEED, null))); updateChart(chart); chart.setVisibility(View.VISIBLE); } else { @@ -1144,7 +1146,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit LatLon location = null; WptPt wpt = null; gpxItem.chartTypes = null; - List ds = getDataSets(null, tabType); + List ds = getDataSets(null, tabType, null, null); if (ds != null && ds.size() > 0) { gpxItem.chartTypes = new GPXDataSetType[ds.size()]; for (int i = 0; i < ds.size(); i++) { From b1ddd40ec834a3bd188a0b5934c2a8b1d98ce977 Mon Sep 17 00:00:00 2001 From: nazar-kutz Date: Thu, 5 Nov 2020 02:04:25 +0200 Subject: [PATCH 16/34] small fixes --- .../src/net/osmand/plus/measurementtool/GraphsCard.java | 4 ++-- .../plus/measurementtool/graph/CustomGraphAdapter.java | 4 ++-- .../plus/measurementtool/graph/GraphAdapterHelper.java | 8 +++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java index 9a64d77433..a0f74d34db 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/GraphsCard.java @@ -42,7 +42,7 @@ import net.osmand.router.RouteSegmentResult; import net.osmand.util.Algorithms; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import static net.osmand.GPXUtilities.GPXFile; @@ -107,7 +107,7 @@ public class GraphsCard extends BaseCard implements OnUpdateAdditionalInfoListen } }); - GraphAdapterHelper.bindGraphAdapters(commonGraphAdapter, Arrays.asList((BaseGraphAdapter) customGraphAdapter), (ViewGroup) view); + GraphAdapterHelper.bindGraphAdapters(commonGraphAdapter, Collections.singletonList((BaseGraphAdapter) customGraphAdapter), (ViewGroup) view); refreshMapCallback = GraphAdapterHelper.bindToMap(commonGraphAdapter, mapActivity, trackDetailsMenu); fullUpdate(); } diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java index 72ccff4604..1bc763b165 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/graph/CustomGraphAdapter.java @@ -29,7 +29,7 @@ import net.osmand.router.RouteStatisticsHelper.RouteSegmentAttribute; import net.osmand.util.Algorithms; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import static net.osmand.plus.track.ColorsCard.MINIMUM_CONTRAST_RATIO; @@ -122,7 +122,7 @@ public class CustomGraphAdapter extends BaseGraphAdapter Date: Thu, 5 Nov 2020 13:29:59 +0200 Subject: [PATCH 17/34] Fix review --- .../backend/backup/FileSettingsItem.java | 20 +++++++++---------- .../backend/backup/SettingsExporter.java | 18 ++++++++++------- .../backend/backup/SettingsHelper.java | 16 +++++++-------- .../fragments/ExportProfileBottomSheet.java | 8 +++----- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java index fd28e05adc..dc001eb9f5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java @@ -24,14 +24,15 @@ import java.util.zip.ZipOutputStream; public class FileSettingsItem extends StreamSettingsItem { public enum FileSubtype { - UNKNOWN("", null, -1), - OTHER("other", "", -1), + UNKNOWN("", null, R.drawable.ic_type_file), + OTHER("other", "", R.drawable.ic_type_file), ROUTING_CONFIG("routing_config", IndexConstants.ROUTING_PROFILES_DIR, R.drawable.ic_action_route_distance), RENDERING_STYLE("rendering_style", IndexConstants.RENDERERS_DIR, R.drawable.ic_action_map_style), WIKI_MAP("wiki_map", IndexConstants.WIKI_INDEX_DIR, R.drawable.ic_plugin_wikipedia), SRTM_MAP("srtm_map", IndexConstants.SRTM_INDEX_DIR, R.drawable.ic_plugin_srtm), OBF_MAP("obf_map", IndexConstants.MAPS_PATH, R.drawable.ic_map), TILES_MAP("tiles_map", IndexConstants.TILES_INDEX_DIR, R.drawable.ic_map), + ROAD_MAP("road_map", IndexConstants.ROADS_INDEX_DIR, R.drawable.ic_map), GPX("gpx", IndexConstants.GPX_INDEX_DIR, R.drawable.ic_action_route_distance), TTS_VOICE("tts_voice", IndexConstants.VOICE_INDEX_DIR, R.drawable.ic_action_volume_up), VOICE("voice", IndexConstants.VOICE_INDEX_DIR, R.drawable.ic_action_volume_up), @@ -49,7 +50,7 @@ public class FileSettingsItem extends StreamSettingsItem { } public boolean isMap() { - return this == OBF_MAP || this == WIKI_MAP || this == SRTM_MAP || this == TILES_MAP; + return this == OBF_MAP || this == WIKI_MAP || this == SRTM_MAP || this == TILES_MAP || this == ROAD_MAP; } public String getSubtypeName() { @@ -60,6 +61,7 @@ public class FileSettingsItem extends StreamSettingsItem { return subtypeFolder; } + @DrawableRes public int getIconId() { return iconId; } @@ -208,7 +210,7 @@ public class FileSettingsItem extends StreamSettingsItem { } public long getSize() { - return file != null && !file.isDirectory() ? file.length() : size; + return size == 0 ? file != null && !file.isDirectory() ? file.length() : size : size; } public void setSize(long size) { @@ -231,23 +233,21 @@ public class FileSettingsItem extends StreamSettingsItem { } private File renameFile(File oldFile) { - int number = 0; String oldPath = oldFile.getAbsolutePath(); - String suffix; String prefix; if (file.isDirectory()) { prefix = file.getAbsolutePath(); - suffix = oldPath.replace(file.getAbsolutePath(), ""); } else if (oldPath.endsWith(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) { prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)); - suffix = IndexConstants.BINARY_WIKI_MAP_INDEX_EXT; } else if (oldPath.endsWith(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)) { prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)); - suffix = IndexConstants.BINARY_SRTM_MAP_INDEX_EXT; + } else if (oldPath.endsWith(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)) { + prefix = oldPath.substring(0, oldPath.lastIndexOf(IndexConstants.BINARY_ROAD_MAP_INDEX_EXT)); } else { prefix = oldPath.substring(0, oldPath.lastIndexOf(".")); - suffix = "." + Algorithms.getFileExtension(oldFile); } + String suffix = oldPath.replace(prefix, ""); + int number = 0; while (true) { number++; String newName = prefix + "_" + number + suffix; diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java index e97a109561..40917bd7c5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java @@ -16,15 +16,19 @@ import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import static net.osmand.plus.settings.backend.backup.SettingsHelper.*; + class SettingsExporter { private Map items; private Map additionalParams; private boolean exportItemsFiles; private boolean exportCancel; + private final ExportProgress exportProgress; - SettingsExporter(boolean exportItemsFiles) { + SettingsExporter(boolean exportItemsFiles, ExportProgress exportProgress) { this.exportItemsFiles = exportItemsFiles; + this.exportProgress = exportProgress; items = new LinkedHashMap<>(); additionalParams = new LinkedHashMap<>(); } @@ -44,9 +48,9 @@ class SettingsExporter { additionalParams.put(key, value); } - void exportSettings(File file, SettingsHelper.ExportProgress exportProgress) throws JSONException, IOException { + void exportSettings(File file) throws JSONException, IOException { JSONObject json = createItemsJson(); - OutputStream os = new BufferedOutputStream(new FileOutputStream(file), SettingsHelper.BUFFER); + OutputStream os = new BufferedOutputStream(new FileOutputStream(file), BUFFER); ZipOutputStream zos = new ZipOutputStream(os); try { ZipEntry entry = new ZipEntry("items.json"); @@ -54,7 +58,7 @@ class SettingsExporter { zos.write(json.toString(2).getBytes("UTF-8")); zos.closeEntry(); if (exportItemsFiles) { - writeItemFiles(zos, exportProgress); + writeItemFiles(zos); } zos.flush(); zos.finish(); @@ -64,7 +68,7 @@ class SettingsExporter { } } - private void writeItemFiles(ZipOutputStream zos, SettingsHelper.ExportProgress exportProgress) throws IOException { + private void writeItemFiles(ZipOutputStream zos) throws IOException { int progress = 0; for (SettingsItem item : items.values()) { SettingsItemWriter writer = item.getWriter(); @@ -80,7 +84,7 @@ class SettingsExporter { return; } if (item instanceof FileSettingsItem) { - int size = (int) ((FileSettingsItem) item).getSize() / 1000000; + int size = (int) ((FileSettingsItem) item).getSize() / (1 << 20); progress += size; if (exportProgress != null) { exportProgress.setProgress(progress); @@ -91,7 +95,7 @@ class SettingsExporter { private JSONObject createItemsJson() throws JSONException { JSONObject json = new JSONObject(); - json.put("version", SettingsHelper.VERSION); + json.put("version", VERSION); for (Map.Entry param : additionalParams.entrySet()) { json.put(param.getKey(), param.getValue()); } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java index 09389bcefa..a9b66189ad 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -216,7 +216,6 @@ public class SettingsHelper { private final SettingsExporter exporter; private final File file; private SettingsExportListener listener; - private final ExportProgress exportProgress; ExportAsyncTask(@NonNull File settingsFile, @@ -224,23 +223,23 @@ public class SettingsHelper { @NonNull List items, boolean exportItemsFiles) { this.file = settingsFile; this.listener = listener; - this.exporter = new SettingsExporter(exportItemsFiles); - for (SettingsItem item : items) { - exporter.addSettingsItem(item); - } - exportProgress = new ExportProgress() { + ExportProgress exportProgress = new ExportProgress() { @Override public void setProgress(int value) { exporter.setExportCancel(isCancelled()); publishProgress(value); } }; + this.exporter = new SettingsExporter(exportItemsFiles, exportProgress); + for (SettingsItem item : items) { + exporter.addSettingsItem(item); + } } @Override protected Boolean doInBackground(Void... voids) { try { - exporter.exportSettings(file, exportProgress); + exporter.exportSettings(file); return true; } catch (JSONException e) { LOG.error("Failed to export items to: " + file.getName(), e); @@ -252,7 +251,6 @@ public class SettingsHelper { @Override protected void onProgressUpdate(Integer... values) { - super.onProgressUpdate(values); if (listener != null) { listener.onSettingsExportProgressUpdate(values[0]); } @@ -843,7 +841,7 @@ public class SettingsHelper { return settingsToOperate; } - public void sortData(List files) { + private void sortData(List files) { final Collator collator = OsmAndCollator.primaryCollator(); Collections.sort(files, new Comparator() { @Override diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java index 2657e58d2a..ba1d630bef 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java @@ -74,8 +74,8 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { private SettingsExportListener exportListener; private ProgressDialog progress; - int progressMax; - int progressValue; + private int progressMax; + private int progressValue; private long exportStartTime; @@ -295,7 +295,7 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { maxProgress += ((FileSettingsItem) item).getSize(); } } - return (int) maxProgress / 1000000; + return (int) maxProgress / (1 << 20); } private String getFileName() { @@ -339,8 +339,6 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { private void cancelExport() { app.getSettingsHelper().getExportAsyncTask(getExportFile()).cancel(true); - //noinspection ResultOfMethodCallIgnored - getExportFile().delete(); progress.dismiss(); dismiss(); } From 46ffc11ce3138417be2310afb8c55401850f007c Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 5 Nov 2020 16:43:39 +0200 Subject: [PATCH 18/34] Added icons for location permission dialog --- .../drawable/ic_action_device_location.xml | 30 +++++++++++++++++++ .../ic_action_device_location_colored.xml | 30 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 OsmAnd/res/drawable/ic_action_device_location.xml create mode 100644 OsmAnd/res/drawable/ic_action_device_location_colored.xml diff --git a/OsmAnd/res/drawable/ic_action_device_location.xml b/OsmAnd/res/drawable/ic_action_device_location.xml new file mode 100644 index 0000000000..c804224052 --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_device_location.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/OsmAnd/res/drawable/ic_action_device_location_colored.xml b/OsmAnd/res/drawable/ic_action_device_location_colored.xml new file mode 100644 index 0000000000..2bceb2d67e --- /dev/null +++ b/OsmAnd/res/drawable/ic_action_device_location_colored.xml @@ -0,0 +1,30 @@ + + + + + + + + + From f5cf80818e8b68c64fcb95da46ecc9bf6c7b4942 Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Thu, 5 Nov 2020 18:18:58 +0200 Subject: [PATCH 19/34] Fix hillshade names --- OsmAnd/src/net/osmand/plus/download/IndexItem.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/download/IndexItem.java b/OsmAnd/src/net/osmand/plus/download/IndexItem.java index 7173dfca66..650ab0679b 100644 --- a/OsmAnd/src/net/osmand/plus/download/IndexItem.java +++ b/OsmAnd/src/net/osmand/plus/download/IndexItem.java @@ -143,9 +143,9 @@ public class IndexItem implements Comparable { public String getTranslatedBasename() { if (type == DownloadActivityType.HILLSHADE_FILE) { - return (FileNameTranslationHelper.HILL_SHADE + getBasename()).replace("_", " "); + return (FileNameTranslationHelper.HILL_SHADE + "_" + getBasename()).replace("_", " "); } else if (type == DownloadActivityType.SLOPE_FILE) { - return (FileNameTranslationHelper.SLOPE + getBasename()).replace('_', ' '); + return (FileNameTranslationHelper.SLOPE + "_" + getBasename()).replace('_', ' '); } else { return getBasename(); } From 1b3247780ad2cd0119f09c89537a8f8138806481 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Thu, 5 Nov 2020 18:38:52 +0200 Subject: [PATCH 20/34] Small clean up --- .../backend/backup/FileSettingsItem.java | 39 ++++++++------ .../backend/backup/SettingsExporter.java | 22 ++++---- .../backend/backup/SettingsHelper.java | 53 ++++++++++--------- .../fragments/ExportProfileBottomSheet.java | 2 +- 4 files changed, 62 insertions(+), 54 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java index dc001eb9f5..563a04fc75 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/FileSettingsItem.java @@ -210,7 +210,12 @@ public class FileSettingsItem extends StreamSettingsItem { } public long getSize() { - return size == 0 ? file != null && !file.isDirectory() ? file.length() : size : size; + if (size != 0) { + return size; + } else if (file != null && !file.isDirectory()) { + return file.length(); + } + return 0; } public void setSize(long size) { @@ -307,26 +312,26 @@ public class FileSettingsItem extends StreamSettingsItem { @Override public void writeEntry(String fileName, @NonNull ZipOutputStream zos) throws IOException { - zipDirsWithFiles(file, zos); + writeDirWithFiles(file, zos); } - public void zipDirsWithFiles(File file, ZipOutputStream zos) throws IOException { - if (file == null) { - return; - } - if (file.isDirectory()) { - File[] fs = file.listFiles(); - if (fs != null) { - for (File c : fs) { - zipDirsWithFiles(c, zos); + public void writeDirWithFiles(File file, ZipOutputStream zos) throws IOException { + if (file != null) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + if (files != null) { + for (File subfolderFile : files) { + writeDirWithFiles(subfolderFile, zos); + } } + } else { + String subtypeFolder = getSubtype().getSubtypeFolder(); + String zipEntryName = Algorithms.isEmpty(subtypeFolder) + ? file.getName() + : file.getPath().substring(file.getPath().indexOf(subtypeFolder) - 1); + setInputStream(new FileInputStream(file)); + super.writeEntry(zipEntryName, zos); } - } else { - String zipEntryName = Algorithms.isEmpty(getSubtype().getSubtypeFolder()) - ? file.getName() - : file.getPath().substring(file.getPath().indexOf(getSubtype().getSubtypeFolder()) - 1); - setInputStream(new FileInputStream(file)); - super.writeEntry(zipEntryName, zos); } } }; diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java index 40917bd7c5..38c637e0c7 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsExporter.java @@ -22,13 +22,14 @@ class SettingsExporter { private Map items; private Map additionalParams; - private boolean exportItemsFiles; - private boolean exportCancel; - private final ExportProgress exportProgress; + private ExportProgressListener progressListener; - SettingsExporter(boolean exportItemsFiles, ExportProgress exportProgress) { + private boolean cancelled; + private boolean exportItemsFiles; + + SettingsExporter(ExportProgressListener progressListener, boolean exportItemsFiles) { + this.progressListener = progressListener; this.exportItemsFiles = exportItemsFiles; - this.exportProgress = exportProgress; items = new LinkedHashMap<>(); additionalParams = new LinkedHashMap<>(); } @@ -40,8 +41,8 @@ class SettingsExporter { items.put(item.getName(), item); } - public void setExportCancel(boolean exportCancel) { - this.exportCancel = exportCancel; + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; } void addAdditionalParam(String key, String value) { @@ -79,15 +80,14 @@ class SettingsExporter { } writer.writeEntry(fileName, zos); } - if (exportCancel) { - exportCancel = false; + if (cancelled) { return; } if (item instanceof FileSettingsItem) { int size = (int) ((FileSettingsItem) item).getSize() / (1 << 20); progress += size; - if (exportProgress != null) { - exportProgress.setProgress(progress); + if (progressListener != null) { + progressListener.updateProgress(progress); } } } diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java index a9b66189ad..9c47589674 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/SettingsHelper.java @@ -37,6 +37,7 @@ import net.osmand.plus.quickaction.QuickActionRegistry; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean; import net.osmand.plus.settings.backend.ExportSettingsType; +import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; import org.json.JSONException; @@ -53,8 +54,8 @@ import java.util.Map; import java.util.Set; import static net.osmand.IndexConstants.OSMAND_SETTINGS_FILE_EXT; -import static net.osmand.plus.settings.backend.backup.FileSettingsItem.*; import static net.osmand.plus.activities.LocalIndexHelper.LocalIndexType; +import static net.osmand.plus.settings.backend.backup.FileSettingsItem.FileSubtype; /* Usage: @@ -141,8 +142,12 @@ public class SettingsHelper { return importTask == null || importTask.isImportDone(); } - public ExportAsyncTask getExportAsyncTask(File file) { - return exportAsyncTasks.get(file); + public boolean cancelExportForFile(File file) { + ExportAsyncTask exportTask = exportAsyncTasks.get(file); + if (exportTask != null && (exportTask.getStatus() == AsyncTask.Status.RUNNING)) { + return exportTask.cancel(true); + } + return false; } public boolean isFileExporting(File file) { @@ -206,31 +211,23 @@ public class SettingsHelper { } } - public interface ExportProgress { - void setProgress(int value); + public interface ExportProgressListener { + void updateProgress(int value); } @SuppressLint("StaticFieldLeak") public class ExportAsyncTask extends AsyncTask { - private final SettingsExporter exporter; - private final File file; + private File file; + private SettingsExporter exporter; private SettingsExportListener listener; - ExportAsyncTask(@NonNull File settingsFile, - @Nullable SettingsExportListener listener, - @NonNull List items, boolean exportItemsFiles) { + @Nullable SettingsExportListener listener, + @NonNull List items, boolean exportItemsFiles) { this.file = settingsFile; this.listener = listener; - ExportProgress exportProgress = new ExportProgress() { - @Override - public void setProgress(int value) { - exporter.setExportCancel(isCancelled()); - publishProgress(value); - } - }; - this.exporter = new SettingsExporter(exportItemsFiles, exportProgress); + this.exporter = new SettingsExporter(getProgressListener(), exportItemsFiles); for (SettingsItem item : items) { exporter.addSettingsItem(item); } @@ -266,9 +263,17 @@ public class SettingsHelper { @Override protected void onCancelled() { - super.onCancelled(); - //noinspection ResultOfMethodCallIgnored - file.delete(); + Algorithms.removeAllFiles(file); + } + + private ExportProgressListener getProgressListener() { + return new ExportProgressListener() { + @Override + public void updateProgress(int value) { + exporter.setCancelled(isCancelled()); + publishProgress(value); + } + }; } } @@ -448,8 +453,6 @@ public class SettingsHelper { public void exportSettings(@NonNull File fileDir, @NonNull String fileName, @Nullable SettingsExportListener listener, @NonNull List items, boolean exportItemsFiles) { File file = new File(fileDir, fileName + OSMAND_SETTINGS_FILE_EXT); ExportAsyncTask exportAsyncTask = new ExportAsyncTask(file, listener, items, exportItemsFiles); - - exportAsyncTasks.put(file, exportAsyncTask); exportAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -580,7 +583,7 @@ public class SettingsHelper { List files = getFilesByType(localIndexInfoList, LocalIndexType.MAP_DATA, LocalIndexType.TILES_DATA, LocalIndexType.SRTM_DATA, LocalIndexType.WIKI_DATA); if (!files.isEmpty()) { - sortData(files); + sortLocalFiles(files); dataList.put(ExportSettingsType.OFFLINE_MAPS, files); } files = getFilesByType(localIndexInfoList, LocalIndexType.TTS_VOICE_DATA); @@ -841,7 +844,7 @@ public class SettingsHelper { return settingsToOperate; } - private void sortData(List files) { + private void sortLocalFiles(List files) { final Collator collator = OsmAndCollator.primaryCollator(); Collections.sort(files, new Comparator() { @Override diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java index ba1d630bef..8d5b484dfb 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ExportProfileBottomSheet.java @@ -338,7 +338,7 @@ public class ExportProfileBottomSheet extends BasePreferenceBottomSheet { } private void cancelExport() { - app.getSettingsHelper().getExportAsyncTask(getExportFile()).cancel(true); + app.getSettingsHelper().cancelExportForFile(getExportFile()); progress.dismiss(); dismiss(); } From 81b4dc6e8ecfaeb1f51e95b19a91d43435606d4c Mon Sep 17 00:00:00 2001 From: Michal L Date: Thu, 5 Nov 2020 22:06:00 +0000 Subject: [PATCH 21/34] Translated using Weblate (Polish) Currently translated at 99.3% (3501 of 3524 strings) --- OsmAnd/res/values-pl/strings.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/OsmAnd/res/values-pl/strings.xml b/OsmAnd/res/values-pl/strings.xml index 13ddd2c001..a523ac90ad 100644 --- a/OsmAnd/res/values-pl/strings.xml +++ b/OsmAnd/res/values-pl/strings.xml @@ -3675,7 +3675,7 @@ Zakupy w OsmAnd Opłata zostanie pobrana z twojego konta Google Play przy potwierdzeniu zakupu. \n -\nSubskrypcja automatycznie odnawia się, chyba że anulujesz ją przed dniem odnowienia. Twoje konto zostanie obciążone za okres odnowienia (miesiąc/trzy miesiące/rok) dopiero w dniu odnowienia. +\nSubskrypcja automatycznie odnawia się, chyba że anulujesz ją przed dniem odnowienia. Twoje konto zostanie obciążone za okres odnowienia (miesiąc/trzy miesiące/rok) dopiero w dniu odnowienia. \n \nMożesz zarządzać subskrypcjami i anulować je w ustawieniach Google Play. • Nowe mapy stoków offline @@ -3802,7 +3802,7 @@ Przyciski głośności jako powiększenie Wózek inwalidzki Gokart - Zamknięta notatka OSM + Zamknięta uwaga OSM Aby kontynuować, musisz ustawić dni robocze Droga pomiędzy punktami Zaplanuj trasę @@ -3844,7 +3844,7 @@ Czy na pewno chcesz odrzucić wszystkie zmiany w zaplanowanej trasie, zamykając ją\? W przypadku odwrotnego kierunku Przejdź z mojej lokalizacji na trasę - Wózek naprzód + Wózek inwalidzki naprzód Ślady Podążanie za śladem Wybierz plik śladu do śledzenia lub zaimportuj go z urządzenia. @@ -3935,4 +3935,6 @@ Wylogowanie powiodło się Plik jest już zaimportowany do OsmAnd %1$s — %2$s + MGRS + MGRS \ No newline at end of file From 218f9abfb6fe3ed3178950c1be49dcf03f84c3b3 Mon Sep 17 00:00:00 2001 From: WaldiS Date: Thu, 5 Nov 2020 19:19:08 +0000 Subject: [PATCH 22/34] Translated using Weblate (Polish) Currently translated at 99.3% (3501 of 3524 strings) --- OsmAnd/res/values-pl/strings.xml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/OsmAnd/res/values-pl/strings.xml b/OsmAnd/res/values-pl/strings.xml index a523ac90ad..19ad8d4b91 100644 --- a/OsmAnd/res/values-pl/strings.xml +++ b/OsmAnd/res/values-pl/strings.xml @@ -3913,7 +3913,7 @@ Nazwa: A – Z Co nowego Ikony start/koniec - Dziękujemy za zakup linii konturowych + Dziękujemy za zakup \"Linii konturowych\" Subskrypcja naliczona za wybrany okres. Anuluj ją w AppGallery w dowolnym momencie. Płatność zostanie pobrana z konta AppGallery po potwierdzeniu zakupu. \n @@ -3937,4 +3937,19 @@ %1$s — %2$s MGRS MGRS + Użyj 2-fazowego algorytmu routingu A * + Wykres + %1$s dane dostępne tylko na drogach, aby je uzyskać, musisz obliczyć trasę za pomocą opcji „Trasa między punktami”. + Poczekaj na ponowne obliczenie trasy. +\nWykres będzie dostępny po ponownym obliczeniu. + Mapy lokalne + Luka + Przyjemności + Specjalne + Transport + Usługi + Symbole + Sport + Służby ratunkowe + Podróże \ No newline at end of file From 2bcc2e6559251f6965399ddecbbcb82e49adacc5 Mon Sep 17 00:00:00 2001 From: Artem Date: Wed, 4 Nov 2020 21:11:32 +0000 Subject: [PATCH 23/34] Translated using Weblate (Russian) Currently translated at 99.8% (3520 of 3524 strings) --- OsmAnd/res/values-ru/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OsmAnd/res/values-ru/strings.xml b/OsmAnd/res/values-ru/strings.xml index ef0b614441..d873a03ba5 100644 --- a/OsmAnd/res/values-ru/strings.xml +++ b/OsmAnd/res/values-ru/strings.xml @@ -3937,4 +3937,8 @@ Спорт Экстренные службы Путешествие + MGRS + MGRS + OsmAnd использует MGRS, который похож на формат UTM NATO. + Развитие местного общественного транспорта \ No newline at end of file From fe87d486ffcae8f97efd60d43c86cdeee059318a Mon Sep 17 00:00:00 2001 From: Mirco Zorzo Date: Wed, 4 Nov 2020 19:03:30 +0000 Subject: [PATCH 24/34] Translated using Weblate (Italian) Currently translated at 89.7% (3162 of 3524 strings) --- OsmAnd/res/values-it/strings.xml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/OsmAnd/res/values-it/strings.xml b/OsmAnd/res/values-it/strings.xml index db30024603..33315de637 100644 --- a/OsmAnd/res/values-it/strings.xml +++ b/OsmAnd/res/values-it/strings.xml @@ -222,7 +222,7 @@ La versione dell\'indice \'\'{0}\'\' non è supportata Il routing offline di OsmAnd è sperimentale e non funziona per distanze superiori ai 20 km. \n -\nNavigazione eseguita temporaneamente tramite servizio online CloudMade. +\nNavigazione temporaneamente spostata sul servizio online CloudMade. Impossibile trovare la cartella specificata. Cartella salvataggio dei dati Tutti i dati offline nella vecchia app verranno supportati dalla nuova, ma i Preferiti devono essere esportati dalla vecchia app e importati nella nuova. @@ -313,13 +313,13 @@ GPS secondi min. - Intervallo di tempo di risveglio usato dal servizio in background: + Intervallo di risveglio usato dal servizio in background: Intervallo di risveglio GPS - Fornitore di posizione utilizzato dal servizio in background: + Metodo di localizzazione utilizzato dal servizio in background: Fornitore di posizionamento Traccia la posizione mentre lo schermo è spento. Esegui OsmAnd in background - Il servizio di navigazione in background di OsmAnd necessita del sistema di posizionamento attivato. + Il servizio di navigazione in background necessita di un sistema di posizionamento attivo. Nascondi filtro Visualizza filtro Filtro @@ -2695,13 +2695,13 @@ Sto cercando l’articolo Wiki corrispondente Articolo non trovato Come aprire gli articoli di Wikipedia? - Navigazione -\n • Funziona online (veloce) o offline (nessuna tariffa di roaming quando sei all\'estero) -\n • Guida vocale svolta-dopo-svolta (voci registrate e sintetizzate) -\n • Guida sulla corsia opzionale, visualizzazione dei nomi delle strade, e tempo di arrivo stimato -\n • Supporto per punti intermedi del tuo itinerario -\n • Rielaborazione del percorso automatico ogni volta che si devia -\n • Ricerca di posti per indirizzo, per tipo (es: ristorante, albergo, stazione di servizio, museo) o per coordinate geografiche + Navigazione +\n • Funziona online (veloce) o offline (nessuna tariffa di roaming quando sei all\'estero) +\n • Guida vocale svolta-per-svolta (voci registrate e sintetizzate) +\n • Indicazioni di corsia opzionali, visualizzazione dei nomi delle strade, e tempo di arrivo stimato +\n • Supporto dei punti intermedi del tuo itinerario +\n • Rielaborazione del percorso automatico ogni volta che si devia +\n • Ricerca di luoghi per indirizzo, per tipo (es: ristorante, albergo, stazione di servizio, museo) o per coordinate geografiche \n Nascondi la descrizione completa Mostra la descrizione completa @@ -2743,12 +2743,12 @@ \n • Condividi la tua posizione in modo tale che i tuoi amici possano trovarti \n Funzioni per pedoni e velocipedi -\n • Mostra percorsi per pedoni, escursionisti e biciclette, ottimo per le attività all’aperto +\n • Mostra percorsi per pedoni, escursionisti e biciclette, ottimo per le attività all\'aperto \n • Navigazione e visualizzazione speciali per pedoni e velocipedi \n • Scegli se mostrare le fermate del trasporto pubblico (bus, tram e treno) inclusi i nomi delle linee \n • Scegli se registrare la tua visita su un file GPX locale oppure su di un servizio online \n • Scegli se mostrare la velocità e l’altitudine -\n • Mostra le curve di livello e l’ombreggiatura dei rilievi +\n • Mostra le curve di livello e l’ombreggiatura dei rilievi (attraverso il componente aggiuntivo) Modifica dello stile standard per un maggior contrasto delle strade pedonali e piste ciclabili. Utilizza i colori della versione vecchia di Mapnik. Orario di arrivo intermedio Orario intermedio @@ -3940,7 +3940,7 @@ Amenità Speciale Trasporto - Servizio + Servizi Simboli Sport Emergenza From 8ec94b7ae249d231ec2d43e22bc6b4eb48693efa Mon Sep 17 00:00:00 2001 From: Michal L Date: Thu, 5 Nov 2020 22:08:54 +0000 Subject: [PATCH 25/34] Translated using Weblate (Polish) Currently translated at 99.3% (3502 of 3524 strings) --- OsmAnd/res/values-pl/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OsmAnd/res/values-pl/strings.xml b/OsmAnd/res/values-pl/strings.xml index 19ad8d4b91..274f6b544a 100644 --- a/OsmAnd/res/values-pl/strings.xml +++ b/OsmAnd/res/values-pl/strings.xml @@ -3944,7 +3944,7 @@ \nWykres będzie dostępny po ponownym obliczeniu. Mapy lokalne Luka - Przyjemności + Udogodnienie Specjalne Transport Usługi From d3dd9ef3233cda28088cf0ece734c497a316a0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BB=D0=B0=D0=BC=D0=B5=D0=BD?= Date: Thu, 5 Nov 2020 12:38:26 +0000 Subject: [PATCH 26/34] Translated using Weblate (Bulgarian) Currently translated at 47.6% (1680 of 3524 strings) --- OsmAnd/res/values-bg/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OsmAnd/res/values-bg/strings.xml b/OsmAnd/res/values-bg/strings.xml index 35f42cfdcc..f225fb42df 100644 --- a/OsmAnd/res/values-bg/strings.xml +++ b/OsmAnd/res/values-bg/strings.xml @@ -2218,4 +2218,10 @@ Всички предишни сегменти Само избраният сегмент ще бъде преизчислен съобразно избрания профил. Всички следващи сегменти ще бъдат преизчислени с помощта на избрания профил. + Промяна типа на маршрута след + Опростена пътека + Само линията на маршрута ще бъде запазена, точките ще бъдат изтрити. + Име на файл + Избрани файлове за проследяване: %s + REC \ No newline at end of file From bd08933ca41cf41cd0ba3618e6e3a0bd94c5b367 Mon Sep 17 00:00:00 2001 From: ssantos Date: Thu, 5 Nov 2020 07:43:27 +0000 Subject: [PATCH 27/34] Translated using Weblate (Portuguese) Currently translated at 100.0% (3830 of 3830 strings) --- OsmAnd/res/values-pt/phrases.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OsmAnd/res/values-pt/phrases.xml b/OsmAnd/res/values-pt/phrases.xml index 978eb601ae..2386f2f08a 100644 --- a/OsmAnd/res/values-pt/phrases.xml +++ b/OsmAnd/res/values-pt/phrases.xml @@ -3833,4 +3833,6 @@ Barracão Telhado Ponto GPX + Torre de radar + Área de repouso \ No newline at end of file From 22cf3249aca94aa6ba61d3db0bf429776fa52bc8 Mon Sep 17 00:00:00 2001 From: Ahmed744 Date: Wed, 4 Nov 2020 23:07:39 +0000 Subject: [PATCH 28/34] Translated using Weblate (Arabic (Saudi Arabia)) Currently translated at 100.0% (271 of 271 strings) Translation: OsmAnd/Telegram Translate-URL: https://hosted.weblate.org/projects/osmand/telegram/ar_SA/ --- OsmAnd-telegram/res/values-ar-rSA/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OsmAnd-telegram/res/values-ar-rSA/strings.xml b/OsmAnd-telegram/res/values-ar-rSA/strings.xml index da6f0efd1b..f799745114 100644 --- a/OsmAnd-telegram/res/values-ar-rSA/strings.xml +++ b/OsmAnd-telegram/res/values-ar-rSA/strings.xml @@ -267,4 +267,8 @@ مشاركة: %1$s مفعل %1$s منذ + تصدير + لوجكات العازلة + تحقق من السجلات التفصيلية للتطبيق وشاركها + إرسال تقرير \ No newline at end of file From 87a165ee31476d3b4de0d65c2599ed7f5bf5e9b5 Mon Sep 17 00:00:00 2001 From: Artem Date: Wed, 4 Nov 2020 21:10:06 +0000 Subject: [PATCH 29/34] Translated using Weblate (Russian) Currently translated at 99.9% (3828 of 3830 strings) --- OsmAnd/res/values-ru/phrases.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/OsmAnd/res/values-ru/phrases.xml b/OsmAnd/res/values-ru/phrases.xml index 36b7e66d59..c75c0ac4ef 100644 --- a/OsmAnd/res/values-ru/phrases.xml +++ b/OsmAnd/res/values-ru/phrases.xml @@ -3835,4 +3835,5 @@ СПГ Навесы Точка GPX + Радиолокационная вышка \ No newline at end of file From 5f45b8751f3d657c2c5032424df126afb104661d Mon Sep 17 00:00:00 2001 From: max-klaus Date: Fri, 6 Nov 2020 13:17:40 +0300 Subject: [PATCH 30/34] Handle subscription states (on hold / paused) --- ...t.xml => osmlive_gone_dialog_fragment.xml} | 17 +- OsmAnd/res/values/strings.xml | 5 + .../plus/inapp/InAppPurchaseHelperImpl.java | 56 ++- OsmAnd/src/net/osmand/plus/Version.java | 4 +- .../osmand/plus/activities/MapActivity.java | 7 +- .../chooseplan/OsmLiveCancelledDialog.java | 245 ------------- .../plus/chooseplan/OsmLiveGoneDialog.java | 334 ++++++++++++++++++ .../plus/inapp/InAppPurchaseHelper.java | 57 ++- .../net/osmand/plus/inapp/InAppPurchases.java | 86 +++++ .../plus/settings/backend/OsmandSettings.java | 5 +- 10 files changed, 514 insertions(+), 302 deletions(-) rename OsmAnd/res/layout/{osmlive_cancelled_dialog_fragment.xml => osmlive_gone_dialog_fragment.xml} (81%) delete mode 100644 OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveCancelledDialog.java create mode 100644 OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveGoneDialog.java diff --git a/OsmAnd/res/layout/osmlive_cancelled_dialog_fragment.xml b/OsmAnd/res/layout/osmlive_gone_dialog_fragment.xml similarity index 81% rename from OsmAnd/res/layout/osmlive_cancelled_dialog_fragment.xml rename to OsmAnd/res/layout/osmlive_gone_dialog_fragment.xml index a936b85350..1a2a28f1c6 100644 --- a/OsmAnd/res/layout/osmlive_cancelled_dialog_fragment.xml +++ b/OsmAnd/res/layout/osmlive_gone_dialog_fragment.xml @@ -84,26 +84,11 @@ - - + android:layout_marginTop="@dimen/title_padding"> diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 91eec18222..c0d8bb8721 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,11 @@ Thx - Hardy --> + OsmAnd Live subscription is on hold + OsmAnd Live subscription has been paused + OsmAnd Live subscription has been expired + There is a problem with your subscription. Click the button to go to the Google Play subscription settings to fix your payment method. + Manage subscription You must add at least two points. Travel Emergency diff --git a/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java b/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java index 5bd9f2cb23..d5ff6fcedf 100644 --- a/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java +++ b/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java @@ -21,8 +21,10 @@ import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.inapp.InAppPurchases.InAppPurchase; import net.osmand.plus.inapp.InAppPurchases.InAppSubscription; +import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState; import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription; import net.osmand.plus.inapp.util.BillingManager; +import net.osmand.plus.settings.backend.CommonPreference; import net.osmand.plus.settings.backend.OsmandPreference; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.srtmplugin.SRTMPlugin; @@ -33,6 +35,7 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map.Entry; public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { @@ -139,6 +142,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { for (Purchase p : purchases) { skuSubscriptions.add(p.getSku()); } + skuSubscriptions.addAll(subscriptionStateMap.keySet()); BillingManager billingManager = getBillingManager(); // Have we been disposed of in the meantime? If so, quit. @@ -291,7 +295,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { } // Listener that's called when we finish querying the items and subscriptions we own - private SkuDetailsResponseListener mSkuDetailsResponseListener = new SkuDetailsResponseListener() { + private final SkuDetailsResponseListener mSkuDetailsResponseListener = new SkuDetailsResponseListener() { @NonNull private List getAllOwnedSubscriptionSkus() { @@ -304,6 +308,15 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { } } } + for (Entry entry : subscriptionStateMap.entrySet()) { + SubscriptionState state = entry.getValue(); + if (state == SubscriptionState.PAUSED || state == SubscriptionState.ON_HOLD) { + String sku = entry.getKey(); + if (!result.contains(sku)) { + result.add(sku); + } + } + } return result; } @@ -399,35 +412,28 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { // Do we have the live updates? boolean subscribedToLiveUpdates = false; List liveUpdatesPurchases = new ArrayList<>(); - for (InAppPurchase p : getLiveUpdates().getAllSubscriptions()) { - Purchase purchase = getPurchase(p.getSku()); - if (purchase != null) { - liveUpdatesPurchases.add(purchase); + for (InAppSubscription s : getLiveUpdates().getAllSubscriptions()) { + Purchase purchase = getPurchase(s.getSku()); + if (purchase != null || s.getState().isActive()) { + if (purchase != null) { + liveUpdatesPurchases.add(purchase); + } if (!subscribedToLiveUpdates) { subscribedToLiveUpdates = true; } } } - OsmandPreference subscriptionCancelledTime = ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_TIME; if (!subscribedToLiveUpdates && ctx.getSettings().LIVE_UPDATES_PURCHASED.get()) { - if (subscriptionCancelledTime.get() == 0) { - subscriptionCancelledTime.set(System.currentTimeMillis()); - ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.set(false); - ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.set(false); - } else if (System.currentTimeMillis() - subscriptionCancelledTime.get() > SUBSCRIPTION_HOLDING_TIME_MSEC) { - ctx.getSettings().LIVE_UPDATES_PURCHASED.set(false); - if (!isDepthContoursPurchased(ctx)) { - ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(false); - } + ctx.getSettings().LIVE_UPDATES_PURCHASED.set(false); + if (!isDepthContoursPurchased(ctx)) { + ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(false); } } else if (subscribedToLiveUpdates) { - subscriptionCancelledTime.set(0L); ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true); } lastValidationCheckTime = System.currentTimeMillis(); - logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE") - + " live updates purchased."); + logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE") + " live updates purchased."); OsmandSettings settings = ctx.getSettings(); settings.INAPPS_READ.set(true); @@ -490,12 +496,24 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { } } if (inAppPurchase instanceof InAppSubscription) { + InAppSubscription s = (InAppSubscription) inAppPurchase; + + SubscriptionState state = subscriptionStateMap.get(inAppPurchase.getSku()); + s.setState(state == null ? SubscriptionState.UNDEFINED : state); + CommonPreference statePref = ctx.getSettings().registerStringPreference( + s.getSku() + "_state", SubscriptionState.UNDEFINED.getStateStr()).makeGlobal(); + s.setPrevState(SubscriptionState.getByStateStr(statePref.get())); + statePref.set(s.getState().getStateStr()); + if (s.getState().isGone() && s.hasStateChanged()) { + ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L); + ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L); + } + String introductoryPrice = skuDetails.getIntroductoryPrice(); String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod(); String introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles(); long introductoryPriceAmountMicros = skuDetails.getIntroductoryPriceAmountMicros(); if (!Algorithms.isEmpty(introductoryPrice)) { - InAppSubscription s = (InAppSubscription) inAppPurchase; try { s.setIntroductoryInfo(new InAppPurchases.InAppSubscriptionIntroductoryInfo(s, introductoryPrice, introductoryPriceAmountMicros, introductoryPricePeriod, introductoryPriceCycles)); diff --git a/OsmAnd/src/net/osmand/plus/Version.java b/OsmAnd/src/net/osmand/plus/Version.java index 48dd9b1feb..8e23518613 100644 --- a/OsmAnd/src/net/osmand/plus/Version.java +++ b/OsmAnd/src/net/osmand/plus/Version.java @@ -134,11 +134,11 @@ public class Version { } public static boolean isDeveloperVersion(OsmandApplication ctx){ - return getAppName(ctx).contains("~") || ctx.getPackageName().equals(FREE_DEV_VERSION_NAME); + return false;//getAppName(ctx).contains("~") || ctx.getPackageName().equals(FREE_DEV_VERSION_NAME); } public static boolean isDeveloperBuild(OsmandApplication ctx){ - return getAppName(ctx).contains("~"); + return false;//getAppName(ctx).contains("~"); } public static String getVersionForTracker(OsmandApplication ctx) { diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java index 8cb6e832c5..2d33be5f82 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java @@ -83,7 +83,7 @@ import net.osmand.plus.base.BaseOsmAndFragment; import net.osmand.plus.base.ContextMenuFragment; import net.osmand.plus.base.FailSafeFuntions; import net.osmand.plus.base.MapViewTrackingUtilities; -import net.osmand.plus.chooseplan.OsmLiveCancelledDialog; +import net.osmand.plus.chooseplan.OsmLiveGoneDialog; import net.osmand.plus.dashboard.DashBaseFragment; import net.osmand.plus.dashboard.DashboardOnMap; import net.osmand.plus.dialogs.CrashBottomSheetDialogFragment; @@ -845,8 +845,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven getSupportFragmentManager().beginTransaction() .add(R.id.fragmentContainer, new FirstUsageWelcomeFragment(), FirstUsageWelcomeFragment.TAG).commitAllowingStateLoss(); - } else if (!isFirstScreenShowing() && OsmLiveCancelledDialog.shouldShowDialog(app)) { - OsmLiveCancelledDialog.showInstance(getSupportFragmentManager()); } else if (SendAnalyticsBottomSheetDialogFragment.shouldShowDialog(app)) { SendAnalyticsBottomSheetDialogFragment.showInstance(app, getSupportFragmentManager(), null); } @@ -2290,6 +2288,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven @Override public void onInAppPurchaseGetItems() { DiscountHelper.checkAndDisplay(this); + if (!isFirstScreenShowing() && OsmLiveGoneDialog.shouldShowDialog(app)) { + OsmLiveGoneDialog.showInstance(app, getSupportFragmentManager()); + } } public enum ShowQuickSearchMode { diff --git a/OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveCancelledDialog.java b/OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveCancelledDialog.java deleted file mode 100644 index a62ffcd296..0000000000 --- a/OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveCancelledDialog.java +++ /dev/null @@ -1,245 +0,0 @@ -package net.osmand.plus.chooseplan; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.os.Build; -import android.os.Bundle; -import android.view.ContextThemeWrapper; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.ProgressBar; - -import androidx.annotation.ColorRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; - -import net.osmand.PlatformUtil; -import net.osmand.plus.OsmandApplication; -import net.osmand.plus.Version; -import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.plus.settings.backend.OsmandPreference; -import net.osmand.plus.R; -import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.base.BaseOsmAndDialogFragment; -import net.osmand.plus.chooseplan.ChoosePlanDialogFragment.OsmAndFeature; -import net.osmand.plus.inapp.InAppPurchaseHelper; -import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener; -import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType; -import net.osmand.plus.widgets.TextViewEx; - -import org.apache.commons.logging.Log; - -import static net.osmand.plus.inapp.InAppPurchaseHelper.SUBSCRIPTION_HOLDING_TIME_MSEC; - -public class OsmLiveCancelledDialog extends BaseOsmAndDialogFragment implements InAppPurchaseListener { - public static final String TAG = OsmLiveCancelledDialog.class.getSimpleName(); - private static final Log LOG = PlatformUtil.getLog(OsmLiveCancelledDialog.class); - - private OsmandApplication app; - private InAppPurchaseHelper purchaseHelper; - - private boolean nightMode; - private View osmLiveButton; - - private final OsmAndFeature[] osmLiveFeatures = { - OsmAndFeature.DAILY_MAP_UPDATES, - OsmAndFeature.UNLIMITED_DOWNLOADS, - OsmAndFeature.WIKIPEDIA_OFFLINE, - OsmAndFeature.WIKIVOYAGE_OFFLINE, - OsmAndFeature.CONTOUR_LINES_HILLSHADE_MAPS, - OsmAndFeature.SEA_DEPTH_MAPS, - OsmAndFeature.UNLOCK_ALL_FEATURES, - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - app = getMyApplication(); - purchaseHelper = app.getInAppPurchaseHelper(); - nightMode = isNightMode(getMapActivity() != null); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Activity ctx = requireActivity(); - int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar; - Dialog dialog = new Dialog(ctx, themeId); - Window window = dialog.getWindow(); - if (window != null) { - window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) { - window.getAttributes().windowAnimations = R.style.Animations_Alpha; - } - if (Build.VERSION.SDK_INT >= 21) { - window.setStatusBarColor(ContextCompat.getColor(ctx, getStatusBarColor())); - } - } - return dialog; - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Context ctx = getContext(); - if (ctx == null) { - return null; - } - int themeRes = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar; - View view = LayoutInflater.from(new ContextThemeWrapper(getContext(), themeRes)) - .inflate(R.layout.osmlive_cancelled_dialog_fragment, container, false); - - view.findViewById(R.id.button_close).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismiss(); - } - }); - - TextViewEx infoDescr = (TextViewEx) view.findViewById(R.id.info_description); - StringBuilder descr = new StringBuilder(); - descr.append(getString(R.string.purchase_cancelled_dialog_descr)); - for (OsmAndFeature feature : osmLiveFeatures) { - descr.append("\n").append("— ").append(feature.toHumanString(ctx)); - } - infoDescr.setText(descr); - TextViewEx inappDescr = (TextViewEx) view.findViewById(R.id.inapp_descr); - inappDescr.setText(Version.isHuawei(app) ? R.string.osm_live_payment_desc_hw : R.string.osm_live_payment_desc); - - osmLiveButton = view.findViewById(R.id.card_button); - - return view; - } - - @Nullable - public MapActivity getMapActivity() { - Activity activity = getActivity(); - if (activity instanceof MapActivity) { - return (MapActivity) activity; - } - return null; - } - - @Override - public void onResume() { - super.onResume(); - - MapActivity mapActivity = getMapActivity(); - if (mapActivity != null) { - mapActivity.disableDrawer(); - } - - boolean requestingInventory = purchaseHelper != null && purchaseHelper.getActiveTask() == InAppPurchaseTaskType.REQUEST_INVENTORY; - setupOsmLiveButton(requestingInventory); - - OsmandPreference firstTimeShown = app.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN; - OsmandPreference secondTimeShown = app.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN; - if (!firstTimeShown.get()) { - firstTimeShown.set(true); - } else if (!secondTimeShown.get()) { - secondTimeShown.set(true); - } - } - - @Override - public void onPause() { - super.onPause(); - - MapActivity mapActivity = getMapActivity(); - if (mapActivity != null) { - mapActivity.enableDrawer(); - } - } - - @ColorRes - protected int getStatusBarColor() { - return nightMode ? R.color.status_bar_wikivoyage_dark : R.color.status_bar_wikivoyage_light; - } - - @Override - public void onError(InAppPurchaseTaskType taskType, String error) { - if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) { - setupOsmLiveButton(false); - } - } - - @Override - public void onGetItems() { - } - - @Override - public void onItemPurchased(String sku, boolean active) { - } - - @Override - public void showProgress(InAppPurchaseTaskType taskType) { - if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) { - setupOsmLiveButton(true); - } - } - - @Override - public void dismissProgress(InAppPurchaseTaskType taskType) { - if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) { - setupOsmLiveButton(false); - } - } - - private void setupOsmLiveButton(boolean progress) { - if (osmLiveButton != null) { - ProgressBar progressBar = (ProgressBar) osmLiveButton.findViewById(R.id.card_button_progress); - TextViewEx buttonTitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_title); - TextViewEx buttonSubtitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_subtitle); - buttonTitle.setText(getString(R.string.osm_live_plan_pricing)); - buttonSubtitle.setVisibility(View.GONE); - if (progress) { - buttonTitle.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); - osmLiveButton.setOnClickListener(null); - } else { - buttonTitle.setVisibility(View.VISIBLE); - progressBar.setVisibility(View.GONE); - osmLiveButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismiss(); - FragmentActivity activity = getActivity(); - if (activity != null) { - ChoosePlanDialogFragment.showOsmLiveInstance(activity.getSupportFragmentManager()); - } - } - }); - } - } - } - - public static boolean shouldShowDialog(OsmandApplication app) { - OsmandSettings settings = app.getSettings(); - long cancelledTime = settings.LIVE_UPDATES_PURCHASE_CANCELLED_TIME.get(); - boolean firstTimeShown = settings.LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.get(); - boolean secondTimeShown = settings.LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.get(); - return cancelledTime > 0 - && (!firstTimeShown - || (System.currentTimeMillis() - cancelledTime > SUBSCRIPTION_HOLDING_TIME_MSEC - && !secondTimeShown)); - } - - public static void showInstance(@NonNull FragmentManager fm) { - try { - if (fm.findFragmentByTag(OsmLiveCancelledDialog.TAG) == null) { - OsmLiveCancelledDialog fragment = new OsmLiveCancelledDialog(); - fragment.show(fm, OsmLiveCancelledDialog.TAG); - } - } catch (RuntimeException e) { - LOG.error("showInstance", e); - } - } -} diff --git a/OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveGoneDialog.java b/OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveGoneDialog.java new file mode 100644 index 0000000000..fdbce9a076 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveGoneDialog.java @@ -0,0 +1,334 @@ +package net.osmand.plus.chooseplan; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; + +import androidx.annotation.ColorRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + +import net.osmand.PlatformUtil; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.base.BaseOsmAndDialogFragment; +import net.osmand.plus.chooseplan.ChoosePlanDialogFragment.OsmAndFeature; +import net.osmand.plus.inapp.InAppPurchaseHelper; +import net.osmand.plus.inapp.InAppPurchases.InAppSubscription; +import net.osmand.plus.settings.backend.OsmandPreference; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.widgets.TextViewEx; +import net.osmand.util.Algorithms; + +import org.apache.commons.logging.Log; + +public abstract class OsmLiveGoneDialog extends BaseOsmAndDialogFragment { + public static final String TAG = OsmLiveGoneDialog.class.getName(); + private static final Log LOG = PlatformUtil.getLog(OsmLiveGoneDialog.class); + + private static final long TIME_BETWEEN_DIALOGS_MSEC = 1000 * 60 * 60 * 24 * 3; // 3 days + + private OsmandApplication app; + private boolean nightMode; + private View osmLiveButton; + + private final OsmAndFeature[] osmLiveFeatures = { + OsmAndFeature.DAILY_MAP_UPDATES, + OsmAndFeature.UNLIMITED_DOWNLOADS, + OsmAndFeature.WIKIPEDIA_OFFLINE, + OsmAndFeature.WIKIVOYAGE_OFFLINE, + OsmAndFeature.CONTOUR_LINES_HILLSHADE_MAPS, + OsmAndFeature.SEA_DEPTH_MAPS, + OsmAndFeature.UNLOCK_ALL_FEATURES, + }; + + public static class OsmLiveOnHoldDialog extends OsmLiveGoneDialog { + public static final String TAG = OsmLiveOnHoldDialog.class.getSimpleName(); + + @Override + protected OsmLiveButtonType getOsmLiveButtonType() { + return OsmLiveButtonType.MANAGE_SUBSCRIPTION; + } + + @Override + protected String getTitle() { + return getString(R.string.subscription_on_hold_title); + } + + @Override + protected String getSubscriptionDescr() { + return getString(R.string.subscription_payment_issue_title); + } + } + + public static class OsmLivePausedDialog extends OsmLiveGoneDialog { + public static final String TAG = OsmLivePausedDialog.class.getSimpleName(); + + @Override + protected OsmLiveButtonType getOsmLiveButtonType() { + return OsmLiveButtonType.MANAGE_SUBSCRIPTION; + } + + @Override + protected String getTitle() { + return getString(R.string.subscription_paused_title); + } + } + + public static class OsmLiveExpiredDialog extends OsmLiveGoneDialog { + public static final String TAG = OsmLiveExpiredDialog.class.getSimpleName(); + + @Override + protected String getTitle() { + return getString(R.string.subscription_expired_title); + } + } + + protected enum OsmLiveButtonType { + PURCHASE_SUBSCRIPTION, + MANAGE_SUBSCRIPTION + } + + protected OsmLiveButtonType getOsmLiveButtonType() { + return OsmLiveButtonType.PURCHASE_SUBSCRIPTION; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + app = getMyApplication(); + nightMode = isNightMode(getMapActivity() != null); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Activity ctx = requireActivity(); + int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar; + Dialog dialog = new Dialog(ctx, themeId); + Window window = dialog.getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) { + window.getAttributes().windowAnimations = R.style.Animations_Alpha; + } + if (Build.VERSION.SDK_INT >= 21) { + window.setStatusBarColor(ContextCompat.getColor(ctx, getStatusBarColor())); + } + } + return dialog; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Context ctx = getContext(); + if (ctx == null) { + return null; + } + int themeRes = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar; + View view = LayoutInflater.from(new ContextThemeWrapper(getContext(), themeRes)) + .inflate(R.layout.osmlive_gone_dialog_fragment, container, false); + + view.findViewById(R.id.button_close).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }); + + TextViewEx title = (TextViewEx) view.findViewById(R.id.title); + title.setText(getTitle()); + TextViewEx infoDescr = (TextViewEx) view.findViewById(R.id.info_description); + StringBuilder descr = new StringBuilder(); + String subscriptionDescr = getSubscriptionDescr(); + if (!Algorithms.isEmpty(subscriptionDescr)) { + descr.append(subscriptionDescr).append("\n\n"); + } + descr.append(getString(R.string.purchase_cancelled_dialog_descr)); + for (OsmAndFeature feature : osmLiveFeatures) { + descr.append("\n").append("— ").append(feature.toHumanString(ctx)); + } + infoDescr.setText(descr); + + osmLiveButton = view.findViewById(R.id.card_button); + + return view; + } + + protected abstract String getTitle(); + + protected String getSubscriptionDescr() { + return null; + } + + @Nullable + public MapActivity getMapActivity() { + Activity activity = getActivity(); + if (activity instanceof MapActivity) { + return (MapActivity) activity; + } + return null; + } + + @Override + public void onResume() { + super.onResume(); + + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null) { + mapActivity.disableDrawer(); + } + + setupOsmLiveButton(); + + OsmandPreference firstTimeShownTime = app.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME; + OsmandPreference secondTimeShownTime = app.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME; + if (firstTimeShownTime.get() == 0) { + firstTimeShownTime.set(System.currentTimeMillis()); + } else if (secondTimeShownTime.get() == 0) { + secondTimeShownTime.set(System.currentTimeMillis()); + } + } + + @Override + public void onPause() { + super.onPause(); + + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null) { + mapActivity.enableDrawer(); + } + } + + @ColorRes + protected int getStatusBarColor() { + return nightMode ? R.color.status_bar_wikivoyage_dark : R.color.status_bar_wikivoyage_light; + } + + private void setupOsmLiveButton() { + if (osmLiveButton != null) { + TextViewEx buttonTitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_title); + TextViewEx buttonSubtitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_subtitle); + switch (getOsmLiveButtonType()) { + case PURCHASE_SUBSCRIPTION: + buttonTitle.setText(getString(R.string.osm_live_plan_pricing)); + osmLiveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + FragmentActivity activity = getActivity(); + if (activity != null) { + ChoosePlanDialogFragment.showOsmLiveInstance(activity.getSupportFragmentManager()); + } + } + }); + break; + case MANAGE_SUBSCRIPTION: + buttonTitle.setText(getString(R.string.manage_subscription)); + osmLiveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + FragmentActivity activity = getActivity(); + if (activity != null) { + InAppSubscription expiredSubscription = getExpiredSubscription((OsmandApplication) activity.getApplication()); + if (expiredSubscription != null) { + manageSubscription(expiredSubscription.getSku()); + } + } + } + }); + break; + } + buttonSubtitle.setVisibility(View.GONE); + buttonTitle.setVisibility(View.VISIBLE); + osmLiveButton.findViewById(R.id.card_button_progress).setVisibility(View.GONE); + } + } + + private void manageSubscription(@Nullable String sku) { + Context ctx = getContext(); + if (ctx != null) { + String url = "https://play.google.com/store/account/subscriptions?package=" + ctx.getPackageName(); + if (!Algorithms.isEmpty(sku)) { + url += "&sku=" + sku; + } + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); + } + } + + @Nullable + private static InAppSubscription getExpiredSubscription(@NonNull OsmandApplication app) { + if (!app.getSettings().LIVE_UPDATES_PURCHASED.get()) { + InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper(); + return purchaseHelper.getLiveUpdates().getTopExpiredSubscription(); + } + return null; + } + + public static boolean shouldShowDialog(@NonNull OsmandApplication app) { + InAppSubscription expiredSubscription = getExpiredSubscription(app); + if (expiredSubscription == null) { + return false; + } + OsmandSettings settings = app.getSettings(); + long firstTimeShownTime = settings.LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.get(); + long secondTimeShownTime = settings.LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.get(); + return firstTimeShownTime == 0 + || (System.currentTimeMillis() - firstTimeShownTime > TIME_BETWEEN_DIALOGS_MSEC && secondTimeShownTime == 0); + } + + public static void showInstance(@NonNull OsmandApplication app, @NonNull FragmentManager fm) { + try { + InAppSubscription expiredSubscription = getExpiredSubscription(app); + if (expiredSubscription == null) { + return; + } + String tag = null; + DialogFragment fragment = null; + switch (expiredSubscription.getState()) { + case ON_HOLD: + tag = OsmLiveOnHoldDialog.TAG; + if (fm.findFragmentByTag(tag) == null) { + fragment = new OsmLiveOnHoldDialog(); + } + break; + case PAUSED: + tag = OsmLivePausedDialog.TAG; + if (fm.findFragmentByTag(tag) == null) { + fragment = new OsmLivePausedDialog(); + } + break; + case EXPIRED: + tag = OsmLiveExpiredDialog.TAG; + if (fm.findFragmentByTag(tag) == null) { + fragment = new OsmLiveExpiredDialog(); + } + break; + } + if (fragment != null) { + fragment.show(fm, tag); + } + } catch (RuntimeException e) { + LOG.error("showInstance", e); + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java index 543c3a819d..c7464c6b1f 100644 --- a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java +++ b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java @@ -17,13 +17,12 @@ import net.osmand.AndroidNetworkUtils.OnRequestsResultListener; import net.osmand.AndroidNetworkUtils.RequestResponse; import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.plus.settings.backend.OsmandPreference; import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.inapp.InAppPurchases.InAppPurchase; import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState; import net.osmand.plus.inapp.InAppPurchases.InAppSubscription; +import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState; import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionList; import net.osmand.plus.liveupdates.CountrySelectionFragment; import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem; @@ -50,11 +49,10 @@ public abstract class InAppPurchaseHelper { private static final String TAG = InAppPurchaseHelper.class.getSimpleName(); private boolean mDebugLog = false; - public static final long SUBSCRIPTION_HOLDING_TIME_MSEC = 1000 * 60 * 60 * 24 * 3; // 3 days - protected InAppPurchases purchases; protected long lastValidationCheckTime; protected boolean inventoryRequested; + protected Map subscriptionStateMap = new HashMap<>(); private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily @@ -375,21 +373,33 @@ public abstract class InAppPurchaseHelper { final String sku, final String payload) throws UnsupportedOperationException; @SuppressLint("StaticFieldLeak") - private class RequestInventoryTask extends AsyncTask { + private class RequestInventoryTask extends AsyncTask { RequestInventoryTask() { } @Override - protected String doInBackground(Void... params) { + protected String[] doInBackground(Void... params) { try { Map parameters = new HashMap<>(); parameters.put("androidPackage", ctx.getPackageName()); addUserInfo(parameters); - return AndroidNetworkUtils.sendRequest(ctx, + String activeSubscriptionsIds = AndroidNetworkUtils.sendRequest(ctx, "https://osmand.net/api/subscriptions/active", parameters, "Requesting active subscriptions...", false, false); + String subscriptionsState = null; + String userId = ctx.getSettings().BILLING_USER_ID.get(); + String userToken = ctx.getSettings().BILLING_USER_TOKEN.get(); + if (!Algorithms.isEmpty(userId) && !Algorithms.isEmpty(userToken)) { + parameters.put("userId", userId); + parameters.put("userToken", userToken); + subscriptionsState = AndroidNetworkUtils.sendRequest(ctx, + "https://osmand.net/api/subscriptions/get", + parameters, "Requesting subscriptions state...", false, false); + } + + return new String[] { activeSubscriptionsIds, subscriptionsState }; } catch (Exception e) { logError("sendRequest Error", e); } @@ -397,12 +407,14 @@ public abstract class InAppPurchaseHelper { } @Override - protected void onPostExecute(String response) { - logDebug("Response=" + response); - if (response != null) { + protected void onPostExecute(String[] response) { + logDebug("Response=" + Arrays.toString(response)); + String activeSubscriptionsIdsJson = response[0]; + String subscriptionsStateJson = response[1]; + if (activeSubscriptionsIdsJson != null) { inventoryRequested = true; try { - JSONObject obj = new JSONObject(response); + JSONObject obj = new JSONObject(activeSubscriptionsIdsJson); JSONArray names = obj.names(); if (names != null) { for (int i = 0; i < names.length(); i++) { @@ -418,6 +430,24 @@ public abstract class InAppPurchaseHelper { logError("Json parsing error", e); } } + if (subscriptionsStateJson != null) { + inventoryRequested = true; + Map subscriptionStateMap = new HashMap<>(); + try { + JSONArray subArrJson = new JSONArray(subscriptionsStateJson); + for (int i = 0; i < subArrJson.length(); i++) { + JSONObject subObj = subArrJson.getJSONObject(i); + String sku = subObj.getString("sku"); + String state = subObj.getString("state"); + if (!Algorithms.isEmpty(sku) && !Algorithms.isEmpty(state)) { + subscriptionStateMap.put(sku, SubscriptionState.getByStateStr(state)); + } + } + } catch (JSONException e) { + logError("Json parsing error", e); + } + InAppPurchaseHelper.this.subscriptionStateMap = subscriptionStateMap; + } exec(InAppPurchaseTaskType.REQUEST_INVENTORY, getRequestInventoryCommand()); } } @@ -467,9 +497,8 @@ public abstract class InAppPurchaseHelper { ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true); ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(true); - ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_TIME.set(0L); - ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.set(false); - ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.set(false); + ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L); + ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L); notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES); notifyItemPurchased(sku, active); diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java index 5004e97165..7cc9a8fbee 100644 --- a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java +++ b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java @@ -24,6 +24,8 @@ import java.text.NumberFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.Currency; import java.util.List; import java.util.Locale; @@ -190,6 +192,28 @@ public abstract class InAppPurchases { } return null; } + + @Nullable + public InAppSubscription getTopExpiredSubscription() { + List expiredSubscriptions = new ArrayList<>(); + for (InAppSubscription s : getAllSubscriptions()) { + if (s.getState().isGone()) { + expiredSubscriptions.add(s); + } + } + Collections.sort(expiredSubscriptions, new Comparator() { + @Override + public int compare(InAppSubscription s1, InAppSubscription s2) { + int orderS1 = s1.getState().ordinal(); + int orderS2 = s2.getState().ordinal(); + if (orderS1 != orderS2) { + return (orderS1 < orderS2) ? -1 : ((orderS1 == orderS2) ? 0 : 1); + } + return Double.compare(s1.getMonthlyPriceValue(), s2.getMonthlyPriceValue()); + } + }); + return expiredSubscriptions.isEmpty() ? null : expiredSubscriptions.get(0); + } } public abstract static class InAppPurchase { @@ -554,9 +578,49 @@ public abstract class InAppPurchases { private String subscriptionPeriodString; private Period subscriptionPeriod; private boolean upgrade = false; + private SubscriptionState state = SubscriptionState.UNDEFINED; + private SubscriptionState prevState = SubscriptionState.UNDEFINED; private InAppSubscriptionIntroductoryInfo introductoryInfo; + public enum SubscriptionState { + UNDEFINED("undefined"), + ACTIVE("active"), + CANCELLED("cancelled"), + IN_GRACE_PERIOD("in_grace_period"), + ON_HOLD("on_hold"), + PAUSED("paused"), + EXPIRED("expired"); + + private final String stateStr; + + SubscriptionState(@NonNull String stateStr) { + this.stateStr = stateStr; + } + + public String getStateStr() { + return stateStr; + } + + @NonNull + public static SubscriptionState getByStateStr(@NonNull String stateStr) { + for (SubscriptionState state : SubscriptionState.values()) { + if (state.stateStr.equals(stateStr)) { + return state; + } + } + return UNDEFINED; + } + + public boolean isGone() { + return this == ON_HOLD || this == PAUSED || this == EXPIRED; + } + + public boolean isActive() { + return this == ACTIVE || this == CANCELLED || this == IN_GRACE_PERIOD; + } + } + InAppSubscription(@NonNull String skuNoVersion, int version) { super(skuNoVersion + "_v" + version); this.skuNoVersion = skuNoVersion; @@ -592,6 +656,28 @@ public abstract class InAppPurchases { return upgrade; } + @NonNull + public SubscriptionState getState() { + return state; + } + + public void setState(@NonNull SubscriptionState state) { + this.state = state; + } + + @NonNull + public SubscriptionState getPrevState() { + return prevState; + } + + public void setPrevState(@NonNull SubscriptionState prevState) { + this.prevState = prevState; + } + + public boolean hasStateChanged() { + return state != prevState; + } + public boolean isAnyPurchased() { if (isPurchased()) { return true; diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java index bcc7a4c170..d24dd23ee6 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java @@ -1104,9 +1104,8 @@ public class OsmandSettings { public final OsmandPreference BILLING_PURCHASE_TOKEN_SENT = new BooleanPreference(this, "billing_purchase_token_sent", false).makeGlobal(); public final OsmandPreference BILLING_PURCHASE_TOKENS_SENT = new StringPreference(this, "billing_purchase_tokens_sent", "").makeGlobal(); public final OsmandPreference LIVE_UPDATES_PURCHASED = new BooleanPreference(this, "billing_live_updates_purchased", false).makeGlobal(); - public final OsmandPreference LIVE_UPDATES_PURCHASE_CANCELLED_TIME = new LongPreference(this, "live_updates_purchase_cancelled_time", 0).makeGlobal(); - public final OsmandPreference LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN = new BooleanPreference(this, "live_updates_purchase_cancelled_first_dlg_shown", false).makeGlobal(); - public final OsmandPreference LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN = new BooleanPreference(this, "live_updates_purchase_cancelled_second_dlg_shown", false).makeGlobal(); + public final OsmandPreference LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME = new LongPreference(this, "live_updates_expired_first_dlg_shown_time", 0).makeGlobal(); + public final OsmandPreference LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME = new LongPreference(this, "live_updates_expired_second_dlg_shown_time", 0).makeGlobal(); public final OsmandPreference FULL_VERSION_PURCHASED = new BooleanPreference(this, "billing_full_version_purchased", false).makeGlobal(); public final OsmandPreference DEPTH_CONTOURS_PURCHASED = new BooleanPreference(this, "billing_sea_depth_purchased", false).makeGlobal(); public final OsmandPreference CONTOUR_LINES_PURCHASED = new BooleanPreference(this, "billing_srtm_purchased", false).makeGlobal(); From e01ff6a646a54d7fdbfe3e925f1ad81d16de7d7a Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Fri, 6 Nov 2020 12:54:56 +0200 Subject: [PATCH 31/34] Fix #10091 Replacing a Favorite is faulty --- .../osmand/plus/dialogs/FavoriteDialogs.java | 25 ++++++++++++------- .../editors/PointEditorFragmentNew.java | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java b/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java index b6817fab05..e2a53f1d4a 100644 --- a/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java +++ b/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java @@ -20,6 +20,7 @@ import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; import net.osmand.AndroidUtils; import net.osmand.data.FavouritePoint; @@ -32,6 +33,8 @@ import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.FavoritesListFragment.FavouritesAdapter; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.mapcontextmenu.editors.FavoritePointEditor; +import net.osmand.plus.mapcontextmenu.editors.FavoritePointEditorFragmentNew; import java.text.MessageFormat; import java.util.ArrayList; @@ -79,20 +82,24 @@ public class FavoriteDialogs { @Override public void onClick(DialogInterface dialog, int which) { - if(dlgHolder != null && dlgHolder.length > 0 && dlgHolder[0] != null) { + if (dlgHolder != null && dlgHolder.length > 0 && dlgHolder[0] != null) { dlgHolder[0].dismiss(); } - FavouritePoint point = (FavouritePoint) args.getSerializable(KEY_FAVORITE); - if (helper.editFavourite(fp, point.getLatitude(), point.getLongitude())) { - helper.deleteFavourite(point); - if (activity instanceof MapActivity) { - ((MapActivity) activity).getContextMenu() + if (activity instanceof MapActivity) { + MapActivity mapActivity = (MapActivity) activity; + FavouritePoint point = (FavouritePoint) args.getSerializable(KEY_FAVORITE); + if (point != null && helper.editFavourite(fp, point.getLatitude(), point.getLongitude())) { + helper.deleteFavourite(point); + Fragment fragment = mapActivity.getSupportFragmentManager() + .findFragmentByTag(FavoritePointEditor.TAG); + if (fragment instanceof FavoritePointEditorFragmentNew) { + ((FavoritePointEditorFragmentNew) fragment).exitEditing(); + } + mapActivity.getContextMenu() .show(new LatLon(point.getLatitude(), point.getLongitude()), fp.getPointDescription(activity), fp); } + mapActivity.getMapView().refreshMap(); } - if (activity instanceof MapActivity) { - ((MapActivity) activity).getMapView().refreshMap(); - } } }); builder.show(); diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/PointEditorFragmentNew.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/PointEditorFragmentNew.java index 0918b7cd80..e59ce02373 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/PointEditorFragmentNew.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/PointEditorFragmentNew.java @@ -942,7 +942,7 @@ public abstract class PointEditorFragmentNew extends BaseOsmAndFragment implemen } } - private void exitEditing() { + public void exitEditing() { cancelled = true; dismiss(); } From 9b287b81b3c8d9bea162aa532030c617788e97a4 Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Fri, 6 Nov 2020 14:23:37 +0200 Subject: [PATCH 32/34] Fix #9627 Long press opens 2 menus (Local Maps) --- .../download/ui/LocalIndexesFragment.java | 73 ------------------- 1 file changed, 73 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java index 2fb12e2ea4..4cf4f1154a 100644 --- a/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java @@ -7,8 +7,6 @@ import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.util.TypedValue; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -19,7 +17,6 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.ExpandableListView; -import android.widget.ExpandableListView.ExpandableListContextMenuInfo; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; @@ -45,7 +42,6 @@ import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuAdapter.ItemClickListener; import net.osmand.plus.ContextMenuItem; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.UiUtilities; @@ -127,19 +123,6 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement if (asyncLoader == null || asyncLoader.getResult() == null) { reloadData(); } - - getExpandableListView().setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - long packedPos = ((ExpandableListContextMenuInfo) menuInfo).packedPosition; - int group = ExpandableListView.getPackedPositionGroup(packedPos); - int child = ExpandableListView.getPackedPositionChild(packedPos); - if (child >= 0 && group >= 0) { - final LocalIndexInfo point = listAdapter.getChild(group, child); - showContextMenu(point); - } - } - }); } public void reloadData() { @@ -156,62 +139,6 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement } } - private void showContextMenu(final LocalIndexInfo info) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - final ContextMenuAdapter adapter = new ContextMenuAdapter(getMyApplication()); - basicFileOperation(info, adapter); - OsmandPlugin.onContextMenuActivity(getActivity(), null, info, adapter); - - String[] values = adapter.getItemNames(); - builder.setItems(values, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - ContextMenuItem item = adapter.getItem(which); - if (item.getItemClickListener() != null) { - item.getItemClickListener().onContextMenuClick(null, - item.getTitleId(), which, false, null); - } - } - - }); - builder.show(); - } - - private void basicFileOperation(final LocalIndexInfo info, ContextMenuAdapter adapter) { - ItemClickListener listener = new ItemClickListener() { - @Override - public boolean onContextMenuClick(ArrayAdapter adapter, int resId, int pos, boolean isChecked, int[] viewCoordinates) { - return performBasicOperation(resId, info); - } - }; - if (info.getType() == LocalIndexType.MAP_DATA || info.getType() == LocalIndexType.SRTM_DATA || - info.getType() == LocalIndexType.WIKI_DATA ) { - if (!info.isBackupedData()) { - adapter.addItem(new ContextMenuItem.ItemBuilder() - .setTitleId(R.string.local_index_mi_backup, getContext()) - .setListener(listener) - .createItem()); - } - } - if (info.isBackupedData()) { - adapter.addItem(new ContextMenuItem.ItemBuilder() - .setTitleId(R.string.local_index_mi_restore, getContext()) - .setListener(listener) - .createItem()); - } - if (info.getType() != LocalIndexType.TTS_VOICE_DATA && info.getType() != LocalIndexType.VOICE_DATA - && info.getType() != LocalIndexType.FONT_DATA) { - adapter.addItem(new ContextMenuItem.ItemBuilder() - .setTitleId(R.string.shared_string_rename, getContext()) - .setListener(listener) - .createItem()); - } - adapter.addItem(new ContextMenuItem.ItemBuilder() - .setTitleId(R.string.shared_string_delete, getContext()) - .setListener(listener) - .createItem()); - } - private boolean performBasicOperation(int resId, final LocalIndexInfo info) { if (resId == R.string.shared_string_rename) { FileUtils.renameFile(getActivity(), new File(info.getPathToData()), new RenameCallback() { From 18e231ad8b4c687b1905f555cc7285791f04fe1e Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Fri, 6 Nov 2020 15:15:41 +0200 Subject: [PATCH 33/34] Fix mapActivity --- .../net/osmand/plus/dialogs/FavoriteDialogs.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java b/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java index e2a53f1d4a..1e5e79745e 100644 --- a/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java +++ b/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java @@ -85,11 +85,11 @@ public class FavoriteDialogs { if (dlgHolder != null && dlgHolder.length > 0 && dlgHolder[0] != null) { dlgHolder[0].dismiss(); } - if (activity instanceof MapActivity) { - MapActivity mapActivity = (MapActivity) activity; - FavouritePoint point = (FavouritePoint) args.getSerializable(KEY_FAVORITE); - if (point != null && helper.editFavourite(fp, point.getLatitude(), point.getLongitude())) { - helper.deleteFavourite(point); + FavouritePoint point = (FavouritePoint) args.getSerializable(KEY_FAVORITE); + if (point != null && helper.editFavourite(fp, point.getLatitude(), point.getLongitude())) { + helper.deleteFavourite(point); + if (activity instanceof MapActivity) { + MapActivity mapActivity = (MapActivity) activity; Fragment fragment = mapActivity.getSupportFragmentManager() .findFragmentByTag(FavoritePointEditor.TAG); if (fragment instanceof FavoritePointEditorFragmentNew) { @@ -98,7 +98,9 @@ public class FavoriteDialogs { mapActivity.getContextMenu() .show(new LatLon(point.getLatitude(), point.getLongitude()), fp.getPointDescription(activity), fp); } - mapActivity.getMapView().refreshMap(); + if (activity instanceof MapActivity) { + ((MapActivity) activity).getMapView().refreshMap(); + } } } }); From 5732d8840eed06fdd74d92cdc96b5e43ea0c5a17 Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Fri, 6 Nov 2020 15:28:55 +0200 Subject: [PATCH 34/34] Fix review --- OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java b/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java index 1e5e79745e..0690952bdd 100644 --- a/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java +++ b/OsmAnd/src/net/osmand/plus/dialogs/FavoriteDialogs.java @@ -97,9 +97,7 @@ public class FavoriteDialogs { } mapActivity.getContextMenu() .show(new LatLon(point.getLatitude(), point.getLongitude()), fp.getPointDescription(activity), fp); - } - if (activity instanceof MapActivity) { - ((MapActivity) activity).getMapView().refreshMap(); + mapActivity.getMapView().refreshMap(); } } }