feat: route infrared through selected device

This commit is contained in:
2026-08-26 19:55:30 +08:00
parent 4798ae32ba
commit 26ab5095e5
4 changed files with 44 additions and 13 deletions
@@ -239,7 +239,7 @@ fun AuthenticatedNavigation(
profile.id,
selection.deviceName,
)
DeviceType.INFRARED -> "${Routes.INFRARED_HUB}/${Uri.encode(profile.id.value)}"
DeviceType.INFRARED -> Routes.infraredHub(profile.id.value, selection.deviceName.value)
}
},
selectionForRoute = { route -> profile.selectionForRoute(route) },
@@ -367,9 +367,12 @@ private fun AuthenticatedNavHost(
)
sceneExecutionDestination(onBack = navController::popBackStack)
composable(
route = "${Routes.INFRARED_HUB}/{profileId}",
arguments = listOf(navArgument("profileId") { type = NavType.StringType }),
) {
route = Routes.INFRARED_HUB,
arguments = listOf(
navArgument("profileId") { type = NavType.StringType },
navArgument("deviceName") { type = NavType.StringType },
),
) { entry ->
InfraredHubRoute(
onBack = {
onClearDeviceSelection()
@@ -381,7 +384,8 @@ private fun AuthenticatedNavHost(
)
},
onOpenSettings = {
navController.navigate("${Routes.INFRARED_SETTINGS}/${Uri.encode(profile.id.value)}")
val deviceName = entry.arguments?.getString("deviceName").orEmpty()
navController.navigate(Routes.infraredSettings(profile.id.value, deviceName))
},
onSessionInvalid = onLogout,
)
@@ -399,8 +403,11 @@ private fun AuthenticatedNavHost(
)
}
composable(
route = "${Routes.INFRARED_SETTINGS}/{profileId}",
arguments = listOf(navArgument("profileId") { type = NavType.StringType }),
route = Routes.INFRARED_SETTINGS,
arguments = listOf(
navArgument("profileId") { type = NavType.StringType },
navArgument("deviceName") { type = NavType.StringType },
),
) {
InfraredControlRoute(
onBack = navController::popBackStack,
@@ -473,9 +480,9 @@ private fun ProviderProfile.selectionForRoute(route: String?): DeviceSelection?
deviceName = DeviceName(parts.drop(3).joinToString("/").decodeRoutePart()),
type = DeviceType.TEMPERATURE_HUMIDITY,
)
parts.size >= 2 && parts[0] == Routes.INFRARED_HUB -> DeviceSelection(
parts.size >= 3 && parts[0] == "infrared_hub" -> DeviceSelection(
profileId = id,
deviceName = DeviceName("红外遥控器"),
deviceName = DeviceName(parts[2].decodeRoutePart()),
type = DeviceType.INFRARED,
)
else -> null
@@ -1,5 +1,7 @@
package com.flagship.abox.manager.ui.navigation
import android.net.Uri
object Routes {
const val STARTUP = "startup"
const val PROVIDER_SELECTION = "provider_selection"
@@ -7,7 +9,13 @@ object Routes {
const val AUTHENTICATED = "authenticated"
const val SETTINGS = "settings"
const val INFRARED_HUB = "infrared_hub"
const val INFRARED_HUB = "infrared_hub/{profileId}/{deviceName}"
const val INFRARED_PANEL = "infrared_panel"
const val INFRARED_SETTINGS = "infrared_settings"
const val INFRARED_SETTINGS = "infrared_settings/{profileId}/{deviceName}"
fun infraredHub(profileId: String, deviceName: String): String =
"infrared_hub/${Uri.encode(profileId)}/${Uri.encode(deviceName)}"
fun infraredSettings(profileId: String, deviceName: String): String =
"infrared_settings/${Uri.encode(profileId)}/${Uri.encode(deviceName)}"
}
@@ -49,6 +49,9 @@ class InfraredHubViewModel @Inject constructor(
val profileId: ProviderProfileId? = rawProfileId?.takeIf { it.isNotBlank() }?.let { ProviderProfileId(it) }
private val messageFlow = MutableStateFlow<HubUiMessage?>(null)
private val routeDeviceName: DeviceName? = savedStateHandle.get<String>("deviceName")
?.takeIf { it.isNotBlank() }
?.let(::DeviceName)
private data class HubSnapshot(
val providerProfile: ProviderProfile? = null,
@@ -68,7 +71,12 @@ class InfraredHubViewModel @Inject constructor(
when (devResult) {
is DomainResult.Failure -> flowOf(HubSnapshot(providerProfile = active, configError = devResult.error))
is DomainResult.Success -> {
val deviceName = devResult.value ?: DEFAULT_DEVICE_NAME
val deviceName = routeDeviceName ?: devResult.value ?: return@flatMapLatest flowOf(
HubSnapshot(
providerProfile = active,
configError = DomainError.InvalidRequest(detail = "No infrared device configured"),
),
)
combine(
virtualRemoteRepository.observeRemotes(profileId, deviceName),
virtualRemoteRepository.observeSlotQuota(profileId, deviceName),
@@ -40,6 +40,9 @@ class InfraredControlViewModel @Inject constructor(
private val deviceNameInputFlow = MutableStateFlow<String?>(null)
private val messageFlow = MutableStateFlow<InfraredUiMessage?>(null)
private val routeDeviceName: DeviceName? = savedStateHandle.get<String>("deviceName")
?.takeIf { it.isNotBlank() }
?.let(::DeviceName)
private data class ServerState(
val providerProfile: com.flagship.abox.manager.domain.ProviderProfile? = null,
@@ -65,7 +68,12 @@ class InfraredControlViewModel @Inject constructor(
),
)
is DomainResult.Success -> {
val deviceName = deviceResult.value ?: DEFAULT_DEVICE_NAME
val deviceName = routeDeviceName ?: deviceResult.value ?: return@flatMapLatest flowOf(
ServerState(
providerProfile = active,
configError = DomainError.InvalidRequest(detail = "No infrared device configured"),
),
)
combine(
virtualRemoteRepository.observeRemotes(profileId, deviceName),
virtualRemoteRepository.observeSlotQuota(profileId, deviceName),