kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor: finish transition from `NodeInfo` to `NodeEntity`
rodzic
ed2703c77a
commit
b503c10789
|
@ -4,6 +4,7 @@ import android.graphics.Color
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig
|
||||||
import com.geeksville.mesh.DeviceMetrics
|
import com.geeksville.mesh.DeviceMetrics
|
||||||
import com.geeksville.mesh.EnvironmentMetrics
|
import com.geeksville.mesh.EnvironmentMetrics
|
||||||
import com.geeksville.mesh.MeshProtos
|
import com.geeksville.mesh.MeshProtos
|
||||||
|
@ -13,7 +14,10 @@ import com.geeksville.mesh.PaxcountProtos
|
||||||
import com.geeksville.mesh.Position
|
import com.geeksville.mesh.Position
|
||||||
import com.geeksville.mesh.TelemetryProtos
|
import com.geeksville.mesh.TelemetryProtos
|
||||||
import com.geeksville.mesh.copy
|
import com.geeksville.mesh.copy
|
||||||
|
import com.geeksville.mesh.util.bearing
|
||||||
|
import com.geeksville.mesh.util.GPSFormat
|
||||||
import com.geeksville.mesh.util.latLongToMeter
|
import com.geeksville.mesh.util.latLongToMeter
|
||||||
|
import com.geeksville.mesh.util.toDistanceString
|
||||||
import com.google.protobuf.ByteString
|
import com.google.protobuf.ByteString
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
|
@ -108,6 +112,26 @@ data class NodeEntity(
|
||||||
else latLongToMeter(latitude, longitude, o.latitude, o.longitude).toInt()
|
else latLongToMeter(latitude, longitude, o.latitude, o.longitude).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @return a nice human readable string for the distance, or null for unknown
|
||||||
|
fun distanceStr(o: NodeEntity, displayUnits: Int = 0): String? = distance(o)?.let { dist ->
|
||||||
|
val system = DisplayConfig.DisplayUnits.forNumber(displayUnits)
|
||||||
|
return if (dist > 0) dist.toDistanceString(system) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
// @return bearing to the other position in degrees
|
||||||
|
fun bearing(o: NodeEntity?): Int? {
|
||||||
|
return if (validPosition == null || o?.validPosition == null) null
|
||||||
|
else bearing(latitude, longitude, o.latitude, o.longitude).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun gpsString(gpsFormat: Int): String = when (gpsFormat) {
|
||||||
|
DisplayConfig.GpsCoordinateFormat.DEC_VALUE -> GPSFormat.toDEC(latitude, longitude)
|
||||||
|
DisplayConfig.GpsCoordinateFormat.DMS_VALUE -> GPSFormat.toDMS(latitude, longitude)
|
||||||
|
DisplayConfig.GpsCoordinateFormat.UTM_VALUE -> GPSFormat.toUTM(latitude, longitude)
|
||||||
|
DisplayConfig.GpsCoordinateFormat.MGRS_VALUE -> GPSFormat.toMGRS(latitude, longitude)
|
||||||
|
else -> GPSFormat.toDEC(latitude, longitude)
|
||||||
|
}
|
||||||
|
|
||||||
private fun TelemetryProtos.EnvironmentMetrics.getDisplayString(isFahrenheit: Boolean): String {
|
private fun TelemetryProtos.EnvironmentMetrics.getDisplayString(isFahrenheit: Boolean): String {
|
||||||
val temp = if (temperature != 0f) {
|
val temp = if (temperature != 0f) {
|
||||||
if (isFahrenheit) {
|
if (isFahrenheit) {
|
||||||
|
|
|
@ -186,8 +186,8 @@ class UIViewModel @Inject constructor(
|
||||||
private val _quickChatActions = MutableStateFlow<List<QuickChatAction>>(emptyList())
|
private val _quickChatActions = MutableStateFlow<List<QuickChatAction>>(emptyList())
|
||||||
val quickChatActions: StateFlow<List<QuickChatAction>> = _quickChatActions
|
val quickChatActions: StateFlow<List<QuickChatAction>> = _quickChatActions
|
||||||
|
|
||||||
private val _focusedNode = MutableStateFlow<NodeInfo?>(null)
|
private val _focusedNode = MutableStateFlow<NodeEntity?>(null)
|
||||||
val focusedNode: StateFlow<NodeInfo?> = _focusedNode
|
val focusedNode: StateFlow<NodeEntity?> = _focusedNode
|
||||||
|
|
||||||
private val nodeFilterText = MutableStateFlow("")
|
private val nodeFilterText = MutableStateFlow("")
|
||||||
private val nodeSortOption = MutableStateFlow(NodeSortOption.LAST_HEARD)
|
private val nodeSortOption = MutableStateFlow(NodeSortOption.LAST_HEARD)
|
||||||
|
@ -747,7 +747,7 @@ class UIViewModel @Inject constructor(
|
||||||
_currentTab.value = tab
|
_currentTab.value = tab
|
||||||
}
|
}
|
||||||
|
|
||||||
fun focusUserNode(node: NodeInfo?) {
|
fun focusUserNode(node: NodeEntity?) {
|
||||||
_currentTab.value = 1
|
_currentTab.value = 1
|
||||||
_focusedNode.value = node
|
_focusedNode.value = node
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import com.geeksville.mesh.DataPacket
|
||||||
import com.geeksville.mesh.android.Logging
|
import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.database.entity.QuickChatAction
|
import com.geeksville.mesh.database.entity.QuickChatAction
|
||||||
import com.geeksville.mesh.database.entity.toNodeInfo
|
|
||||||
import com.geeksville.mesh.databinding.MessagesFragmentBinding
|
import com.geeksville.mesh.databinding.MessagesFragmentBinding
|
||||||
import com.geeksville.mesh.model.Message
|
import com.geeksville.mesh.model.Message
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
|
@ -297,7 +296,7 @@ class MessagesFragment : Fragment(), Logging {
|
||||||
private fun openNodeInfo(msg: Message) = lifecycleScope.launch {
|
private fun openNodeInfo(msg: Message) = lifecycleScope.launch {
|
||||||
model.nodeList.firstOrNull()?.find { it.user.id == msg.user.id }?.let { node ->
|
model.nodeList.firstOrNull()?.find { it.user.id == msg.user.id }?.let { node ->
|
||||||
parentFragmentManager.popBackStack()
|
parentFragmentManager.popBackStack()
|
||||||
model.focusUserNode(node.toNodeInfo())
|
model.focusUserNode(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import com.geeksville.mesh.DataPacket
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.android.Logging
|
import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.database.entity.NodeEntity
|
import com.geeksville.mesh.database.entity.NodeEntity
|
||||||
import com.geeksville.mesh.database.entity.toNodeInfo
|
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
import com.geeksville.mesh.ui.components.NodeFilterTextField
|
import com.geeksville.mesh.ui.components.NodeFilterTextField
|
||||||
import com.geeksville.mesh.ui.components.rememberTimeTickWithLifecycle
|
import com.geeksville.mesh.ui.components.rememberTimeTickWithLifecycle
|
||||||
|
@ -175,7 +174,6 @@ fun NodesScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
items(nodes, key = { it.num }) { node ->
|
items(nodes, key = { it.num }) { node ->
|
||||||
val nodeInfo = node.toNodeInfo()
|
|
||||||
NodeItem(
|
NodeItem(
|
||||||
thisNode = ourNode,
|
thisNode = ourNode,
|
||||||
thatNode = node,
|
thatNode = node,
|
||||||
|
@ -187,7 +185,7 @@ fun NodesScreen(
|
||||||
focusManager.clearFocus()
|
focusManager.clearFocus()
|
||||||
chipClicked(node)
|
chipClicked(node)
|
||||||
},
|
},
|
||||||
blinking = nodeInfo == focusedNode,
|
blinking = node == focusedNode,
|
||||||
expanded = state.showDetails,
|
expanded = state.showDetails,
|
||||||
currentTimeMillis = currentTimeMillis,
|
currentTimeMillis = currentTimeMillis,
|
||||||
)
|
)
|
||||||
|
|
|
@ -38,7 +38,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.geeksville.mesh.BuildConfig
|
import com.geeksville.mesh.BuildConfig
|
||||||
import com.geeksville.mesh.DataPacket
|
import com.geeksville.mesh.DataPacket
|
||||||
import com.geeksville.mesh.MeshProtos.Waypoint
|
import com.geeksville.mesh.MeshProtos.Waypoint
|
||||||
import com.geeksville.mesh.NodeInfo
|
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.android.BuildUtils.debug
|
import com.geeksville.mesh.android.BuildUtils.debug
|
||||||
import com.geeksville.mesh.android.Logging
|
import com.geeksville.mesh.android.Logging
|
||||||
|
@ -47,8 +46,8 @@ import com.geeksville.mesh.android.gpsDisabled
|
||||||
import com.geeksville.mesh.android.hasGps
|
import com.geeksville.mesh.android.hasGps
|
||||||
import com.geeksville.mesh.android.hasLocationPermission
|
import com.geeksville.mesh.android.hasLocationPermission
|
||||||
import com.geeksville.mesh.copy
|
import com.geeksville.mesh.copy
|
||||||
|
import com.geeksville.mesh.database.entity.NodeEntity
|
||||||
import com.geeksville.mesh.database.entity.Packet
|
import com.geeksville.mesh.database.entity.Packet
|
||||||
import com.geeksville.mesh.database.entity.toNodeInfo
|
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
import com.geeksville.mesh.model.map.CustomTileSource
|
import com.geeksville.mesh.model.map.CustomTileSource
|
||||||
import com.geeksville.mesh.model.map.MarkerWithLabel
|
import com.geeksville.mesh.model.map.MarkerWithLabel
|
||||||
|
@ -61,8 +60,6 @@ import com.geeksville.mesh.util.zoomIn
|
||||||
import com.geeksville.mesh.waypoint
|
import com.geeksville.mesh.waypoint
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
|
||||||
import org.osmdroid.bonuspack.utils.BonusPackHelper.getBitmapFromVectorDrawable
|
import org.osmdroid.bonuspack.utils.BonusPackHelper.getBitmapFromVectorDrawable
|
||||||
import org.osmdroid.config.Configuration
|
import org.osmdroid.config.Configuration
|
||||||
import org.osmdroid.events.DelayedMapListener
|
import org.osmdroid.events.DelayedMapListener
|
||||||
|
@ -330,10 +327,7 @@ fun MapView(
|
||||||
if (permissions.entries.all { it.value }) map.toggleMyLocation()
|
if (permissions.entries.all { it.value }) map.toggleMyLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
val nodes by model.nodeList.collectAsStateWithLifecycle()
|
||||||
val nodes by model.nodeList
|
|
||||||
.mapLatest { list -> list.map { it.toNodeInfo() } }
|
|
||||||
.collectAsStateWithLifecycle(emptyList())
|
|
||||||
val waypoints by model.waypoints.collectAsStateWithLifecycle(emptyMap())
|
val waypoints by model.waypoints.collectAsStateWithLifecycle(emptyMap())
|
||||||
|
|
||||||
var showDownloadButton: Boolean by remember { mutableStateOf(false) }
|
var showDownloadButton: Boolean by remember { mutableStateOf(false) }
|
||||||
|
@ -344,21 +338,21 @@ fun MapView(
|
||||||
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_location_on_24)
|
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_location_on_24)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MapView.onNodesChanged(nodes: Collection<NodeInfo>): List<MarkerWithLabel> {
|
fun MapView.onNodesChanged(nodes: Collection<NodeEntity>): List<MarkerWithLabel> {
|
||||||
val nodesWithPosition = nodes.filter { it.validPosition != null }
|
val nodesWithPosition = nodes.filter { it.validPosition != null }
|
||||||
val ourNode = model.ourNodeInfo.value?.toNodeInfo()
|
val ourNode = model.ourNodeInfo.value
|
||||||
val gpsFormat = model.config.display.gpsFormat.number
|
val gpsFormat = model.config.display.gpsFormat.number
|
||||||
val displayUnits = model.config.display.units.number
|
val displayUnits = model.config.display.units.number
|
||||||
return nodesWithPosition.map { node ->
|
return nodesWithPosition.map { node ->
|
||||||
val (p, u) = node.position!! to node.user!!
|
val (p, u) = node.position to node.user
|
||||||
val nodePosition = GeoPoint(p.latitude, p.longitude)
|
val nodePosition = GeoPoint(node.latitude, node.longitude)
|
||||||
MarkerWithLabel(
|
MarkerWithLabel(
|
||||||
mapView = this,
|
mapView = this,
|
||||||
label = "${u.shortName} ${formatAgo(p.time)}"
|
label = "${u.shortName} ${formatAgo(p.time)}"
|
||||||
).apply {
|
).apply {
|
||||||
id = u.id
|
id = u.id
|
||||||
title = "${u.longName} ${node.batteryStr}"
|
title = "${u.longName} ${node.batteryStr}"
|
||||||
snippet = p.gpsString(gpsFormat)
|
snippet = node.gpsString(gpsFormat)
|
||||||
ourNode?.distanceStr(node, displayUnits)?.let { dist ->
|
ourNode?.distanceStr(node, displayUnits)?.let { dist ->
|
||||||
subDescription =
|
subDescription =
|
||||||
context.getString(R.string.map_subDescription, ourNode.bearing(node), dist)
|
context.getString(R.string.map_subDescription, ourNode.bearing(node), dist)
|
||||||
|
|
Ładowanie…
Reference in New Issue