feat: pass users preferred tile source to MapViews

pull/1409/head
andrekir 2024-11-15 07:10:01 -03:00
rodzic aeedd4de43
commit ee75ba3392
4 zmienionych plików z 27 dodań i 40 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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(),

Wyświetl plik

@ -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)
}