kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
feat: pass users preferred tile source to MapViews
rodzic
aeedd4de43
commit
ee75ba3392
|
@ -1,6 +1,7 @@
|
|||
package com.geeksville.mesh.model
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
|
@ -17,8 +18,10 @@ import com.geeksville.mesh.TelemetryProtos.Telemetry
|
|||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.database.MeshLogRepository
|
||||
import com.geeksville.mesh.database.entity.MeshLog
|
||||
import com.geeksville.mesh.model.map.CustomTileSource
|
||||
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
|
||||
import com.geeksville.mesh.ui.Route
|
||||
import com.geeksville.mesh.ui.map.MAP_STYLE_ID
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
@ -111,6 +114,7 @@ class MetricsViewModel @Inject constructor(
|
|||
private val dispatchers: CoroutineDispatchers,
|
||||
private val meshLogRepository: MeshLogRepository,
|
||||
private val radioConfigRepository: RadioConfigRepository,
|
||||
private val preferences: SharedPreferences,
|
||||
) : ViewModel(), Logging {
|
||||
private val destNum = savedStateHandle.toRoute<Route.NodeDetail>().destNum
|
||||
|
||||
|
@ -119,6 +123,7 @@ class MetricsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun getUser(nodeNum: Int) = radioConfigRepository.getUser(nodeNum)
|
||||
val tileSource get() = CustomTileSource.getTileSource(preferences.getInt(MAP_STYLE_ID, 0))
|
||||
|
||||
fun deleteLog(uuid: String) = viewModelScope.launch(dispatchers.io) {
|
||||
meshLogRepository.deleteLog(uuid)
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.geeksville.mesh.database.entity.QuickChatAction
|
|||
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.service.MeshService
|
||||
import com.geeksville.mesh.ui.map.MAP_STYLE_ID
|
||||
import com.geeksville.mesh.util.positionToMeter
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -43,10 +44,8 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import java.io.BufferedWriter
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileWriter
|
||||
|
@ -122,15 +121,6 @@ data class NodesUiState(
|
|||
}
|
||||
}
|
||||
|
||||
data class MapState(
|
||||
val center: GeoPoint? = null,
|
||||
val zoom: Double = 0.0,
|
||||
) {
|
||||
companion object {
|
||||
val Empty = MapState()
|
||||
}
|
||||
}
|
||||
|
||||
data class Contact(
|
||||
val contactKey: String,
|
||||
val shortName: String,
|
||||
|
@ -259,11 +249,9 @@ class UIViewModel @Inject constructor(
|
|||
|
||||
val nodesWithPosition get() = nodeDB.nodeDBbyNum.value.values.filter { it.validPosition != null }
|
||||
|
||||
private val _mapState = MutableStateFlow(MapState.Empty)
|
||||
val mapState: StateFlow<MapState> get() = _mapState
|
||||
|
||||
fun updateMapCenterAndZoom(center: GeoPoint, zoom: Double) =
|
||||
_mapState.update { it.copy(center = center, zoom = zoom) }
|
||||
var mapStyleId: Int
|
||||
get() = preferences.getInt(MAP_STYLE_ID, 0)
|
||||
set(value) = preferences.edit { putInt(MAP_STYLE_ID, value) }
|
||||
|
||||
fun getUser(userId: String?) = nodeDB.getUser(userId ?: DataPacket.ID_BROADCAST)
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ fun NodeMapScreen(
|
|||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val geoPoints = state.positionLogs.map { GeoPoint(it.latitudeI * DegD, it.longitudeI * DegD) }
|
||||
val cameraView = remember { BoundingBox.fromGeoPoints(geoPoints) }
|
||||
val mapView = rememberMapViewWithLifecycle(cameraView)
|
||||
val mapView = rememberMapViewWithLifecycle(cameraView, viewModel.tileSource)
|
||||
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
|
|
@ -214,10 +214,6 @@ fun MapView(
|
|||
// UI Elements
|
||||
var cacheEstimate by remember { mutableStateOf("") }
|
||||
|
||||
// constants
|
||||
val prefsName = "org.geeksville.osm.prefs"
|
||||
val mapStyleId = "map_style_id"
|
||||
|
||||
var zoomLevelMin by remember { mutableDoubleStateOf(0.0) }
|
||||
var zoomLevelMax by remember { mutableDoubleStateOf(0.0) }
|
||||
|
||||
|
@ -225,20 +221,33 @@ fun MapView(
|
|||
var downloadRegionBoundingBox: BoundingBox? by remember { mutableStateOf(null) }
|
||||
var myLocationOverlay: MyLocationNewOverlay? by remember { mutableStateOf(null) }
|
||||
|
||||
var showDownloadButton: Boolean by remember { mutableStateOf(false) }
|
||||
var showEditWaypointDialog by remember { mutableStateOf<Waypoint?>(null) }
|
||||
var showCurrentCacheInfo by remember { mutableStateOf(false) }
|
||||
|
||||
val context = LocalContext.current
|
||||
val density = LocalDensity.current
|
||||
val mPrefs = remember { context.getSharedPreferences(prefsName, Context.MODE_PRIVATE) }
|
||||
|
||||
val haptic = LocalHapticFeedback.current
|
||||
fun performHapticFeedback() = haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
|
||||
val hasGps = remember { context.hasGps() }
|
||||
|
||||
fun loadOnlineTileSourceBase(): ITileSource {
|
||||
val id = model.mapStyleId
|
||||
debug("mapStyleId from prefs: $id")
|
||||
return CustomTileSource.getTileSource(id).also {
|
||||
zoomLevelMax = it.maximumZoomLevel.toDouble()
|
||||
showDownloadButton =
|
||||
if (it is OnlineTileSourceBase) it.tileSourcePolicy.acceptsBulkDownload() else false
|
||||
}
|
||||
}
|
||||
|
||||
val cameraView = remember {
|
||||
val geoPoints = model.nodesWithPosition.map { GeoPoint(it.latitude, it.longitude) }
|
||||
BoundingBox.fromGeoPoints(geoPoints)
|
||||
}
|
||||
val map = rememberMapViewWithLifecycle(cameraView)
|
||||
val map = rememberMapViewWithLifecycle(cameraView, loadOnlineTileSourceBase())
|
||||
|
||||
val nodeClusterer = remember { RadiusMarkerClusterer(context) }
|
||||
|
||||
|
@ -281,10 +290,6 @@ fun MapView(
|
|||
val nodes by model.nodeList.collectAsStateWithLifecycle()
|
||||
val waypoints by model.waypoints.collectAsStateWithLifecycle(emptyMap())
|
||||
|
||||
var showDownloadButton: Boolean by remember { mutableStateOf(false) }
|
||||
var showEditWaypointDialog by remember { mutableStateOf<Waypoint?>(null) }
|
||||
var showCurrentCacheInfo by remember { mutableStateOf(false) }
|
||||
|
||||
val markerIcon = remember {
|
||||
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_location_on_24)
|
||||
}
|
||||
|
@ -451,16 +456,6 @@ fun MapView(
|
|||
UpdateMarkers(onNodesChanged(nodes), onWaypointChanged(waypoints.values), nodeClusterer)
|
||||
}
|
||||
|
||||
fun loadOnlineTileSourceBase(): ITileSource {
|
||||
val id = mPrefs.getInt(mapStyleId, 0)
|
||||
debug("mapStyleId from prefs: $id")
|
||||
return CustomTileSource.getTileSource(id).also {
|
||||
zoomLevelMax = it.maximumZoomLevel.toDouble()
|
||||
showDownloadButton =
|
||||
if (it is OnlineTileSourceBase) it.tileSourcePolicy.acceptsBulkDownload() else false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Box overlay showing what area can be downloaded
|
||||
*/
|
||||
|
@ -536,10 +531,10 @@ fun MapView(
|
|||
val builder = MaterialAlertDialogBuilder(context)
|
||||
val mapStyles: Array<CharSequence> = CustomTileSource.mTileSources.values.toTypedArray()
|
||||
|
||||
val mapStyleInt = mPrefs.getInt(mapStyleId, 0)
|
||||
val mapStyleInt = model.mapStyleId
|
||||
builder.setSingleChoiceItems(mapStyles, mapStyleInt) { dialog, which ->
|
||||
debug("Set mapStyleId pref to $which")
|
||||
mPrefs.edit().putInt(mapStyleId, which).apply()
|
||||
model.mapStyleId = which
|
||||
dialog.dismiss()
|
||||
map.setTileSource(loadOnlineTileSourceBase())
|
||||
}
|
||||
|
@ -586,7 +581,6 @@ fun MapView(
|
|||
AndroidView(
|
||||
factory = {
|
||||
map.apply {
|
||||
setTileSource(loadOnlineTileSourceBase())
|
||||
setDestroyMode(false) // keeps map instance alive when in the background
|
||||
addMapListener(boxOverlayListener)
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue