diff --git a/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java b/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java index a8c0aebb1e..50a5dfbb41 100644 --- a/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java +++ b/OsmAnd-api/src/net/osmand/aidlapi/OsmAndCustomizationConstants.java @@ -45,6 +45,7 @@ public interface OsmAndCustomizationConstants { String UNDERLAY_MAP = SHOW_ITEMS_ID_SCHEME + "underlay_map"; String CONTOUR_LINES = SHOW_ITEMS_ID_SCHEME + "contour_lines"; String HILLSHADE_LAYER = SHOW_ITEMS_ID_SCHEME + "hillshade_layer"; + String TERRAIN = SHOW_ITEMS_ID_SCHEME + "terrain"; String MAP_RENDERING_CATEGORY_ID = RENDERING_ITEMS_ID_SCHEME + "category"; String MAP_STYLE_ID = RENDERING_ITEMS_ID_SCHEME + "map_style"; diff --git a/OsmAnd/res/layout/fragment_terrain.xml b/OsmAnd/res/layout/fragment_terrain.xml new file mode 100644 index 0000000000..8fb1ecc19d --- /dev/null +++ b/OsmAnd/res/layout/fragment_terrain.xml @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 77a52af947..7259b518af 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,9 @@ Thx - Hardy --> + Legend + Zoom levels + Transparency You can read more about Slopes in %1$s. Additional maps are needed to view Slopes on the map. Additional maps are needed to view Hillshade on the map. diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 692bc82177..6e59f7dc5a 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -2096,6 +2096,10 @@ public class OsmandSettings { public final CommonPreference HILLSHADE = new BooleanPreference("hillshade_layer", true).makeProfile(); + public final CommonPreference TERRAIN = new BooleanPreference("terrain_layer", true).makeProfile(); + + public final CommonPreference TERRAIN_MODE = new EnumIntPreference<>("terrain_mode", TerrainMode.HILLSHADE, TerrainMode.values()).makeProfile(); + public final CommonPreference CONTOUR_LINES_ZOOM = new StringPreference("contour_lines_zoom", null).makeProfile().cache(); // this value string is synchronized with settings_pref.xml preference name @@ -3872,6 +3876,11 @@ public class OsmandSettings { } } + public enum TerrainMode { + HILLSHADE, + SLOPE + } + private OsmandPreference[] generalPrefs = new OsmandPreference[]{ EXTERNAL_INPUT_DEVICE, CENTER_POSITION_ON_MAP, diff --git a/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java b/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java index 5b3d0d0b83..0da40c9b4b 100644 --- a/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java +++ b/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java @@ -79,6 +79,7 @@ import net.osmand.plus.routing.RoutingHelper; import net.osmand.plus.srtmplugin.ContourLinesMenu; import net.osmand.plus.srtmplugin.HillshadeMenu; import net.osmand.plus.srtmplugin.SRTMPlugin; +import net.osmand.plus.srtmplugin.TerrainFragment; import net.osmand.plus.views.DownloadedRegionsLayer; import net.osmand.plus.views.MapInfoLayer; import net.osmand.plus.views.OsmandMapTileView; @@ -173,7 +174,9 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, IRouteInfo MAPILLARY, CONTOUR_LINES, HILLSHADE, - OSM_NOTES + OSM_NOTES, + TERRAIN, + SLOPE } private Map actionButtons = new HashMap<>(); @@ -320,6 +323,8 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, IRouteInfo tv.setText(R.string.layer_hillshade); } else if (visibleType == DashboardType.OSM_NOTES) { tv.setText(R.string.osm_notes); + } else if (visibleType == DashboardType.TERRAIN) { + tv.setText(R.string.shared_string_terrain); } ImageView edit = (ImageView) dashboardView.findViewById(R.id.toolbar_edit); edit.setVisibility(View.GONE); @@ -588,13 +593,19 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, IRouteInfo updateDownloadBtn(); View listViewLayout = dashboardView.findViewById(R.id.dash_list_view_layout); ScrollView scrollView = (ScrollView) dashboardView.findViewById(R.id.main_scroll); - if (visibleType == DashboardType.DASHBOARD || visibleType == DashboardType.MAPILLARY) { + if (visibleType == DashboardType.DASHBOARD + || visibleType == DashboardType.MAPILLARY + || visibleType == DashboardType.TERRAIN) { if (visibleType == DashboardType.DASHBOARD) { addOrUpdateDashboardFragments(); - } else { + } else if (visibleType == DashboardType.MAPILLARY) { mapActivity.getSupportFragmentManager().beginTransaction() .replace(R.id.content, new MapillaryFiltersFragment(), MapillaryFiltersFragment.TAG) .commit(); + } else { + mapActivity.getSupportFragmentManager().beginTransaction() + .replace(R.id.content, new TerrainFragment(), TerrainFragment.TAG) + .commit(); } scrollView.setVisibility(View.VISIBLE); scrollView.scrollTo(0, 0); diff --git a/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java b/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java index b733d3e94f..31c329a74b 100644 --- a/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java +++ b/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java @@ -19,6 +19,7 @@ import net.osmand.plus.DialogListItemAdapter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandSettings; +import net.osmand.plus.OsmandSettings.TerrainMode; import net.osmand.plus.OsmandSettings.CommonPreference; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; @@ -42,6 +43,7 @@ import java.util.List; import static net.osmand.aidlapi.OsmAndCustomizationConstants.CONTOUR_LINES; import static net.osmand.aidlapi.OsmAndCustomizationConstants.HILLSHADE_LAYER; +import static net.osmand.aidlapi.OsmAndCustomizationConstants.TERRAIN; public class SRTMPlugin extends OsmandPlugin { @@ -156,6 +158,14 @@ public class SRTMPlugin extends OsmandPlugin { return settings.HILLSHADE.get(); } + public boolean isTerrainLayerEnabled() { + return settings.TERRAIN.get(); + } + + public TerrainMode getTerrainMode() { + return settings.TERRAIN_MODE.get(); + } + public static boolean isContourLinesLayerEnabled(OsmandApplication app) { boolean contourLinesEnabled = false; @@ -199,6 +209,9 @@ public class SRTMPlugin extends OsmandPlugin { } else if (itemId == R.string.layer_hillshade) { mapActivity.getDashboard().setDashboardVisibility(true, DashboardOnMap.DashboardType.HILLSHADE, viewCoordinates); return false; + } else if (itemId == R.string.shared_string_terrain) { + mapActivity.getDashboard().setDashboardVisibility(true, DashboardOnMap.DashboardType.TERRAIN, viewCoordinates); + return false; } return true; } @@ -288,6 +301,18 @@ public class SRTMPlugin extends OsmandPlugin { .setListener(listener) .setPosition(13) .createItem()); + boolean terrainEnabled = settings.TERRAIN.get(); + adapter.addItem(new ContextMenuItem.ItemBuilder() + .setId(TERRAIN) + .setTitleId(R.string.shared_string_terrain, mapActivity) + .setSelected(terrainEnabled) + .setColor(terrainEnabled ? R.color.osmand_orange : ContextMenuItem.INVALID_ID) + .setIcon(R.drawable.ic_action_hillshade_dark) + .setSecondaryIcon(R.drawable.ic_action_additional_option) + .setListener(listener) + .setPosition(14) + .createItem() + ); } @Override diff --git a/OsmAnd/src/net/osmand/plus/srtmplugin/TerrainFragment.java b/OsmAnd/src/net/osmand/plus/srtmplugin/TerrainFragment.java new file mode 100644 index 0000000000..8818b30431 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/srtmplugin/TerrainFragment.java @@ -0,0 +1,176 @@ +package net.osmand.plus.srtmplugin; + +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSeekBar; +import android.support.v7.widget.SwitchCompat; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +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 net.osmand.plus.OsmandApplication; +import net.osmand.plus.OsmandPlugin; +import net.osmand.plus.OsmandSettings; +import net.osmand.plus.OsmandSettings.TerrainMode; +import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; +import net.osmand.plus.base.BaseOsmAndFragment; +import net.osmand.plus.inapp.InAppPurchaseHelper; +import net.osmand.plus.widgets.TextViewEx; + +public class TerrainFragment extends BaseOsmAndFragment { + + public static final String TAG = TerrainFragment.class.getSimpleName(); + + private static final String SLOPES_WIKI_URL = ""; + private static final String PLUGIN_URL = ""; + + private OsmandApplication app; + private UiUtilities uiUtilities; + private OsmandSettings settings; + private SRTMPlugin srtmPlugin; + private boolean nightMode; + private boolean srtmEnabled; + private boolean terrainEnabled; + + private int colorProfile; + + private TextView downloadDescriptionTv; + private TextView emptyStateDescriptionTv; + private TextView transparencyValueTv; + private TextView slopeReadMoreTv; + private TextView descriptionTv; + private TextView titleTv; + private TextView stateTv; + private SwitchCompat switchCompat; + private ImageView iconIv; + private LinearLayout legendContainer; + private LinearLayout emptyState; + private LinearLayout contentContainer; + private View legendTopDivider; + private View legendBottomDivider; + private View titleBottomDivider; + private AppCompatSeekBar transparencySlider; + + public TerrainFragment() { + + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + app = requireMyApplication(); + settings = app.getSettings(); + uiUtilities = app.getUIUtilities(); + nightMode = !settings.isLightContent(); + srtmPlugin = OsmandPlugin.getPlugin(SRTMPlugin.class); + srtmEnabled = OsmandPlugin.getEnabledPlugin(SRTMPlugin.class) != null + || InAppPurchaseHelper.isSubscribedToLiveUpdates(app); + colorProfile = settings.getApplicationMode().getIconColorInfo().getColor(nightMode); + terrainEnabled = srtmPlugin.isTerrainLayerEnabled(); + super.onCreate(savedInstanceState); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + inflater = UiUtilities.getInflater(app, nightMode); + View root = inflater.inflate(R.layout.fragment_terrain, container, false); + emptyStateDescriptionTv = root.findViewById(R.id.empty_state_description); + downloadDescriptionTv = root.findViewById(R.id.download_description_tv); + transparencyValueTv = root.findViewById(R.id.transparency_value_tv); + legendBottomDivider = root.findViewById(R.id.legend_bottom_divider); + transparencySlider = root.findViewById(R.id.transparency_slider); + titleBottomDivider = root.findViewById(R.id.titleBottomDivider); + legendTopDivider = root.findViewById(R.id.legend_top_divider); + slopeReadMoreTv = root.findViewById(R.id.slope_read_more_tv); + contentContainer = root.findViewById(R.id.content_container); + legendContainer = root.findViewById(R.id.legend_container); + switchCompat = root.findViewById(R.id.switch_compat); + descriptionTv = root.findViewById(R.id.description); + titleTv = root.findViewById(R.id.title_tv); + stateTv = root.findViewById(R.id.state_tv); + iconIv = root.findViewById(R.id.icon_iv); + + adjustUi(); + + return root; + } + + private void adjustUi() { + TerrainMode mode = srtmPlugin.getTerrainMode(); + switch (mode) { + case HILLSHADE: + descriptionTv.setText(R.string.hillshade_description); + downloadDescriptionTv.setText(R.string.hillshade_download_description); + break; + case SLOPE: + descriptionTv.setText(R.string.slope_description); + downloadDescriptionTv.setText(R.string.slope_download_description); + String wikiString = getString(R.string.shared_string_wikipedia); + setupClickableText(slopeReadMoreTv, + String.format(getString(R.string.slope_read_more), wikiString), + wikiString, + SLOPES_WIKI_URL); + break; + } + + if (!terrainEnabled) { + setupClickableText(emptyStateDescriptionTv, + String.format(getString(R.string.slope_read_more), PLUGIN_URL), + PLUGIN_URL, + PLUGIN_URL); + } + adjustGlobalVisibility(); + adjustLegendVisibility(mode); + } + + private void adjustGlobalVisibility() { + emptyStateDescriptionTv.setVisibility(terrainEnabled ? View.GONE : View.VISIBLE); + titleBottomDivider.setVisibility(terrainEnabled ? View.GONE : View.VISIBLE); + contentContainer.setVisibility(terrainEnabled ? View.VISIBLE : View.GONE); + } + + private void adjustLegendVisibility(TerrainMode mode) { + int visibility = TerrainMode.SLOPE.equals(mode) ? View.VISIBLE : View.GONE; + legendContainer.setVisibility(visibility); + legendBottomDivider.setVisibility(visibility); + legendTopDivider.setVisibility(visibility); + } + + private void setupClickableText(TextView textView, + String text, + String clickableText, + final String url) { + SpannableString spannableString = new SpannableString(text); + ClickableSpan clickableSpan = new ClickableSpan() { + @Override + public void onClick(@NonNull View view) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(url)); + startActivity(i); + } + }; + try { + int startIndex = text.indexOf(clickableText); + spannableString.setSpan(clickableSpan, startIndex, startIndex + clickableText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + textView.setText(spannableString); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + textView.setHighlightColor(nightMode + ? getResources().getColor(R.color.active_color_primary_dark) + : getResources().getColor(R.color.active_color_primary_light)); + } catch (RuntimeException e) { +// LOG.error("Error trying to find index of " + clickableText + " " + e); + } + } +}