kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor: move node detail logs to shared ViewModel
rodzic
e7b30597b7
commit
b668a21b68
|
@ -38,6 +38,7 @@ import androidx.compose.material.icons.filled.Usb
|
||||||
import androidx.compose.material.icons.filled.Wifi
|
import androidx.compose.material.icons.filled.Wifi
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
|
@ -129,20 +130,11 @@ class NavGraphFragment : ScreenFragment("NavGraph"), Logging {
|
||||||
|
|
||||||
AppCompatTheme {
|
AppCompatTheme {
|
||||||
val navController: NavHostController = rememberNavController()
|
val navController: NavHostController = rememberNavController()
|
||||||
// Get current back stack entry
|
|
||||||
// val backStackEntry by navController.currentBackStackEntryAsState()
|
|
||||||
// Get the name of the current screen
|
|
||||||
// val currentScreen = backStackEntry?.destination?.route?.let { route ->
|
|
||||||
// NavRoute.entries.find { it.name == route }?.title
|
|
||||||
// }
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
MeshAppBar(
|
MeshAppBar(
|
||||||
currentScreen = node?.user?.longName
|
currentScreen = node?.user?.longName
|
||||||
?: stringResource(R.string.unknown_username),
|
?: stringResource(R.string.unknown_username),
|
||||||
// canNavigateBack = navController.previousBackStackEntry != null,
|
|
||||||
// navigateUp = { navController.navigateUp() },
|
|
||||||
canNavigateBack = true,
|
canNavigateBack = true,
|
||||||
navigateUp = {
|
navigateUp = {
|
||||||
if (navController.previousBackStackEntry != null) {
|
if (navController.previousBackStackEntry != null) {
|
||||||
|
@ -233,7 +225,7 @@ private fun MeshAppBar(
|
||||||
IconButton(onClick = navigateUp) {
|
IconButton(onClick = navigateUp) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
null,
|
contentDescription = stringResource(id = R.string.navigate_back),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,9 +248,6 @@ fun NavGraph(
|
||||||
val radioConfigState by viewModel.radioConfigState.collectAsStateWithLifecycle()
|
val radioConfigState by viewModel.radioConfigState.collectAsStateWithLifecycle()
|
||||||
val isWaiting = radioConfigState.responseState.isWaiting()
|
val isWaiting = radioConfigState.responseState.isWaiting()
|
||||||
|
|
||||||
val metricsViewModel: MetricsViewModel = hiltViewModel()
|
|
||||||
val metricsState by metricsViewModel.state.collectAsStateWithLifecycle()
|
|
||||||
|
|
||||||
if (isWaiting) {
|
if (isWaiting) {
|
||||||
PacketResponseStateDialog(
|
PacketResponseStateDialog(
|
||||||
state = radioConfigState.responseState,
|
state = radioConfigState.responseState,
|
||||||
|
@ -282,27 +271,25 @@ fun NavGraph(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
composable("NodeDetails") {
|
composable("NodeDetails") {
|
||||||
NodeDetailsScreen(
|
NodeDetailScreen(
|
||||||
node = node,
|
node = node,
|
||||||
metricsState = metricsState,
|
) { navController.navigate(route = it) }
|
||||||
onNavigate = { navController.navigate(route = it) },
|
|
||||||
setSelectedNode = metricsViewModel::setSelectedNode,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
composable("DeviceMetrics") {
|
composable("DeviceMetrics") {
|
||||||
DeviceMetricsScreen(metricsState.deviceMetrics)
|
val parentEntry = remember { navController.getBackStackEntry("NodeDetails") }
|
||||||
|
DeviceMetricsScreen(hiltViewModel<MetricsViewModel>(parentEntry))
|
||||||
}
|
}
|
||||||
composable("EnvironmentMetrics") {
|
composable("EnvironmentMetrics") {
|
||||||
EnvironmentMetricsScreen(
|
val parentEntry = remember { navController.getBackStackEntry("NodeDetails") }
|
||||||
metricsState.environmentMetrics,
|
EnvironmentMetricsScreen(hiltViewModel<MetricsViewModel>(parentEntry))
|
||||||
metricsState.environmentDisplayFahrenheit,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
composable("TracerouteList") {
|
|
||||||
TracerouteLogScreen(metricsViewModel)
|
|
||||||
}
|
}
|
||||||
composable("SignalMetrics") {
|
composable("SignalMetrics") {
|
||||||
SignalMetricsScreen(metricsState.signalMetrics)
|
val parentEntry = remember { navController.getBackStackEntry("NodeDetails") }
|
||||||
|
SignalMetricsScreen(hiltViewModel<MetricsViewModel>(parentEntry))
|
||||||
|
}
|
||||||
|
composable("TracerouteList") {
|
||||||
|
val parentEntry = remember { navController.getBackStackEntry("NodeDetails") }
|
||||||
|
TracerouteLogScreen(hiltViewModel<MetricsViewModel>(parentEntry))
|
||||||
}
|
}
|
||||||
composable("RadioConfig") {
|
composable("RadioConfig") {
|
||||||
RadioConfigScreen(
|
RadioConfigScreen(
|
||||||
|
|
|
@ -46,6 +46,7 @@ import androidx.compose.material.icons.filled.WaterDrop
|
||||||
import androidx.compose.material.icons.filled.Work
|
import androidx.compose.material.icons.filled.Work
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -56,9 +57,12 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.database.entity.NodeEntity
|
import com.geeksville.mesh.database.entity.NodeEntity
|
||||||
import com.geeksville.mesh.model.MetricsState
|
import com.geeksville.mesh.model.MetricsState
|
||||||
|
import com.geeksville.mesh.model.MetricsViewModel
|
||||||
import com.geeksville.mesh.ui.components.PreferenceCategory
|
import com.geeksville.mesh.ui.components.PreferenceCategory
|
||||||
import com.geeksville.mesh.ui.preview.NodeEntityPreviewParameterProvider
|
import com.geeksville.mesh.ui.preview.NodeEntityPreviewParameterProvider
|
||||||
import com.geeksville.mesh.ui.theme.AppTheme
|
import com.geeksville.mesh.ui.theme.AppTheme
|
||||||
|
@ -67,21 +71,21 @@ import java.util.concurrent.TimeUnit
|
||||||
import kotlin.math.ln
|
import kotlin.math.ln
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NodeDetailsScreen(
|
fun NodeDetailScreen(
|
||||||
node: NodeEntity?,
|
node: NodeEntity?,
|
||||||
metricsState: MetricsState,
|
viewModel: MetricsViewModel = hiltViewModel(),
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onNavigate: (String) -> Unit,
|
onNavigate: (String) -> Unit,
|
||||||
setSelectedNode: (Int) -> Unit,
|
|
||||||
) {
|
) {
|
||||||
|
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
LaunchedEffect(node.num) {
|
LaunchedEffect(node.num) {
|
||||||
setSelectedNode(node.num)
|
viewModel.setSelectedNode(node.num)
|
||||||
}
|
}
|
||||||
|
NodeDetailList(
|
||||||
NodeDetailsItemList(
|
|
||||||
node = node,
|
node = node,
|
||||||
metricsState = metricsState,
|
metricsState = state,
|
||||||
onNavigate = onNavigate,
|
onNavigate = onNavigate,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
|
@ -97,7 +101,7 @@ fun NodeDetailsScreen(
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
private fun NodeDetailsItemList(
|
private fun NodeDetailList(
|
||||||
node: NodeEntity,
|
node: NodeEntity,
|
||||||
metricsState: MetricsState,
|
metricsState: MetricsState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
@ -453,6 +457,6 @@ private fun NodeDetailsPreview(
|
||||||
node: NodeEntity
|
node: NodeEntity
|
||||||
) {
|
) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
NodeDetailsItemList(node, MetricsState.Empty)
|
NodeDetailList(node, MetricsState.Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -34,8 +34,11 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.TelemetryProtos.Telemetry
|
import com.geeksville.mesh.TelemetryProtos.Telemetry
|
||||||
|
import com.geeksville.mesh.model.MetricsViewModel
|
||||||
import com.geeksville.mesh.ui.BatteryInfo
|
import com.geeksville.mesh.ui.BatteryInfo
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.X_AXIS_SPACING
|
import com.geeksville.mesh.ui.components.CommonCharts.X_AXIS_SPACING
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
|
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
|
||||||
|
@ -56,8 +59,10 @@ private val LEGEND_DATA = listOf(
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DeviceMetricsScreen(telemetries: List<Telemetry>) {
|
fun DeviceMetricsScreen(
|
||||||
|
viewModel: MetricsViewModel = hiltViewModel(),
|
||||||
|
) {
|
||||||
|
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||||
var displayInfoDialog by remember { mutableStateOf(false) }
|
var displayInfoDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
@ -76,14 +81,14 @@ fun DeviceMetricsScreen(telemetries: List<Telemetry>) {
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.fillMaxHeight(fraction = 0.33f),
|
.fillMaxHeight(fraction = 0.33f),
|
||||||
telemetries.reversed(),
|
state.deviceMetrics.reversed(),
|
||||||
promptInfoDialog = { displayInfoDialog = true }
|
promptInfoDialog = { displayInfoDialog = true }
|
||||||
)
|
)
|
||||||
/* Device Metric Cards */
|
/* Device Metric Cards */
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
items(telemetries) { telemetry -> DeviceMetricsCard(telemetry) }
|
items(state.deviceMetrics) { telemetry -> DeviceMetricsCard(telemetry) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,12 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.TelemetryProtos.Telemetry
|
import com.geeksville.mesh.TelemetryProtos.Telemetry
|
||||||
import com.geeksville.mesh.copy
|
import com.geeksville.mesh.copy
|
||||||
|
import com.geeksville.mesh.model.MetricsViewModel
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.X_AXIS_SPACING
|
import com.geeksville.mesh.ui.components.CommonCharts.X_AXIS_SPACING
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
|
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.TIME_FORMAT
|
import com.geeksville.mesh.ui.components.CommonCharts.TIME_FORMAT
|
||||||
|
@ -69,15 +72,19 @@ private val LEGEND_DATA = listOf(
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EnvironmentMetricsScreen(telemetries: List<Telemetry>, environmentDisplayFahrenheit: Boolean) {
|
fun EnvironmentMetricsScreen(
|
||||||
|
viewModel: MetricsViewModel = hiltViewModel(),
|
||||||
|
) {
|
||||||
|
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
/* Convert Celsius to Fahrenheit */
|
/* Convert Celsius to Fahrenheit */
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
fun celsiusToFahrenheit(celsius: Float): Float {
|
fun celsiusToFahrenheit(celsius: Float): Float {
|
||||||
return (celsius * 1.8F) + 32
|
return (celsius * 1.8F) + 32
|
||||||
}
|
}
|
||||||
|
|
||||||
val processedTelemetries: List<Telemetry> = if (environmentDisplayFahrenheit) {
|
val processedTelemetries: List<Telemetry> = if (state.environmentDisplayFahrenheit) {
|
||||||
telemetries.map { telemetry ->
|
state.environmentMetrics.map { telemetry ->
|
||||||
val temperatureFahrenheit =
|
val temperatureFahrenheit =
|
||||||
celsiusToFahrenheit(telemetry.environmentMetrics.temperature)
|
celsiusToFahrenheit(telemetry.environmentMetrics.temperature)
|
||||||
telemetry.copy {
|
telemetry.copy {
|
||||||
|
@ -86,7 +93,7 @@ fun EnvironmentMetricsScreen(telemetries: List<Telemetry>, environmentDisplayFah
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
telemetries
|
state.environmentMetrics
|
||||||
}
|
}
|
||||||
|
|
||||||
var displayInfoDialog by remember { mutableStateOf(false) }
|
var displayInfoDialog by remember { mutableStateOf(false) }
|
||||||
|
@ -117,7 +124,7 @@ fun EnvironmentMetricsScreen(telemetries: List<Telemetry>, environmentDisplayFah
|
||||||
items(processedTelemetries) { telemetry ->
|
items(processedTelemetries) { telemetry ->
|
||||||
EnvironmentMetricsCard(
|
EnvironmentMetricsCard(
|
||||||
telemetry,
|
telemetry,
|
||||||
environmentDisplayFahrenheit
|
state.environmentDisplayFahrenheit
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,11 @@ import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.geeksville.mesh.MeshProtos.MeshPacket
|
import com.geeksville.mesh.MeshProtos.MeshPacket
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
|
import com.geeksville.mesh.model.MetricsViewModel
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
|
import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.LINE_LIMIT
|
import com.geeksville.mesh.ui.components.CommonCharts.LINE_LIMIT
|
||||||
import com.geeksville.mesh.ui.components.CommonCharts.TEXT_PAINT_ALPHA
|
import com.geeksville.mesh.ui.components.CommonCharts.TEXT_PAINT_ALPHA
|
||||||
|
@ -61,8 +64,10 @@ private val LEGEND_DATA = listOf(
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SignalMetricsScreen(meshPackets: List<MeshPacket>) {
|
fun SignalMetricsScreen(
|
||||||
|
viewModel: MetricsViewModel = hiltViewModel(),
|
||||||
|
) {
|
||||||
|
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||||
var displayInfoDialog by remember { mutableStateOf(false) }
|
var displayInfoDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
@ -81,14 +86,14 @@ fun SignalMetricsScreen(meshPackets: List<MeshPacket>) {
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.fillMaxHeight(fraction = 0.33f),
|
.fillMaxHeight(fraction = 0.33f),
|
||||||
meshPackets = meshPackets.reversed(),
|
meshPackets = state.signalMetrics.reversed(),
|
||||||
promptInfoDialog = { displayInfoDialog = true }
|
promptInfoDialog = { displayInfoDialog = true }
|
||||||
)
|
)
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
items(meshPackets) { meshPacket -> SignalMetricsCard(meshPacket) }
|
items(state.signalMetrics) { meshPacket -> SignalMetricsCard(meshPacket) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue