diff --git a/OsmAnd/res/layout/gradient_card.xml b/OsmAnd/res/layout/gradient_card.xml index a4edba9be2..11b82f10ad 100644 --- a/OsmAnd/res/layout/gradient_card.xml +++ b/OsmAnd/res/layout/gradient_card.xml @@ -5,8 +5,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:padding="@dimen/content_padding" android:paddingStart="@dimen/content_padding" + android:paddingLeft="@dimen/content_padding" + android:paddingTop="@dimen/content_padding" + android:paddingRight="@dimen/content_padding" android:paddingEnd="@dimen/content_padding"> + + \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 9959488bd2..0a6f64787d 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -12,6 +12,9 @@ --> + Max. height + Min. height + Route line will be colorized depending on the elevation profile of the route. Output User points Announce when exceeded diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteLineDrawInfo.java b/OsmAnd/src/net/osmand/plus/routing/RouteLineDrawInfo.java index 88a033edae..2bb2eec155 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteLineDrawInfo.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteLineDrawInfo.java @@ -6,12 +6,14 @@ import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import net.osmand.plus.track.GradientScaleType; import net.osmand.util.Algorithms; public class RouteLineDrawInfo { private static final String LINE_COLOR_DAY = "line_color_day"; private static final String LINE_COLOR_NIGHT = "line_color_night"; + private static final String LINE_COLOR_GRADIENT = "line_color_gradient"; private static final String LINE_WIDTH = "line_width"; private static final String NAVIGATION_ICON_ID = "navigation_icon_id"; private static final String NAVIGATION_ICON_COLOR = "navigation_icon_color"; @@ -24,6 +26,7 @@ public class RouteLineDrawInfo { @ColorInt private Integer colorDay; private Integer colorNight; + private GradientScaleType scaleType; private String width; // temporally parameters to show in preview @@ -37,9 +40,11 @@ public class RouteLineDrawInfo { public RouteLineDrawInfo(@Nullable @ColorInt Integer colorDay, @Nullable @ColorInt Integer colorNight, + @Nullable GradientScaleType gradientScaleType, @Nullable String width) { this.colorDay = colorDay; this.colorNight = colorNight; + this.scaleType = gradientScaleType; this.width = width; } @@ -50,6 +55,7 @@ public class RouteLineDrawInfo { public RouteLineDrawInfo(@NonNull RouteLineDrawInfo existed) { this.colorDay = existed.colorDay; this.colorNight = existed.colorNight; + this.scaleType = existed.scaleType; this.width = existed.width; this.iconId = existed.iconId; this.iconColor = existed.iconColor; @@ -71,6 +77,10 @@ public class RouteLineDrawInfo { this.useDefaultColor = useDefaultColor; } + public void setGradientScaleType(@Nullable GradientScaleType scaleType) { + this.scaleType = scaleType; + } + public void setWidth(@Nullable String width) { this.width = width; } @@ -108,6 +118,11 @@ public class RouteLineDrawInfo { return nightMode ? colorNight : colorDay; } + @Nullable + public GradientScaleType getGradientScaleType() { + return scaleType; + } + @Nullable public String getWidth() { return width; @@ -141,6 +156,9 @@ public class RouteLineDrawInfo { if (bundle.containsKey(LINE_COLOR_NIGHT)) { colorNight = bundle.getInt(LINE_COLOR_NIGHT); } + if (bundle.containsKey(LINE_COLOR_GRADIENT)) { + scaleType = GradientScaleType.getGradientTypeByName(bundle.getString(LINE_COLOR_GRADIENT)); + } width = bundle.getString(LINE_WIDTH); iconId = bundle.getInt(NAVIGATION_ICON_ID); iconColor = bundle.getInt(NAVIGATION_ICON_COLOR); @@ -157,6 +175,9 @@ public class RouteLineDrawInfo { if (colorNight != null) { bundle.putInt(LINE_COLOR_NIGHT, colorNight); } + if (scaleType != null) { + bundle.putString(LINE_COLOR_GRADIENT, scaleType.getTypeName()); + } if (width != null) { bundle.putString(LINE_WIDTH, width); } @@ -177,6 +198,7 @@ public class RouteLineDrawInfo { if (!Algorithms.objectEquals(getColor(false), that.getColor(false))) return false; if (!Algorithms.objectEquals(getColor(true), that.getColor(true))) return false; + if (!Algorithms.objectEquals(scaleType, that.scaleType)) return false; return Algorithms.objectEquals(width, that.width); } @@ -184,6 +206,7 @@ public class RouteLineDrawInfo { public int hashCode() { int result = colorDay != null ? colorDay.hashCode() : 0; result = 31 * result + (colorNight != null ? colorNight.hashCode() : 0); + result = 31 * result + (scaleType != null ? scaleType.getTypeName().hashCode() : 0); result = 31 * result + (width != null ? width.hashCode() : 0); return result; } diff --git a/OsmAnd/src/net/osmand/plus/routing/cards/RouteLineColorCard.java b/OsmAnd/src/net/osmand/plus/routing/cards/RouteLineColorCard.java index dc6b10f9cd..f73371d643 100644 --- a/OsmAnd/src/net/osmand/plus/routing/cards/RouteLineColorCard.java +++ b/OsmAnd/src/net/osmand/plus/routing/cards/RouteLineColorCard.java @@ -21,6 +21,7 @@ import net.osmand.AndroidUtils; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.helpers.ColorDialogs; import net.osmand.plus.helpers.enums.DayNightMode; import net.osmand.plus.routepreparationmenu.cards.BaseCard; @@ -32,6 +33,8 @@ import net.osmand.plus.settings.fragments.HeaderUiAdapter; import net.osmand.plus.track.AppearanceViewHolder; import net.osmand.plus.track.ColorsCard; import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener; +import net.osmand.plus.track.GradientCard; +import net.osmand.plus.track.GradientScaleType; import net.osmand.plus.widgets.MultiStateToggleButton; import net.osmand.plus.widgets.MultiStateToggleButton.OnRadioItemClickListener; import net.osmand.plus.widgets.MultiStateToggleButton.RadioItem; @@ -50,6 +53,7 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP private HeaderUiAdapter headerUiAdapter; private ColorsCard colorsCard; + private GradientCard gradientCard; private ColorTypeAdapter colorAdapter; private RecyclerView groupRecyclerView; private TextView tvDescription; @@ -63,7 +67,9 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP private enum ColorMode { DEFAULT(R.string.map_widget_renderer, R.drawable.ic_action_map_style), - CUSTOM(R.string.shared_string_custom, R.drawable.ic_action_settings); + CUSTOM(R.string.shared_string_custom, R.drawable.ic_action_settings), + ALTITUDE(R.string.altitude, R.drawable.ic_action_hillshade_dark), + SLOPE(R.string.shared_string_slope, R.drawable.ic_action_altitude_ascent); ColorMode(int titleId, int iconId) { this.titleId = titleId; @@ -107,28 +113,43 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP setupRadioGroup(radioGroup); cardsContainer = (ViewGroup) view.findViewById(R.id.colors_card_container); - createColorSelector(cardsContainer); + createCards(cardsContainer); initSelectedMode(); } private void initSelectedMode() { - selectedMode = getRouteLineColor() == null ? ColorMode.DEFAULT : ColorMode.CUSTOM; + if (routeLineDrawInfo.getGradientScaleType() == GradientScaleType.ALTITUDE) { + selectedMode = ColorMode.ALTITUDE; + } else if (routeLineDrawInfo.getGradientScaleType() == GradientScaleType.SLOPE) { + selectedMode = ColorMode.SLOPE; + } else { + selectedMode = getRouteLineColor() == null ? ColorMode.DEFAULT : ColorMode.CUSTOM; + } modeChanged(); } private void modeChanged() { if (selectedMode == ColorMode.DEFAULT) { themeToggleContainer.setVisibility(View.GONE); - cardsContainer.setVisibility(View.GONE); + AndroidUiHelper.updateVisibility(colorsCard.getView(), false); + AndroidUiHelper.updateVisibility(gradientCard.getView(), false); routeLineDrawInfo.setUseDefaultColor(true); changeMapTheme(initMapTheme); - } else { + } else if (selectedMode == ColorMode.CUSTOM) { themeToggleContainer.setVisibility(View.VISIBLE); - cardsContainer.setVisibility(View.VISIBLE); + AndroidUiHelper.updateVisibility(colorsCard.getView(), true); + AndroidUiHelper.updateVisibility(gradientCard.getView(), false); routeLineDrawInfo.setUseDefaultColor(false); changeMapTheme(isNightMap() ? DayNightMode.NIGHT : DayNightMode.DAY); + } else { + gradientCard.setSelectedScaleType(getGradientScaleTypeFromMode()); + AndroidUiHelper.updateVisibility(colorsCard.getView(), false); + AndroidUiHelper.updateVisibility(gradientCard.getView(), true); + themeToggleContainer.setVisibility(View.GONE); + routeLineDrawInfo.setUseDefaultColor(false); } + routeLineDrawInfo.setGradientScaleType(getGradientScaleTypeFromMode()); updateColorItems(); updateDescription(); } @@ -169,7 +190,7 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP } } - private void createColorSelector(ViewGroup container) { + private void createCards(ViewGroup container) { MapActivity mapActivity = getMapActivity(); if (mapActivity != null) { List colors = new ArrayList<>(); @@ -183,6 +204,9 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP colorsCard = new ColorsCard(mapActivity, selectedColor, targetFragment, colors, preference, null); colorsCard.setListener(this); container.addView(colorsCard.build(mapActivity)); + + gradientCard = new GradientCard(mapActivity, routeLineDrawInfo.getGradientScaleType()); + container.addView(gradientCard.build(mapActivity)); } } @@ -211,6 +235,17 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP return routeLineDrawInfo.getColor(isNightMap()); } + @Nullable + private GradientScaleType getGradientScaleTypeFromMode() { + if (selectedMode == ColorMode.ALTITUDE) { + return GradientScaleType.ALTITUDE; + } else if (selectedMode == ColorMode.SLOPE) { + return GradientScaleType.SLOPE; + } else { + return null; + } + } + private void updateSelectedColor() { int selectedColor = colorsCard.getSelectedColor(); routeLineDrawInfo.setColor(selectedColor, isNightMap()); @@ -234,6 +269,8 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP String colorName = ""; if (selectedMode == ColorMode.DEFAULT) { colorName = app.getString(R.string.map_widget_renderer); + } else if (selectedMode == ColorMode.ALTITUDE || selectedMode == ColorMode.SLOPE) { + colorName = app.getString(selectedMode.titleId); } else if (getRouteLineColor() != null) { int colorNameId = ColorDialogs.getColorName(getRouteLineColor()); colorName = app.getString(colorNameId); @@ -247,10 +284,12 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP String pattern = app.getString(R.string.route_line_use_map_style_appearance); String color = app.getString(R.string.shared_string_color).toLowerCase(); description = String.format(pattern, color, app.getRendererRegistry().getSelectedRendererName()); - } else { + } else if (selectedMode == ColorMode.CUSTOM) { String pattern = app.getString(R.string.specify_color_for_map_mode); String mapModeTitle = app.getString(isNightMap() ? NIGHT_TITLE_ID : DAY_TITLE_ID); description = String.format(pattern, mapModeTitle.toLowerCase()); + } else { + description = app.getString(R.string.route_line_use_gradient_coloring); } tvDescription.setText(description); } @@ -367,4 +406,4 @@ public class RouteLineColorCard extends BaseCard implements CardListener, ColorP void onMapThemeUpdated(@NonNull DayNightMode mapTheme); } -} +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java index 1a77de50fb..c186146d81 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java @@ -2705,6 +2705,7 @@ public class OsmandSettings { public final ListStringPreference CUSTOM_ROUTE_LINE_COLORS = (ListStringPreference) new ListStringPreference(this, "custom_route_line_colors", null, ",").makeShared().makeGlobal(); public final CommonPreference ROUTE_LINE_COLOR_DAY = new IntPreference(this, "route_line_color", 0).cache().makeProfile(); public final CommonPreference ROUTE_LINE_COLOR_NIGHT = new IntPreference(this, "route_line_color_night", 0).cache().makeProfile(); + public final CommonPreference ROUTE_LINE_GRADIENT = new EnumStringPreference<>(this, "route_line_gradient", null, new GradientScaleType[] {GradientScaleType.ALTITUDE, GradientScaleType.SLOPE}).cache().makeProfile(); public final CommonPreference ROUTE_LINE_WIDTH = new StringPreference(this, "route_line_width", null).makeProfile(); public final OsmandPreference USE_OSM_LIVE_FOR_ROUTING = new BooleanPreference(this, "enable_osmc_routing", true).makeProfile(); diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java index c8d600315c..9bae7b1088 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java @@ -63,6 +63,7 @@ import net.osmand.plus.settings.backend.backup.SettingsHelper; import net.osmand.plus.settings.fragments.RouteLineAppearanceFragment.OnApplyRouteLineListener; import net.osmand.plus.track.ColorsCard; import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener; +import net.osmand.plus.track.GradientScaleType; import net.osmand.plus.widgets.FlowLayout; import net.osmand.plus.widgets.OsmandTextFieldBoxes; import net.osmand.util.Algorithms; @@ -1021,8 +1022,9 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O private RouteLineDrawInfo createRouteLineDrawInfo(@NonNull ApplicationMode appMode) { Integer colorDay = getRouteLineColor(appMode, settings.ROUTE_LINE_COLOR_DAY); Integer colorNight = getRouteLineColor(appMode, settings.ROUTE_LINE_COLOR_NIGHT); + GradientScaleType scaleType = settings.ROUTE_LINE_GRADIENT.getModeValue(appMode); String widthKey = settings.ROUTE_LINE_WIDTH.getModeValue(appMode); - return new RouteLineDrawInfo(colorDay, colorNight, widthKey); + return new RouteLineDrawInfo(colorDay, colorNight, scaleType, widthKey); } private Integer getRouteLineColor(@NonNull ApplicationMode appMode, @@ -1035,6 +1037,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O @NonNull RouteLineDrawInfo drawInfo) { saveRouteLineColor(appMode, settings.ROUTE_LINE_COLOR_DAY, drawInfo.getColor(false)); saveRouteLineColor(appMode, settings.ROUTE_LINE_COLOR_NIGHT, drawInfo.getColor(true)); + settings.ROUTE_LINE_GRADIENT.setModeValue(appMode, drawInfo.getGradientScaleType()); settings.ROUTE_LINE_WIDTH.setModeValue(appMode, drawInfo.getWidth()); } diff --git a/OsmAnd/src/net/osmand/plus/track/GradientCard.java b/OsmAnd/src/net/osmand/plus/track/GradientCard.java index 3c34d9f68d..de2623decf 100644 --- a/OsmAnd/src/net/osmand/plus/track/GradientCard.java +++ b/OsmAnd/src/net/osmand/plus/track/GradientCard.java @@ -19,15 +19,24 @@ import androidx.annotation.Nullable; public class GradientCard extends BaseCard { - private GPXTrackAnalysis gpxTrackAnalysis; + private final GPXTrackAnalysis gpxTrackAnalysis; private GradientScaleType selectedScaleType; + private final int minSlope = 0; + private final int maxSlope = 60; + public GradientCard(@NonNull MapActivity mapActivity, @NonNull GPXTrackAnalysis gpxTrackAnalysis, @Nullable GradientScaleType selectedScaleType) { super(mapActivity); this.gpxTrackAnalysis = gpxTrackAnalysis; this.selectedScaleType = selectedScaleType; } + public GradientCard(@NonNull MapActivity mapActivity, @Nullable GradientScaleType scaleType) { + super(mapActivity); + this.gpxTrackAnalysis = null; + this.selectedScaleType = scaleType; + } + @Override public int getCardLayoutId() { return R.layout.gradient_card; @@ -40,14 +49,27 @@ public class GradientCard extends BaseCard { return; } - AndroidUiHelper.updateVisibility(view, true); TextView minValue = view.findViewById(R.id.min_value); TextView maxValue = view.findViewById(R.id.max_value); - double min = RouteColorize.getMinValue(selectedScaleType.toColorizationType(), gpxTrackAnalysis); - double max = RouteColorize.getMaxValue(selectedScaleType.toColorizationType(), - gpxTrackAnalysis, min, app.getSettings().getApplicationMode().getMaxSpeed()); - minValue.setText(formatValue(min)); - maxValue.setText(formatValue(max)); + + if (gpxTrackAnalysis != null) { + AndroidUiHelper.updateVisibility(view, true); + double min = RouteColorize.getMinValue(selectedScaleType.toColorizationType(), gpxTrackAnalysis); + double max = RouteColorize.getMaxValue(selectedScaleType.toColorizationType(), + gpxTrackAnalysis, min, app.getSettings().getApplicationMode().getMaxSpeed()); + minValue.setText(formatValue(min)); + maxValue.setText(formatValue(max)); + AndroidUiHelper.updateVisibility(view.findViewById(R.id.space), true); + } else { + if (selectedScaleType == GradientScaleType.ALTITUDE) { + minValue.setText(R.string.shared_string_min_height); + maxValue.setText(R.string.shared_string_max_height); + } else if (selectedScaleType == GradientScaleType.SLOPE) { + minValue.setText(formatValue(minSlope)); + maxValue.setText(formatValue(maxSlope)); + } + AndroidUiHelper.updateVisibility(view.findViewById(R.id.space), false); + } } public void setSelectedScaleType(GradientScaleType type) { @@ -59,7 +81,7 @@ public class GradientCard extends BaseCard { if (selectedScaleType == GradientScaleType.ALTITUDE) { return OsmAndFormatter.getFormattedAlt(value, app); } else if (selectedScaleType == GradientScaleType.SLOPE) { - return (int) value + " %"; + return app.getString(R.string.ltr_or_rtl_combine_via_space, String.valueOf((int) value), "%"); } String speed = OsmAndFormatter.getFormattedSpeed((float) value, app); String speedUnit = app.getSettings().SPEED_SYSTEM.get().toShortString(app); diff --git a/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java index e74b0242ce..9ebf2eb093 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/RouteLayer.java @@ -344,15 +344,17 @@ public class RouteLayer extends OsmandMapLayer implements IContextMenuProvider { int centerY = drawInfo.getCenterY(); int screenHeight = drawInfo.getScreenHeight(); + updateRouteColors(nightMode); + updateRouteGradient(); + + LinearGradient gradient = null; if (gradientScaleType == GradientScaleType.ALTITUDE || gradientScaleType == GradientScaleType.SLOPE) { int[] colors = new int[] {RouteColorize.RED, RouteColorize.YELLOW, RouteColorize.GREEN}; float[] positions = new float[] {0, 0.5f, 1}; - LinearGradient gradient = new LinearGradient(centerX, 0, centerX, screenHeight, colors, positions, Shader.TileMode.CLAMP); - paintRouteLinePreview.setShader(gradient); - } else { - updateRouteColors(nightMode); - paintRouteLinePreview.setColor(getRouteLineColor()); + gradient = new LinearGradient(centerX, 0, centerX, screenHeight, colors, positions, Shader.TileMode.CLAMP); } + paintRouteLinePreview.setShader(gradient); + paintRouteLinePreview.setColor(getRouteLineColor()); canvas.drawLine(centerX, 0, centerX, screenHeight, paintRouteLinePreview); @@ -475,6 +477,14 @@ public class RouteLayer extends OsmandMapLayer implements IContextMenuProvider { routeLineColor = color; } + private void updateRouteGradient() { + if (routeLineDrawInfo != null) { + gradientScaleType = routeLineDrawInfo.getGradientScaleType(); + } else { + gradientScaleType = view.getSettings().ROUTE_LINE_GRADIENT.getModeValue(helper.getAppMode()); + } + } + private float getRouteLineWidth(@NonNull RotatedTileBox tileBox) { String widthKey; if (routeLineDrawInfo != null) { @@ -539,9 +549,10 @@ public class RouteLayer extends OsmandMapLayer implements IContextMenuProvider { boolean directTo = route.getRouteService() == RouteService.DIRECT_TO; boolean straight = route.getRouteService() == RouteService.STRAIGHT; publicTransportRouteGeometry.clearRoute(); + updateRouteColors(nightMode); + updateRouteGradient(); routeGeometry.setRouteStyleParams(getRouteLineColor(), getRouteLineWidth(tb), getDirectionArrowsColor(), gradientScaleType); routeGeometry.updateRoute(tb, route, view.getApplication()); - updateRouteColors(nightMode); if (directTo) { routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude, null, 0); diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/RouteGeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/RouteGeometryWay.java index 314e299760..28eef91f07 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/RouteGeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/RouteGeometryWay.java @@ -35,6 +35,7 @@ public class RouteGeometryWay extends GeometryWay