kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
rodzic
bfa2eaef11
commit
3bd4132089
|
@ -24,7 +24,6 @@ import com.geeksville.mesh.database.QuickChatActionRepository
|
|||
import com.geeksville.mesh.database.entity.NodeEntity
|
||||
import com.geeksville.mesh.database.entity.Packet
|
||||
import com.geeksville.mesh.database.entity.QuickChatAction
|
||||
import com.geeksville.mesh.database.entity.toNodeInfo
|
||||
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.service.MeshService
|
||||
|
@ -43,8 +42,10 @@ 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
|
||||
|
@ -119,6 +120,15 @@ 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,
|
||||
|
@ -231,8 +241,13 @@ class UIViewModel @Inject constructor(
|
|||
val myNodeInfo: StateFlow<MyNodeInfo?> get() = nodeDB.myNodeInfo
|
||||
val ourNodeInfo: StateFlow<NodeEntity?> get() = nodeDB.ourNodeInfo
|
||||
|
||||
// FIXME only used in MapFragment
|
||||
val initialNodes get() = nodeDB.nodeDBbyNum.value.values.map { it.toNodeInfo() }
|
||||
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) }
|
||||
|
||||
fun getUser(userId: String?) = nodeDB.getUser(userId) ?: user {
|
||||
id = userId.orEmpty()
|
||||
|
|
|
@ -64,6 +64,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|||
import kotlinx.coroutines.flow.mapLatest
|
||||
import org.osmdroid.bonuspack.utils.BonusPackHelper.getBitmapFromVectorDrawable
|
||||
import org.osmdroid.config.Configuration
|
||||
import org.osmdroid.events.DelayedMapListener
|
||||
import org.osmdroid.events.MapEventsReceiver
|
||||
import org.osmdroid.events.MapListener
|
||||
import org.osmdroid.events.ScrollEvent
|
||||
|
@ -238,6 +239,21 @@ private fun Context.purgeTileSource(onResult: (String) -> Unit) {
|
|||
builder.show()
|
||||
}
|
||||
|
||||
private const val INACTIVITY_DELAY_MILLIS = 500L
|
||||
private fun MapView.addMapEventListener(onEvent: () -> Unit) {
|
||||
addMapListener(DelayedMapListener(object : MapListener {
|
||||
override fun onScroll(event: ScrollEvent): Boolean {
|
||||
onEvent()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onZoom(event: ZoomEvent): Boolean {
|
||||
onEvent()
|
||||
return true
|
||||
}
|
||||
}, INACTIVITY_DELAY_MILLIS))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MapView(
|
||||
model: UIViewModel = viewModel(),
|
||||
|
@ -265,6 +281,7 @@ fun MapView(
|
|||
val hasGps = remember { context.hasGps() }
|
||||
|
||||
val map = rememberMapViewWithLifecycle(context)
|
||||
val state by model.mapState.collectAsStateWithLifecycle()
|
||||
|
||||
fun MapView.toggleMyLocation() {
|
||||
if (context.gpsDisabled()) {
|
||||
|
@ -473,15 +490,17 @@ fun MapView(
|
|||
}
|
||||
|
||||
fun MapView.zoomToNodes() {
|
||||
val nodeMarkers = onNodesChanged(model.initialNodes)
|
||||
if (nodeMarkers.isNotEmpty()) {
|
||||
val box = BoundingBox.fromGeoPoints(nodeMarkers.map { it.position })
|
||||
if (state.center == null) {
|
||||
val geoPoints = model.nodesWithPosition.map { GeoPoint(it.latitude, it.longitude) }
|
||||
val box = BoundingBox.fromGeoPoints(geoPoints)
|
||||
val center = GeoPoint(box.centerLatitude, box.centerLongitude)
|
||||
val maximumZoomLevel = tileProvider.tileSource.maximumZoomLevel.toDouble()
|
||||
val finalZoomLevel = minOf(box.requiredZoomLevel() * 0.8, maximumZoomLevel)
|
||||
val finalZoomLevel = minOf(box.requiredZoomLevel() * 0.8, maxZoomLevel)
|
||||
controller.setCenter(center)
|
||||
controller.setZoom(finalZoomLevel)
|
||||
} else controller.zoomIn()
|
||||
} else {
|
||||
controller.setCenter(state.center)
|
||||
controller.setZoom(state.zoom)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadOnlineTileSourceBase(): ITileSource {
|
||||
|
@ -624,16 +643,9 @@ fun MapView(
|
|||
minZoomLevel = 1.5
|
||||
// Disables default +/- button for zooming
|
||||
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
|
||||
addMapListener(object : MapListener {
|
||||
override fun onScroll(event: ScrollEvent): Boolean {
|
||||
if (downloadRegionBoundingBox != null) generateBoxOverlay()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onZoom(event: ZoomEvent): Boolean {
|
||||
return false
|
||||
}
|
||||
})
|
||||
addMapEventListener {
|
||||
model.updateMapCenterAndZoom(map.projection.currentCenter, map.zoomLevelDouble)
|
||||
}
|
||||
zoomToNodes()
|
||||
}
|
||||
},
|
||||
|
|
Ładowanie…
Reference in New Issue