feat(infrared): add infrared control, learning, and virtual remote module #9

Merged
KremeCN merged 41 commits from feat/moler-infrared-control into main 2026-08-25 14:51:34 +08:00
Showing only changes of commit 1fdc9bd376 - Show all commits
@@ -11,9 +11,19 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.flagship.abox.manager.designsystem.ABoxLoadingIndicator import com.flagship.abox.manager.designsystem.ABoxLoadingIndicator
import com.flagship.abox.manager.designsystem.ABoxSurface import com.flagship.abox.manager.designsystem.ABoxSurface
import com.flagship.abox.manager.designsystem.ABoxTheme import com.flagship.abox.manager.designsystem.ABoxTheme
import com.flagship.abox.manager.domain.ProviderProfile
import com.flagship.abox.manager.domain.Username
import com.flagship.abox.manager.infrared.remote.ui.InfraredRemoteRoute
import com.flagship.abox.manager.infrared.ui.InfraredControlRoute
import com.flagship.abox.manager.ui.devicecontrollist.DeviceListScreen
import com.flagship.abox.manager.ui.login.LoginRoute import com.flagship.abox.manager.ui.login.LoginRoute
import com.flagship.abox.manager.ui.login.LoginViewModel import com.flagship.abox.manager.ui.login.LoginViewModel
import com.flagship.abox.manager.ui.provider.ProviderSelectionRoute import com.flagship.abox.manager.ui.provider.ProviderSelectionRoute
@@ -57,18 +67,75 @@ fun ABoxManagerApp(
onSwitchProvider = sessionActionsViewModel::switchProvider, onSwitchProvider = sessionActionsViewModel::switchProvider,
viewModel = loginViewModel, viewModel = loginViewModel,
) )
is AppSessionUiState.Authenticated -> MainAppShell( is AppSessionUiState.Authenticated -> AuthenticatedNavHost(
userName = state.username.value, username = state.username,
providerName = state.profile.displayName, profile = state.profile,
onLogout = sessionActionsViewModel::logout,
actionInProgress = actionState.inProgress, actionInProgress = actionState.inProgress,
errorMessage = actionState.errorMessage, errorMessage = actionState.errorMessage,
onLogout = sessionActionsViewModel::logout,
) )
} }
} }
} }
} }
@Composable
private fun AuthenticatedNavHost(
username: Username,
profile: ProviderProfile,
actionInProgress: Boolean,
errorMessage: String?,
onLogout: () -> Unit,
) {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home",
) {
composable("home") {
MainAppShell(
userName = username.value,
providerName = profile.displayName,
onLogout = onLogout,
actionInProgress = actionInProgress,
errorMessage = errorMessage,
devicesSlot = {
DeviceListScreen(
onInfraredClick = {
navController.navigate("infrared_remote/${profile.id.value}")
},
)
},
)
}
composable(
route = "infrared_remote/{profileId}",
arguments = listOf(
navArgument("profileId") { type = NavType.StringType },
),
) {
InfraredRemoteRoute(
onBack = { navController.popBackStack() },
onOpenSettings = {
navController.navigate("infrared_settings/${profile.id.value}")
},
onSessionInvalid = onLogout,
)
}
composable(
route = "infrared_settings/{profileId}",
arguments = listOf(
navArgument("profileId") { type = NavType.StringType },
),
) {
InfraredControlRoute(
onBack = { navController.popBackStack() },
onSessionInvalid = onLogout,
)
}
}
}
private fun AppSessionUiState.screenKey(): String = when (this) { private fun AppSessionUiState.screenKey(): String = when (this) {
AppSessionUiState.Loading -> "loading" AppSessionUiState.Loading -> "loading"
AppSessionUiState.ProviderSelection -> "providers" AppSessionUiState.ProviderSelection -> "providers"