kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor(config): extract screen logic from `NavHost`
rodzic
42f9ef24fd
commit
d10b58073c
|
@ -65,6 +65,7 @@ import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.config
|
import com.geeksville.mesh.config
|
||||||
import com.geeksville.mesh.database.entity.NodeEntity
|
import com.geeksville.mesh.database.entity.NodeEntity
|
||||||
import com.geeksville.mesh.model.Channel
|
import com.geeksville.mesh.model.Channel
|
||||||
|
import com.geeksville.mesh.model.RadioConfigState
|
||||||
import com.geeksville.mesh.model.RadioConfigViewModel
|
import com.geeksville.mesh.model.RadioConfigViewModel
|
||||||
import com.geeksville.mesh.moduleConfig
|
import com.geeksville.mesh.moduleConfig
|
||||||
import com.geeksville.mesh.service.MeshService.ConnectionState
|
import com.geeksville.mesh.service.MeshService.ConnectionState
|
||||||
|
@ -239,107 +240,31 @@ private fun MeshAppBar(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
@Suppress("LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
fun RadioConfigNavHost(
|
fun RadioConfigNavHost(
|
||||||
node: NodeEntity?,
|
node: NodeEntity?,
|
||||||
viewModel: RadioConfigViewModel = hiltViewModel(),
|
viewModel: RadioConfigViewModel = hiltViewModel(),
|
||||||
navController: NavHostController = rememberNavController(),
|
navController: NavHostController = rememberNavController(),
|
||||||
modifier: Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
||||||
val connected = connectionState == ConnectionState.CONNECTED && node != null
|
val connected = connectionState == ConnectionState.CONNECTED && node != null
|
||||||
|
|
||||||
val isLocal = node?.num == viewModel.myNodeNum
|
|
||||||
|
|
||||||
val radioConfigState by viewModel.radioConfigState.collectAsStateWithLifecycle()
|
val radioConfigState by viewModel.radioConfigState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
val deviceProfile by viewModel.deviceProfile.collectAsStateWithLifecycle()
|
|
||||||
val isWaiting = radioConfigState.responseState.isWaiting()
|
|
||||||
var showEditDeviceProfileDialog by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
val importConfigLauncher = rememberLauncherForActivityResult(
|
|
||||||
ActivityResultContracts.StartActivityForResult()
|
|
||||||
) {
|
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
|
||||||
showEditDeviceProfileDialog = true
|
|
||||||
it.data?.data?.let { uri -> viewModel.importProfile(uri) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val exportConfigLauncher = rememberLauncherForActivityResult(
|
|
||||||
ActivityResultContracts.StartActivityForResult()
|
|
||||||
) {
|
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
|
||||||
it.data?.data?.let { uri -> viewModel.exportProfile(uri) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showEditDeviceProfileDialog) EditDeviceProfileDialog(
|
|
||||||
title = if (deviceProfile != null) "Import configuration" else "Export configuration",
|
|
||||||
deviceProfile = deviceProfile ?: viewModel.currentDeviceProfile,
|
|
||||||
onConfirm = {
|
|
||||||
showEditDeviceProfileDialog = false
|
|
||||||
if (deviceProfile != null) {
|
|
||||||
viewModel.installProfile(it)
|
|
||||||
} else {
|
|
||||||
viewModel.setDeviceProfile(it)
|
|
||||||
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
|
|
||||||
addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
type = "application/*"
|
|
||||||
putExtra(Intent.EXTRA_TITLE, "${node!!.num.toUInt()}.cfg")
|
|
||||||
}
|
|
||||||
exportConfigLauncher.launch(intent)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onDismiss = {
|
|
||||||
showEditDeviceProfileDialog = false
|
|
||||||
viewModel.setDeviceProfile(null)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isWaiting) PacketResponseStateDialog(
|
|
||||||
radioConfigState.responseState,
|
|
||||||
onDismiss = {
|
|
||||||
showEditDeviceProfileDialog = false
|
|
||||||
viewModel.clearPacketResponse()
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
val route = radioConfigState.route
|
|
||||||
if (ConfigRoute.entries.any { it.name == route } ||
|
|
||||||
ModuleRoute.entries.any { it.name == route }) {
|
|
||||||
navController.navigate(route)
|
|
||||||
viewModel.clearPacketResponse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = "home",
|
startDestination = "home",
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
composable("home") {
|
composable("home") {
|
||||||
RadioConfigItemList(
|
RadioConfigScreen(
|
||||||
enabled = connected && !isWaiting,
|
node = node,
|
||||||
isLocal = isLocal,
|
connected = connected,
|
||||||
onRouteClick = { route ->
|
radioConfigState = radioConfigState,
|
||||||
viewModel.setResponseStateLoading(route)
|
viewModel = viewModel,
|
||||||
},
|
onNavigate = { navController.navigate(route = it) },
|
||||||
onImport = {
|
|
||||||
viewModel.clearPacketResponse()
|
|
||||||
viewModel.setDeviceProfile(null)
|
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
|
||||||
addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
type = "application/*"
|
|
||||||
}
|
|
||||||
importConfigLauncher.launch(intent)
|
|
||||||
},
|
|
||||||
onExport = {
|
|
||||||
viewModel.clearPacketResponse()
|
|
||||||
viewModel.setDeviceProfile(null)
|
|
||||||
showEditDeviceProfileDialog = true
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(ConfigRoute.USER.name) {
|
composable(ConfigRoute.USER.name) {
|
||||||
|
@ -606,6 +531,106 @@ fun RadioConfigNavHost(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
|
@Composable
|
||||||
|
fun RadioConfigScreen(
|
||||||
|
node: NodeEntity?,
|
||||||
|
connected: Boolean,
|
||||||
|
radioConfigState: RadioConfigState,
|
||||||
|
viewModel: RadioConfigViewModel,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onNavigate: (String) -> Unit = {},
|
||||||
|
) {
|
||||||
|
val isLocal = node?.num == viewModel.myNodeNum
|
||||||
|
val isWaiting = radioConfigState.responseState.isWaiting()
|
||||||
|
|
||||||
|
val deviceProfile by viewModel.deviceProfile.collectAsStateWithLifecycle()
|
||||||
|
var showEditDeviceProfileDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val importConfigLauncher = rememberLauncherForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
|
showEditDeviceProfileDialog = true
|
||||||
|
it.data?.data?.let { uri -> viewModel.importProfile(uri) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val exportConfigLauncher = rememberLauncherForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
|
it.data?.data?.let { uri -> viewModel.exportProfile(uri) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showEditDeviceProfileDialog) {
|
||||||
|
EditDeviceProfileDialog(
|
||||||
|
title = if (deviceProfile != null) "Import configuration" else "Export configuration",
|
||||||
|
deviceProfile = deviceProfile ?: viewModel.currentDeviceProfile,
|
||||||
|
onConfirm = {
|
||||||
|
showEditDeviceProfileDialog = false
|
||||||
|
if (deviceProfile != null) {
|
||||||
|
viewModel.installProfile(it)
|
||||||
|
} else {
|
||||||
|
viewModel.setDeviceProfile(it)
|
||||||
|
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "application/*"
|
||||||
|
putExtra(Intent.EXTRA_TITLE, "${node!!.num.toUInt()}.cfg")
|
||||||
|
}
|
||||||
|
exportConfigLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDismiss = {
|
||||||
|
showEditDeviceProfileDialog = false
|
||||||
|
viewModel.setDeviceProfile(null)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWaiting) {
|
||||||
|
PacketResponseStateDialog(
|
||||||
|
state = radioConfigState.responseState,
|
||||||
|
onDismiss = {
|
||||||
|
showEditDeviceProfileDialog = false
|
||||||
|
viewModel.clearPacketResponse()
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
val route = radioConfigState.route
|
||||||
|
if (ConfigRoute.entries.any { it.name == route } ||
|
||||||
|
ModuleRoute.entries.any { it.name == route }) {
|
||||||
|
onNavigate(route)
|
||||||
|
viewModel.clearPacketResponse()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioConfigItemList(
|
||||||
|
enabled = connected && !isWaiting,
|
||||||
|
isLocal = isLocal,
|
||||||
|
modifier = modifier,
|
||||||
|
onRouteClick = { route ->
|
||||||
|
viewModel.setResponseStateLoading(route)
|
||||||
|
},
|
||||||
|
onImport = {
|
||||||
|
viewModel.clearPacketResponse()
|
||||||
|
viewModel.setDeviceProfile(null)
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "application/*"
|
||||||
|
}
|
||||||
|
importConfigLauncher.launch(intent)
|
||||||
|
},
|
||||||
|
onExport = {
|
||||||
|
viewModel.clearPacketResponse()
|
||||||
|
viewModel.setDeviceProfile(null)
|
||||||
|
showEditDeviceProfileDialog = true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NavCard(
|
private fun NavCard(
|
||||||
title: String,
|
title: String,
|
||||||
|
|
Ładowanie…
Reference in New Issue