feat: Add multi-map support with Google, Baidu, and Gaode providers

- Implement MapProvider interface with Google, Baidu, Gaode map providers
- Support satellite and normal map types for all providers
- Add coordinate conversion (WGS84 to BD09/GCJ02)
- Add tab-based map type and provider switching UI
- Add map settings with default provider and type configuration
- Add location button widget
- Add webview-based Baidu and Gaode map HTML assets
This commit is contained in:
2026-05-24 12:45:06 +08:00
parent 15c5fb4dbd
commit 48fbf1564d
13 changed files with 752 additions and 32 deletions
@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>°Ù¶ÈµØÍ¼</title>
<style type="text/css">
body, html, #container {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
font-family: "΢ÈíÑźÚ";
}
</style>
<script type="text/javascript" src="//api.map.baidu.com/api?v=3.0&ak=YOUR_BAIDU_AK"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
var map = new BMap.Map("container");
var point = new BMap.Point(116.404, 39.915);
map.centerAndZoom(point, 15);
map.enableScrollWheelZoom(true);
map.addControl(new BMap.NavigationControl());
map.addControl(new BMap.ScaleControl());
map.addControl(new BMap.MapTypeControl());
var polyline = null;
function setCenter(lat, lng) {
var point = new BMap.Point(lng, lat);
map.centerAndZoom(point, 17);
var marker = new BMap.Marker(point);
map.clearOverlays();
map.addOverlay(marker);
}
function setMapType(type) {
if (type === 'satellite') {
map.setMapType(BMAP_SATELLITE_MAP);
} else if (type === 'hybrid') {
map.setMapType(BMAP_HYBRID_MAP);
} else {
map.setMapType(BMAP_NORMAL_MAP);
}
}
function drawTrack(points) {
if (polyline) {
map.removeOverlay(polyline);
}
if (points.length > 0) {
var bmapPoints = points.map(function(p) {
return new BMap.Point(p[1], p[0]);
});
polyline = new BMap.Polyline(bmapPoints, {strokeColor:"#1E90FF", strokeWeight:5, strokeOpacity:0.8});
map.addOverlay(polyline);
map.setViewport(bmapPoints);
}
}
function clearTrack() {
if (polyline) {
map.removeOverlay(polyline);
polyline = null;
}
}
</script>
</body>
</html>
@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>¸ßµÂµØÍ¼</title>
<style type="text/css">
body, html, #container {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
font-family: "΢ÈíÑźÚ";
}
</style>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=YOUR_GAODE_KEY"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
var map = new AMap.Map('container', {
zoom: 15,
center: [116.397428, 39.90923],
pitch: 0,
viewMode: '3D'
});
map.addControl(new AMap.ToolBar());
map.addControl(new AMap.Scale());
map.addControl(new AMap.MapType());
var polyline = null;
function setCenter(lat, lng) {
map.setZoomAndCenter(17, [lng, lat]);
map.clearMap();
var marker = new AMap.Marker({
position: [lng, lat]
});
map.add(marker);
}
function setMapType(type) {
if (type === 'satellite') {
map.setMapType('satellite');
} else {
map.setMapType('standard');
}
}
function drawTrack(points) {
if (polyline) {
map.remove(polyline);
}
if (points.length > 0) {
var amapPoints = points.map(function(p) {
return [p[1], p[0]];
});
polyline = new AMap.Polyline({
path: amapPoints,
strokeColor: '#1E90FF',
strokeWeight: 5,
strokeOpacity: 0.8
});
map.add(polyline);
map.setFitView();
}
}
function clearTrack() {
if (polyline) {
map.remove(polyline);
polyline = null;
}
}
</script>
</body>
</html>
@@ -1,9 +1,13 @@
package com.senstools.domain.model
import com.senstools.presentation.ui.map.provider.MapType
data class AppSettings(
val gpsEnabled: Boolean = true,
val sensorEnabled: Boolean = true,
val mapEnabled: Boolean = true,
val gpsRate: Int = 5,
val sensorRate: Int = 100
val sensorRate: Int = 100,
val defaultMapProvider: String = "Google",
val defaultMapType: MapType = MapType.GOOGLE_NORMAL
)
@@ -6,22 +6,35 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.PolylineOptions
import com.google.android.material.tabs.TabLayout
import com.senstools.databinding.FragmentMapBinding
import com.senstools.presentation.ui.map.provider.*
import com.senstools.presentation.viewmodel.MapViewModel
class MapFragment : Fragment(), OnMapReadyCallback {
class MapFragment : Fragment() {
private var _binding: FragmentMapBinding? = null
private val binding get() = _binding!!
private val viewModel: MapViewModel by viewModels()
private var googleMap: GoogleMap? = null
private var currentProvider: MapProvider? = null
private val providers = mutableMapOf<String, MapProvider>()
private val googleTypes = listOf(
MapType.GOOGLE_NORMAL,
MapType.GOOGLE_SATELLITE,
MapType.GOOGLE_TERRAIN,
MapType.GOOGLE_HYBRID
)
private val baiduTypes = listOf(
MapType.BAIDU_NORMAL,
MapType.BAIDU_SATELLITE,
MapType.BAIDU_HYBRID
)
private val gaodeTypes = listOf(
MapType.GAODE_NORMAL,
MapType.GAODE_SATELLITE
)
override fun onCreateView(
inflater: LayoutInflater,
@@ -34,41 +47,117 @@ class MapFragment : Fragment(), OnMapReadyCallback {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mapFragment = childFragmentManager.findFragmentById(
com.senstools.R.id.mapFragment
) as? SupportMapFragment
mapFragment?.getMapAsync(this)
setupProviders()
setupTabs()
setupObservers()
}
override fun onMapReady(map: GoogleMap) {
googleMap = map
map.uiSettings.apply {
isZoomControlsEnabled = true
isMyLocationButtonEnabled = true
private fun setupProviders() {
providers["Google"] = GoogleMapProvider()
providers["°Ù¶È"] = BaiduMapProvider()
providers["¸ßµÂ"] = GaodeMapProvider()
}
private fun setupTabs() {
binding.tabMapProvider.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
val providerName = tab?.text.toString()
switchProvider(providerName)
}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {}
})
binding.tabMapType.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
val position = tab?.position ?: 0
switchMapType(position)
}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {}
})
providers.keys.forEach { providerName ->
binding.tabMapProvider.addTab(binding.tabMapProvider.newTab().setText(providerName))
}
providers.keys.firstOrNull()?.let { switchProvider(it) }
}
private fun switchProvider(providerName: String) {
currentProvider?.onPause()
val provider = providers[providerName] ?: return
provider.initialize(requireContext())
binding.mapContainer.removeAllViews()
binding.mapContainer.addView(provider.view)
currentProvider = provider
provider.onResume()
updateMapTypeTabs()
viewModel.currentLocation.value?.let {
provider.setLocation(it.latitude, it.longitude)
}
}
private fun typesForProvider(providerName: String): List<MapType> {
return when (providerName) {
"Google" -> googleTypes
"°Ù¶È" -> baiduTypes
"¸ßµÂ" -> gaodeTypes
else -> googleTypes
}
}
private fun updateMapTypeTabs() {
binding.tabMapType.removeAllTabs()
val types = typesForProvider(currentProvider?.name ?: "Google")
types.forEach { type ->
binding.tabMapType.addTab(binding.tabMapType.newTab().setText(type.displayName))
}
}
private fun switchMapType(position: Int) {
val types = typesForProvider(currentProvider?.name ?: "Google")
if (position in types.indices) {
currentProvider?.setMapType(types[position])
}
}
private fun setupObservers() {
viewModel.currentLocation.observe(viewLifecycleOwner) { location ->
location?.let {
val latLng = LatLng(it.latitude, it.longitude)
googleMap?.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 17f))
currentProvider?.setLocation(it.latitude, it.longitude)
}
}
viewModel.trackPoints.observe(viewLifecycleOwner) { points ->
googleMap?.clear()
if (points.isNotEmpty()) {
val polylineOptions = PolylineOptions()
.add(*points.map { LatLng(it.latitude, it.longitude) }.toTypedArray())
googleMap?.addPolyline(polylineOptions)
currentProvider?.clearTrack()
points.forEach {
currentProvider?.addTrackPoint(it.latitude, it.longitude)
}
}
}
override fun onResume() {
super.onResume()
currentProvider?.onResume()
}
override fun onPause() {
super.onPause()
currentProvider?.onPause()
}
override fun onDestroyView() {
super.onDestroyView()
currentProvider?.onDestroy()
_binding = null
}
}
@@ -0,0 +1,101 @@
package com.senstools.presentation.ui.map.provider
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
class BaiduMapProvider : MapProvider {
override val name = "°Ù¶È"
override var type: MapType = MapType.BAIDU_NORMAL
private set
private var webView: WebView? = null
private var container: FrameLayout? = null
private val trackPoints = mutableListOf<Pair<Double, Double>>()
override val view: View
get() = container ?: throw IllegalStateException("Map not initialized")
override fun initialize(context: Context) {
container = FrameLayout(context)
webView = WebView(context).apply {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
webViewClient = WebViewClient()
webChromeClient = WebChromeClient()
}
container?.addView(webView)
loadBaiduMap()
}
private fun loadBaiduMap() {
val mapType = when (type) {
MapType.BAIDU_SATELLITE -> "satellite"
MapType.BAIDU_HYBRID -> "hybrid"
else -> "normal"
}
webView?.loadUrl("file:///android_asset/baidu_map.html")
}
override fun setLocation(latitude: Double, longitude: Double) {
val bdCoords = convertWGS84ToBD09(latitude, longitude)
webView?.evaluateJavascript(
"setCenter(${bdCoords.first}, ${bdCoords.second})",
null
)
}
override fun addTrackPoint(latitude: Double, longitude: Double) {
val bdCoords = convertWGS84ToBD09(latitude, longitude)
trackPoints.add(bdCoords)
updatePolyline()
}
override fun clearTrack() {
trackPoints.clear()
webView?.evaluateJavascript("clearTrack()", null)
}
private fun updatePolyline() {
val pointsStr = trackPoints.joinToString(",") { "[${it.first}, ${it.second}]" }
webView?.evaluateJavascript("drawTrack([$pointsStr])", null)
}
override fun setMapType(type: MapType) {
this.type = type
val mapType = when (type) {
MapType.BAIDU_SATELLITE -> "satellite"
MapType.BAIDU_HYBRID -> "hybrid"
else -> "normal"
}
webView?.evaluateJavascript("setMapType('$mapType')", null)
}
override fun onResume() {
webView?.onResume()
}
override fun onPause() {
webView?.onPause()
}
override fun onDestroy() {
webView?.destroy()
}
private fun convertWGS84ToBD09(lat: Double, lon: Double): Pair<Double, Double> {
val pi = 3.1415926535897932384626
val x = lon - 0.0065
val y = lat - 0.006
val z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi * 3000.0 / 180.0)
val theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi * 3000.0 / 180.0)
val bdLon = z * Math.cos(theta) + 0.0065
val bdLat = z * Math.sin(theta) + 0.006
return Pair(bdLat, bdLon)
}
}
@@ -0,0 +1,113 @@
package com.senstools.presentation.ui.map.provider
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
class GaodeMapProvider : MapProvider {
override val name = "¸ßµÂ"
override var type: MapType = MapType.GAODE_NORMAL
private set
private var webView: WebView? = null
private var container: FrameLayout? = null
private val trackPoints = mutableListOf<Pair<Double, Double>>()
override val view: View
get() = container ?: throw IllegalStateException("Map not initialized")
override fun initialize(context: Context) {
container = FrameLayout(context)
webView = WebView(context).apply {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
webViewClient = WebViewClient()
webChromeClient = WebChromeClient()
}
container?.addView(webView)
loadGaodeMap()
}
private fun loadGaodeMap() {
webView?.loadUrl("file:///android_asset/gaode_map.html")
}
override fun setLocation(latitude: Double, longitude: Double) {
val gdCoords = convertWGS84ToGCJ02(latitude, longitude)
webView?.evaluateJavascript(
"setCenter(${gdCoords.first}, ${gdCoords.second})",
null
)
}
override fun addTrackPoint(latitude: Double, longitude: Double) {
val gdCoords = convertWGS84ToGCJ02(latitude, longitude)
trackPoints.add(gdCoords)
updatePolyline()
}
override fun clearTrack() {
trackPoints.clear()
webView?.evaluateJavascript("clearTrack()", null)
}
private fun updatePolyline() {
val pointsStr = trackPoints.joinToString(",") { "[${it.first}, ${it.second}]" }
webView?.evaluateJavascript("drawTrack([$pointsStr])", null)
}
override fun setMapType(type: MapType) {
this.type = type
val mapType = when (type) {
MapType.GAODE_SATELLITE -> "satellite"
else -> "normal"
}
webView?.evaluateJavascript("setMapType('$mapType')", null)
}
override fun onResume() {
webView?.onResume()
}
override fun onPause() {
webView?.onPause()
}
override fun onDestroy() {
webView?.destroy()
}
private fun convertWGS84ToGCJ02(lat: Double, lon: Double): Pair<Double, Double> {
val pi = 3.1415926535897932384626
val a = 6378245.0
val ee = 0.00669342162296594997
val (dLat, dLon) = transform(lat, lon)
val radLat = lat / 180.0 * pi
var magic = Math.sin(radLat)
magic = 1 - ee * magic * magic
val sqrtMagic = Math.sqrt(magic)
val mgLat = lat + (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi)
val mgLon = lon + (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi)
return Pair(mgLat, mgLon)
}
private fun transform(lat: Double, lon: Double): Pair<Double, Double> {
var x = lon - 105.0
var y = lat - 35.0
var dLat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x))
dLat += (20.0 * Math.sin(6.0 * x * Math.PI) + (20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0)
dLat += (20.0 * Math.sin(y * Math.PI) + (40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0)
dLat += (160.0 * Math.sin(y / 12.0 * Math.PI) + (320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0)
var dLon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x))
dLon += (20.0 * Math.sin(6.0 * x * Math.PI) + (20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0)
dLon += (20.0 * Math.sin(x * Math.PI) + (40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0)
dLon += (150.0 * Math.sin(x / 12.0 * Math.PI) + (300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0)
return Pair(dLat, dLon)
}
}
@@ -0,0 +1,101 @@
package com.senstools.presentation.ui.map.provider
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.MapView
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Polyline
import com.google.android.gms.maps.model.PolylineOptions
class GoogleMapProvider : MapProvider, OnMapReadyCallback {
override val name = "Google"
override var type: MapType = MapType.GOOGLE_NORMAL
private set
private var googleMap: GoogleMap? = null
private var mapView: MapView? = null
private var trackPolyline: Polyline? = null
private val trackPoints = mutableListOf<LatLng>()
private var container: FrameLayout? = null
override val view: View
get() = mapView ?: throw IllegalStateException("Map not initialized")
override fun initialize(context: Context) {
container = FrameLayout(context)
mapView = MapView(context)
container?.addView(mapView)
mapView?.onCreate(null)
mapView?.getMapAsync(this)
}
override fun onMapReady(map: GoogleMap) {
googleMap = map
map.uiSettings.apply {
isZoomControlsEnabled = true
isMyLocationButtonEnabled = true
isCompassEnabled = true
}
applyMapType()
}
private fun applyMapType() {
setMapType(type)
}
override fun setLocation(latitude: Double, longitude: Double) {
val latLng = LatLng(latitude, longitude)
googleMap?.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 17f))
}
override fun addTrackPoint(latitude: Double, longitude: Double) {
trackPoints.add(LatLng(latitude, longitude))
updatePolyline()
}
override fun clearTrack() {
trackPoints.clear()
trackPolyline?.remove()
trackPolyline = null
}
private fun updatePolyline() {
trackPolyline?.remove()
if (trackPoints.isNotEmpty()) {
val polylineOptions = PolylineOptions()
.addAll(trackPoints)
.color(0xFF1E90FF.toInt())
.width(5f)
trackPolyline = googleMap?.addPolyline(polylineOptions)
}
}
override fun setMapType(type: MapType) {
this.type = type
googleMap?.mapType = when (type) {
MapType.GOOGLE_NORMAL -> GoogleMap.MAP_TYPE_NORMAL
MapType.GOOGLE_SATELLITE -> GoogleMap.MAP_TYPE_SATELLITE
MapType.GOOGLE_TERRAIN -> GoogleMap.MAP_TYPE_TERRAIN
MapType.GOOGLE_HYBRID -> GoogleMap.MAP_TYPE_HYBRID
else -> GoogleMap.MAP_TYPE_NORMAL
}
}
override fun onResume() {
mapView?.onResume()
}
override fun onPause() {
mapView?.onPause()
}
override fun onDestroy() {
mapView?.onDestroy()
}
}
@@ -0,0 +1,33 @@
package com.senstools.presentation.ui.map.provider
import android.content.Context
import android.location.Location
import android.view.View
import androidx.annotation.ColorInt
interface MapProvider {
val name: String
val type: MapType
val view: View
fun initialize(context: Context)
fun setLocation(latitude: Double, longitude: Double)
fun addTrackPoint(latitude: Double, longitude: Double)
fun clearTrack()
fun setMapType(type: MapType)
fun onResume()
fun onPause()
fun onDestroy()
}
enum class MapType(val displayName: String) {
GOOGLE_NORMAL("Google 标准"),
GOOGLE_SATELLITE("Google 卫星"),
GOOGLE_TERRAIN("Google 地形"),
GOOGLE_HYBRID("Google 混合"),
BAIDU_NORMAL("百度 标准"),
BAIDU_SATELLITE("百度 卫星"),
BAIDU_HYBRID("百度 混合"),
GAODE_NORMAL("高德 标准"),
GAODE_SATELLITE("高德 卫星")
}
@@ -4,9 +4,11 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.senstools.databinding.FragmentSettingsBinding
import com.senstools.presentation.ui.map.provider.MapType
import com.senstools.presentation.viewmodel.SettingsViewModel
class SettingsFragment : Fragment() {
@@ -16,6 +18,9 @@ class SettingsFragment : Fragment() {
private val viewModel: SettingsViewModel by viewModels()
private val mapProviders = listOf("Google", "°Ù¶È", "¸ßµÂ")
private val allMapTypes = MapType.values().map { it.displayName }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -27,10 +32,27 @@ class SettingsFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupSpinners()
setupObservers()
setupListeners()
}
private fun setupSpinners() {
val providerAdapter = ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
mapProviders
)
binding.tvDefaultMapProvider.setAdapter(providerAdapter)
val typeAdapter = ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
allMapTypes
)
binding.tvDefaultMapType.setAdapter(typeAdapter)
}
private fun setupObservers() {
viewModel.settings.observe(viewLifecycleOwner) { settings ->
binding.apply {
@@ -39,6 +61,8 @@ class SettingsFragment : Fragment() {
switchMap.isChecked = settings.mapEnabled
sliderGpsRate.value = settings.gpsRate.toFloat()
sliderSensorRate.value = settings.sensorRate.toFloat()
tvDefaultMapProvider.setText(settings.defaultMapProvider, false)
tvDefaultMapType.setText(settings.defaultMapType.displayName, false)
}
}
}
@@ -60,6 +84,13 @@ class SettingsFragment : Fragment() {
sliderSensorRate.addOnChangeListener { _, value, _ ->
viewModel.setSensorRate(value.toInt())
}
tvDefaultMapProvider.setOnItemClickListener { _, _, position, _ ->
viewModel.setDefaultMapProvider(mapProviders[position])
}
tvDefaultMapType.setOnItemClickListener { _, _, position, _ ->
val selectedType = MapType.values().find { it.displayName == allMapTypes[position] }
selectedType?.let { viewModel.setDefaultMapType(it) }
}
}
}
@@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.senstools.domain.model.AppSettings
import com.senstools.presentation.ui.map.provider.MapType
class SettingsViewModel : ViewModel() {
@@ -37,4 +38,12 @@ class SettingsViewModel : ViewModel() {
fun setSensorRate(rate: Int) {
_settings.value = _settings.value?.copy(sensorRate = rate)
}
fun setDefaultMapProvider(provider: String) {
_settings.value = _settings.value?.copy(defaultMapProvider = provider)
}
fun setDefaultMapType(mapType: MapType) {
_settings.value = _settings.value?.copy(defaultMapType = mapType)
}
}
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z"/>
</vector>
@@ -1,12 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/mapFragment"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/mapContainer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/mapTypeSelector" />
</FrameLayout>
<LinearLayout
android:id="@+id/mapTypeSelector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
android:background="@android:color/white"
android:elevation="4dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabMapProvider"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:tabMode="scrollable"
app:tabGravity="start" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabMapType"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:tabMode="scrollable"
app:tabGravity="start" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabMyLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_my_location"
android:layout_margin="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -139,6 +139,44 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Default Map Provider" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp">
<com.google.android.material.textfield.AutoCompleteTextView
android:id="@+id/tvDefaultMapProvider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"
android:hint="Select Provider" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Default Map Type" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp">
<com.google.android.material.textfield.AutoCompleteTextView
android:id="@+id/tvDefaultMapType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"
android:hint="Select Map Type" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>