diff --git a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt index 145767a97..783390d81 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt @@ -41,6 +41,7 @@ import com.geeksville.mesh.database.entity.MeshLog import com.geeksville.mesh.model.map.CustomTileSource import com.geeksville.mesh.navigation.Route import com.geeksville.mesh.repository.datastore.RadioConfigRepository +import com.geeksville.mesh.service.ServiceAction import com.geeksville.mesh.ui.map.MAP_STYLE_ID import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -66,6 +67,7 @@ import java.util.concurrent.TimeUnit import javax.inject.Inject data class MetricsState( + val isLocal: Boolean = false, val isManaged: Boolean = true, val isFahrenheit: Boolean = false, val displayUnits: DisplayUnits = DisplayUnits.METRIC, @@ -214,6 +216,10 @@ class MetricsViewModel @Inject constructor( } } + fun onServiceAction(action: ServiceAction) = viewModelScope.launch { + radioConfigRepository.onServiceAction(action) + } + private val _state = MutableStateFlow(MetricsState.Empty) val state: StateFlow = _state @@ -228,10 +234,10 @@ class MetricsViewModel @Inject constructor( init { destNum?.let { radioConfigRepository.nodeDBbyNum - .mapLatest { nodes -> nodes[destNum] } + .mapLatest { nodes -> nodes[destNum] to nodes.keys.firstOrNull() } .distinctUntilChanged() - .onEach { node -> - _state.update { state -> state.copy(node = node) } + .onEach { (node, ourNode) -> + _state.update { state -> state.copy(node = node, isLocal = destNum == ourNode) } node?.user?.hwModel?.let { hwModel -> val deviceHardware = getDeviceHardwareFromHardwareModel(hwModel) deviceHardware?.let { diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt index 87653925e..eb00668c4 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt @@ -98,6 +98,7 @@ import com.geeksville.mesh.model.Node import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.model.isUnmessageableRole import com.geeksville.mesh.navigation.Route +import com.geeksville.mesh.service.ServiceAction import com.geeksville.mesh.ui.components.PreferenceCategory import com.geeksville.mesh.ui.preview.NodePreviewParameterProvider import com.geeksville.mesh.ui.radioconfig.NavCard @@ -158,7 +159,12 @@ fun NodeDetailScreen( NodeDetailList( node = node, metricsState = state, - onNavigate = onNavigate, + onAction = { action -> + when (action) { + is Route -> onNavigate(action) + is ServiceAction -> viewModel.onServiceAction(action) + } + }, modifier = modifier, metricsAvailability = availabilities, onShared = { @@ -181,7 +187,7 @@ private fun NodeDetailList( modifier: Modifier = Modifier, node: Node, metricsState: MetricsState, - onNavigate: (Route) -> Unit = {}, + onAction: (Any) -> Unit = {}, metricsAvailability: BooleanArray, onShared: () -> Unit = {} ) { @@ -203,11 +209,11 @@ private fun NodeDetailList( } item { - NavCard( - title = stringResource(id = R.string.share_contact), - icon = Icons.Default.Share, - enabled = true, - onClick = onShared + DeviceActions( + isLocal = metricsState.isLocal, + node = node, + onShared = onShared, + onAction = onAction ) } @@ -236,7 +242,7 @@ private fun NodeDetailList( icon = type.icon, enabled = metricsAvailability[type.ordinal] ) { - onNavigate(type.route) + onAction(type.route) } } } @@ -249,7 +255,7 @@ private fun NodeDetailList( icon = Icons.Default.Settings, enabled = true ) { - onNavigate(Route.RadioConfig(node.num)) + onAction(Route.RadioConfig(node.num)) } } } @@ -282,6 +288,31 @@ private fun NodeDetailRow( } } +@Composable +private fun DeviceActions( + isLocal: Boolean = false, + node: Node, + onShared: () -> Unit, + onAction: (ServiceAction) -> Unit, +) { + PreferenceCategory(text = stringResource(R.string.actions)) + NavCard( + title = stringResource(id = R.string.share_contact), + icon = Icons.Default.Share, + enabled = true, + onClick = onShared + ) + + if (!isLocal) { + NavCard( + title = stringResource(id = R.string.request_metadata), + icon = Icons.Default.Memory, + enabled = true, + onClick = { onAction(ServiceAction.GetDeviceMetadata(node.num)) } + ) + } +} + @Composable private fun DeviceDetailsContent( state: MetricsState, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f0c8d30a8..c1ec0d62c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -626,4 +626,6 @@ Warning: This contact is known, importing will overwrite the previous contact information. Public Key Changed Import + Request Metadata + Actions diff --git a/config/detekt/detekt-baseline.xml b/config/detekt/detekt-baseline.xml index 6b459769c..880b55f84 100644 --- a/config/detekt/detekt-baseline.xml +++ b/config/detekt/detekt-baseline.xml @@ -2,6 +2,7 @@ TooManyFunctions:ContactSharing.kt$com.geeksville.mesh.ui.ContactSharing.kt + TooManyFunctions:NodeDetail.kt$com.geeksville.mesh.ui.NodeDetail.kt AbsentOrWrongFileLicense:LazyColumnDragAndDropDemo.kt$com.geeksville.mesh.ui.components.LazyColumnDragAndDropDemo.kt