UI: optimize AppContent's composing
This commit is contained in:
parent
0afd087f35
commit
ea11ee3c94
|
|
@ -28,6 +28,7 @@ import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import com.example.llama.revamp.engine.InferenceEngine
|
||||||
import com.example.llama.revamp.navigation.AppDestinations
|
import com.example.llama.revamp.navigation.AppDestinations
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
import com.example.llama.revamp.navigation.NavigationActions
|
||||||
import com.example.llama.revamp.ui.components.AppNavigationDrawer
|
import com.example.llama.revamp.ui.components.AppNavigationDrawer
|
||||||
|
|
@ -65,61 +66,44 @@ class MainActivity : ComponentActivity() {
|
||||||
fun AppContent(
|
fun AppContent(
|
||||||
mainVewModel: MainViewModel = hiltViewModel()
|
mainVewModel: MainViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
|
// Lifecycle and Coroutine scope
|
||||||
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
// Navigation
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val navigationActions = remember(navController) { NavigationActions(navController) }
|
val navigationActions = remember(navController) { NavigationActions(navController) }
|
||||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
|
||||||
|
|
||||||
val engineState by mainVewModel.engineState.collectAsState()
|
|
||||||
// TODO-han.yin: Also use delegate for `isModelLoaded`:
|
|
||||||
val isModelLoaded = remember(engineState) { mainVewModel.isModelLoaded() }
|
|
||||||
|
|
||||||
|
|
||||||
// Model unloading confirmation
|
|
||||||
var showUnloadDialog by remember { mutableStateOf(false) }
|
|
||||||
var pendingNavigation by remember { mutableStateOf<(() -> Unit)?>(null) }
|
|
||||||
|
|
||||||
// Get current route
|
|
||||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||||
val currentRoute by remember {
|
val currentRoute by remember {
|
||||||
derivedStateOf { navBackStackEntry?.destination?.route ?: "" }
|
derivedStateOf { navBackStackEntry?.destination?.route ?: "" }
|
||||||
}
|
}
|
||||||
|
var pendingNavigation by remember { mutableStateOf<(() -> Unit)?>(null) }
|
||||||
|
|
||||||
// Determine if drawer gestures should be enabled based on route
|
// LLM Inference engine status
|
||||||
val drawerGesturesEnabled by remember(currentRoute, drawerState.currentValue) {
|
val engineState by mainVewModel.engineState.collectAsState()
|
||||||
derivedStateOf {
|
val isModelLoading = engineState is InferenceEngine.State.LoadingModel
|
||||||
// Always allow gesture dismissal when drawer is open
|
|| engineState is InferenceEngine.State.ProcessingSystemPrompt
|
||||||
if (drawerState.currentValue == DrawerValue.Open) {
|
val isModelLoaded = engineState !is InferenceEngine.State.Uninitialized
|
||||||
true
|
&& engineState !is InferenceEngine.State.LibraryLoaded
|
||||||
} else {
|
|
||||||
// Only enable drawer opening by gesture on these screens
|
|
||||||
currentRoute == AppDestinations.MODEL_SELECTION_ROUTE ||
|
|
||||||
currentRoute == AppDestinations.SETTINGS_GENERAL_ROUTE ||
|
|
||||||
currentRoute == AppDestinations.MODELS_MANAGEMENT_ROUTE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if current route requires model unloading
|
// Determine if current route requires model unloading
|
||||||
val routeNeedsModelUnloading by remember(currentRoute) {
|
val routeNeedsModelUnloading by remember(currentRoute) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
currentRoute == AppDestinations.CONVERSATION_ROUTE ||
|
currentRoute == AppDestinations.CONVERSATION_ROUTE
|
||||||
currentRoute == AppDestinations.BENCHMARK_ROUTE ||
|
|| currentRoute == AppDestinations.BENCHMARK_ROUTE
|
||||||
currentRoute == AppDestinations.MODEL_LOADING_ROUTE
|
|| currentRoute == AppDestinations.MODEL_LOADING_ROUTE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get local back dispatcher
|
// Model unloading confirmation
|
||||||
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
var showUnloadDialog by remember { mutableStateOf(false) }
|
||||||
val lifecycleOwner = LocalLifecycleOwner.current
|
|
||||||
|
|
||||||
// Helper function to handle back press with model unloading check
|
// Helper function to handle back press with model unloading check
|
||||||
val handleBackWithModelCheck = {
|
val handleBackWithModelCheck = {
|
||||||
if (mainVewModel.isModelLoading()) {
|
if (isModelLoading) {
|
||||||
// If model is still loading, ignore the request
|
// If model is still loading, ignore the request
|
||||||
true // Mark as handled
|
true // Mark as handled
|
||||||
} else if (mainVewModel.isModelLoaded()) {
|
} else if (isModelLoaded) {
|
||||||
showUnloadDialog = true
|
showUnloadDialog = true
|
||||||
pendingNavigation = { navController.popBackStack() }
|
pendingNavigation = { navController.popBackStack() }
|
||||||
true // Mark as handled
|
true // Mark as handled
|
||||||
|
|
@ -130,6 +114,7 @@ fun AppContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register a system back handler for screens that need unload confirmation
|
// Register a system back handler for screens that need unload confirmation
|
||||||
|
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
||||||
DisposableEffect(lifecycleOwner, backDispatcher, currentRoute, isModelLoaded) {
|
DisposableEffect(lifecycleOwner, backDispatcher, currentRoute, isModelLoaded) {
|
||||||
val callback = object : OnBackPressedCallback(
|
val callback = object : OnBackPressedCallback(
|
||||||
// Only enable for screens that need model unloading confirmation
|
// Only enable for screens that need model unloading confirmation
|
||||||
|
|
@ -148,6 +133,22 @@ fun AppContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine if drawer gestures should be enabled based on route
|
||||||
|
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||||
|
val drawerGesturesEnabled by remember(currentRoute, drawerState.currentValue) {
|
||||||
|
derivedStateOf {
|
||||||
|
// Always allow gesture dismissal when drawer is open
|
||||||
|
if (drawerState.currentValue == DrawerValue.Open) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// Only enable drawer opening by gesture on these screens
|
||||||
|
currentRoute == AppDestinations.MODEL_SELECTION_ROUTE ||
|
||||||
|
currentRoute == AppDestinations.SETTINGS_GENERAL_ROUTE ||
|
||||||
|
currentRoute == AppDestinations.MODELS_MANAGEMENT_ROUTE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compose BackHandler for added protection (this handles Compose-based back navigation)
|
// Compose BackHandler for added protection (this handles Compose-based back navigation)
|
||||||
BackHandler(
|
BackHandler(
|
||||||
enabled = routeNeedsModelUnloading &&
|
enabled = routeNeedsModelUnloading &&
|
||||||
|
|
@ -166,11 +167,7 @@ fun AppContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle drawer state
|
// Handle drawer state
|
||||||
val openDrawer: () -> Unit = {
|
val openDrawer: () -> Unit = { coroutineScope.launch { drawerState.open() } }
|
||||||
coroutineScope.launch {
|
|
||||||
drawerState.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main Content with navigation drawer wrapper
|
// Main Content with navigation drawer wrapper
|
||||||
AppNavigationDrawer(
|
AppNavigationDrawer(
|
||||||
|
|
|
||||||
|
|
@ -260,24 +260,6 @@ class MainViewModel @Inject constructor (
|
||||||
inferenceEngine.unloadModel()
|
inferenceEngine.unloadModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a model is currently being loaded.
|
|
||||||
*/
|
|
||||||
fun isModelLoading() =
|
|
||||||
engineState.value.let {
|
|
||||||
it is InferenceEngine.State.LoadingModel
|
|
||||||
|| it is InferenceEngine.State.ProcessingSystemPrompt
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a model has already been loaded.
|
|
||||||
*/
|
|
||||||
fun isModelLoaded() =
|
|
||||||
engineState.value.let {
|
|
||||||
it !is InferenceEngine.State.Uninitialized
|
|
||||||
&& it !is InferenceEngine.State.LibraryLoaded
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up resources when ViewModel is cleared.
|
* Clean up resources when ViewModel is cleared.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue