diff --git a/app/src/main/java/com/geeksville/mesh/model/NodeDetailsViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt similarity index 86% rename from app/src/main/java/com/geeksville/mesh/model/NodeDetailsViewModel.kt rename to app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt index 576fcc667..256049861 100644 --- a/app/src/main/java/com/geeksville/mesh/model/NodeDetailsViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt @@ -16,27 +16,27 @@ import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.enums.EnumEntries -enum class NodeDetailPage( +enum class MetricsPage( @StringRes val titleResId: Int, @DrawableRes val drawableResId: Int, ) { - DEVICE(R.string.device_metrics, R.drawable.baseline_charging_station_24), - ENVIRONMENT(R.string.environment_metrics, R.drawable.baseline_thermostat_24), + DEVICE(R.string.device, R.drawable.baseline_charging_station_24), + ENVIRONMENT(R.string.environment, R.drawable.baseline_thermostat_24), } -data class NodeDetailsState( - val pages: EnumEntries = NodeDetailPage.entries, +data class MetricsState( + val pages: EnumEntries = MetricsPage.entries, val isLoading: Boolean = false, val deviceMetrics: List = emptyList(), val environmentMetrics: List = emptyList(), ) { companion object { - val Empty = NodeDetailsState() + val Empty = MetricsState() } } @HiltViewModel -class NodeDetailsViewModel @Inject constructor( +class MetricsViewModel @Inject constructor( val nodeDB: NodeDB, private val meshLogRepository: MeshLogRepository ) : ViewModel() { @@ -50,7 +50,7 @@ class NodeDetailsViewModel @Inject constructor( _deviceMetrics, _environmentMetrics, ) { isLoading, device, environment -> - NodeDetailsState( + MetricsState( isLoading = isLoading, deviceMetrics = device, environmentMetrics = environment, @@ -58,7 +58,7 @@ class NodeDetailsViewModel @Inject constructor( }.stateIn( scope = viewModelScope, started = WhileSubscribed(5_000), - initialValue = NodeDetailsState.Empty, + initialValue = MetricsState.Empty, ) /** diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeDetailsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/MetricsFragment.kt similarity index 85% rename from app/src/main/java/com/geeksville/mesh/ui/NodeDetailsFragment.kt rename to app/src/main/java/com/geeksville/mesh/ui/MetricsFragment.kt index 5936f2e7e..3540c374d 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NodeDetailsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MetricsFragment.kt @@ -41,29 +41,29 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.geeksville.mesh.R import com.geeksville.mesh.android.Logging -import com.geeksville.mesh.model.NodeDetailPage -import com.geeksville.mesh.model.NodeDetailsState -import com.geeksville.mesh.model.NodeDetailsViewModel +import com.geeksville.mesh.model.MetricsPage +import com.geeksville.mesh.model.MetricsState +import com.geeksville.mesh.model.MetricsViewModel import com.geeksville.mesh.ui.components.DeviceMetricsScreen import com.geeksville.mesh.ui.components.EnvironmentMetricsScreen import com.geeksville.mesh.ui.theme.AppTheme import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch -internal fun FragmentManager.navigateToNodeDetails(nodeNum: Int? = null) { - val nodeDetailsFragment = NodeDetailsFragment().apply { +internal fun FragmentManager.navigateToMetrics(nodeNum: Int? = null) { + val metricsFragment = MetricsFragment().apply { arguments = bundleOf("nodeNum" to nodeNum) } beginTransaction() - .replace(R.id.mainActivityLayout, nodeDetailsFragment) + .replace(R.id.mainActivityLayout, metricsFragment) .addToBackStack(null) .commit() } @AndroidEntryPoint -class NodeDetailsFragment : ScreenFragment("NodeDetails"), Logging { +class MetricsFragment : ScreenFragment("Metrics"), Logging { - private val model: NodeDetailsViewModel by viewModels() + private val model: MetricsViewModel by viewModels() override fun onCreateView( inflater: LayoutInflater, @@ -80,7 +80,7 @@ class NodeDetailsFragment : ScreenFragment("NodeDetails"), Logging { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { AppTheme { - NodeDetailsScreen( + MetricsScreen( model = model, nodeName = nodeName, navigateBack = { @@ -95,8 +95,8 @@ class NodeDetailsFragment : ScreenFragment("NodeDetails"), Logging { @OptIn(ExperimentalFoundationApi::class) @Composable -fun NodeDetailsScreen( - model: NodeDetailsViewModel = hiltViewModel(), +fun MetricsScreen( + model: MetricsViewModel = hiltViewModel(), nodeName: String?, navigateBack: () -> Unit, ) { @@ -113,7 +113,7 @@ fun NodeDetailsScreen( contentColor = colorResource(R.color.toolbarText), title = { Text( - text = "${stringResource(R.string.node_details)}: $nodeName", + text = "${stringResource(R.string.metrics)}: $nodeName", ) }, navigationIcon = { @@ -127,7 +127,7 @@ fun NodeDetailsScreen( ) }, ) { innerPadding -> - NodeDetailsPagerScreen( + MetricsPagerScreen( state = state, pagerState = pagerState, modifier = Modifier.padding(top = innerPadding.calculateTopPadding()) @@ -137,8 +137,8 @@ fun NodeDetailsScreen( @OptIn(ExperimentalFoundationApi::class) @Composable -fun NodeDetailsPagerScreen( - state: NodeDetailsState, +fun MetricsPagerScreen( + state: MetricsState, pagerState: PagerState, modifier: Modifier = Modifier, ) = with(state) { @@ -178,8 +178,8 @@ fun NodeDetailsPagerScreen( } } else { when (pages[index]) { - NodeDetailPage.DEVICE -> DeviceMetricsScreen(deviceMetrics) - NodeDetailPage.ENVIRONMENT -> EnvironmentMetricsScreen(environmentMetrics) + MetricsPage.DEVICE -> DeviceMetricsScreen(deviceMetrics) + MetricsPage.ENVIRONMENT -> EnvironmentMetricsScreen(environmentMetrics) } } } @@ -189,10 +189,10 @@ fun NodeDetailsPagerScreen( @OptIn(ExperimentalFoundationApi::class) @PreviewLightDark @Composable -private fun NodeDetailsPreview() { +private fun MetricsPreview() { AppTheme { - val state = NodeDetailsState.Empty - NodeDetailsPagerScreen( + val state = MetricsState.Empty + MetricsPagerScreen( state = state, pagerState = rememberPagerState(pageCount = { state.pages.size }), ) diff --git a/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt b/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt index eca3c3add..046128cfa 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt @@ -4,10 +4,12 @@ import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewParameter import com.geeksville.mesh.NodeInfo +import com.geeksville.mesh.R import com.geeksville.mesh.ui.preview.NodeInfoPreviewParameterProvider import com.geeksville.mesh.ui.theme.AppTheme @@ -18,7 +20,7 @@ fun signalInfo( isThisNode: Boolean ): Boolean { val text = if (isThisNode) { - "ChUtil %.1f%% AirUtilTX %.1f%%".format( + stringResource(R.string.channel_air_util).format( nodeInfo.deviceMetrics?.channelUtilization, nodeInfo.deviceMetrics?.airUtilTx ) @@ -30,7 +32,7 @@ fun signalInfo( add("RSSI: %d SNR: %.1f".format(nodeInfo.rssi, nodeInfo.snr)) } } else { - add("Hops Away: %d".format(nodeInfo.hopsAway)) + add("%s: %d".format(stringResource(R.string.hops_away), nodeInfo.hopsAway)) } }.joinToString(" ") } diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index 9384f5042..2e9d509ab 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -83,8 +83,8 @@ class UsersFragment : ScreenFragment("Users"), Logging { navigateToRadioConfig(node) } - R.id.more_details -> { - navigateToMoreDetails(node) + R.id.metrics -> { + navigateToMetrics(node) } } } @@ -101,9 +101,9 @@ class UsersFragment : ScreenFragment("Users"), Logging { parentFragmentManager.navigateToRadioConfig(node.num) } - private fun navigateToMoreDetails(node: NodeInfo) { - info("calling MoreDetails --> destNum: ${node.num}") - parentFragmentManager.navigateToNodeDetails(node.num) + private fun navigateToMetrics(node: NodeInfo) { + info("calling Metrics --> destNum: ${node.num}") + parentFragmentManager.navigateToMetrics(node.num) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/CustomCharts.kt b/app/src/main/java/com/geeksville/mesh/ui/components/CustomCharts.kt index 4946d3dd8..1e5e6c93c 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/CustomCharts.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/CustomCharts.kt @@ -116,7 +116,7 @@ fun EnvironmentMetricsScreen(telemetries: List) { @Composable private fun DeviceMetricsChart(modifier: Modifier = Modifier, telemetries: List) { - ChartHeader(amount = telemetries.size, title = stringResource(R.string.device_metrics)) + ChartHeader(amount = telemetries.size) if (telemetries.isEmpty()) return @@ -205,7 +205,7 @@ private fun DeviceMetricsChart(modifier: Modifier = Modifier, telemetries: List< @Composable private fun EnvironmentMetricsChart(modifier: Modifier = Modifier, telemetries: List) { - ChartHeader(amount = telemetries.size, title = stringResource(R.string.environment_metrics)) + ChartHeader(amount = telemetries.size) if (telemetries.isEmpty()) return @@ -406,10 +406,8 @@ private fun DeviceMetricsCard(telemetry: Telemetry) { modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { - val text = "%s %.2f%% %s %.2f%%".format( - stringResource(R.string.channel_utilization), + val text = stringResource(R.string.channel_air_util).format( deviceMetrics.channelUtilization, - stringResource(R.string.air_utilization), deviceMetrics.airUtilTx ) Text( @@ -493,14 +491,14 @@ private fun EnvironmentMetricsCard(telemetry: Telemetry) { } @Composable -private fun ChartHeader(amount: Int, title: String) { +private fun ChartHeader(amount: Int) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( - text = "$amount $title", + text = "$amount ${stringResource(R.string.logs)}", modifier = Modifier.wrapContentWidth(), style = TextStyle(fontWeight = FontWeight.Bold), fontSize = MaterialTheme.typography.button.fontSize diff --git a/app/src/main/res/menu/menu_nodes.xml b/app/src/main/res/menu/menu_nodes.xml index 1a5e6869a..5e0b0b87d 100644 --- a/app/src/main/res/menu/menu_nodes.xml +++ b/app/src/main/res/menu/menu_nodes.xml @@ -32,8 +32,8 @@ \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eda7a53a3..3e6901ec3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,9 +25,8 @@ Last heard via MQTT - More Details - MSL + ChUtil %.1f%% AirUtilTX %.1f%% Channel Name Channel options @@ -221,9 +220,11 @@ Battery Channel Utilization Air Utilization - Device Metrics - Node Details - Environment Metrics + Device + Metrics + Environment Temperature Humidity + Logs + Hops Away