UI: combine TopBarConfig and BottomBarConfig into each route's ScaffoldConfig

This commit is contained in:
Han Yin 2025-04-17 18:38:44 -07:00
parent 225c5435c5
commit e269da655f
3 changed files with 86 additions and 76 deletions

View File

@ -40,6 +40,8 @@ import com.example.llama.revamp.ui.components.AnimatedNavHost
import com.example.llama.revamp.ui.components.AppNavigationDrawer import com.example.llama.revamp.ui.components.AppNavigationDrawer
import com.example.llama.revamp.ui.components.AppScaffold import com.example.llama.revamp.ui.components.AppScaffold
import com.example.llama.revamp.ui.components.BottomBarConfig import com.example.llama.revamp.ui.components.BottomBarConfig
import com.example.llama.revamp.ui.components.NavigationIcon
import com.example.llama.revamp.ui.components.ScaffoldConfig
import com.example.llama.revamp.ui.components.ScaffoldEvent import com.example.llama.revamp.ui.components.ScaffoldEvent
import com.example.llama.revamp.ui.components.TopBarConfig import com.example.llama.revamp.ui.components.TopBarConfig
import com.example.llama.revamp.ui.components.UnloadModelConfirmationDialog import com.example.llama.revamp.ui.components.UnloadModelConfirmationDialog
@ -147,66 +149,52 @@ fun AppContent(
val openDrawer: () -> Unit = { coroutineScope.launch { drawerState.open() } } val openDrawer: () -> Unit = { coroutineScope.launch { drawerState.open() } }
// Create scaffold's top & bottom bar configs based on current route // Create scaffold's top & bottom bar configs based on current route
val topBarConfig = when (currentRoute) { val scaffoldConfig = when (currentRoute) {
// (Home) Model selection screen // Model selection screen
AppDestinations.MODEL_SELECTION_ROUTE -> { AppDestinations.MODEL_SELECTION_ROUTE ->
TopBarConfig.Default( ScaffoldConfig(
topBarConfig = TopBarConfig.Default(
title = "Models", title = "Models",
navigationIcon = TopBarConfig.NavigationIcon.Menu(openDrawer) navigationIcon = NavigationIcon.Menu(openDrawer)
) )
}
// Settings screen
AppDestinations.SETTINGS_GENERAL_ROUTE -> {
TopBarConfig.Default(
title = "Settings",
navigationIcon = TopBarConfig.NavigationIcon.Back { navigationActions.navigateUp() }
) )
}
// Storage management screen
AppDestinations.MODELS_MANAGEMENT_ROUTE -> {
TopBarConfig.Storage(
title = "Models Management",
navigationIcon = TopBarConfig.NavigationIcon.Back { navigationActions.navigateUp() },
storageMetrics = storageMetrics
)
}
// Model loading screen // Model loading screen
AppDestinations.MODEL_LOADING_ROUTE -> { AppDestinations.MODEL_LOADING_ROUTE ->
TopBarConfig.Performance( ScaffoldConfig(
topBarConfig = TopBarConfig.Performance(
title = "Load Model", title = "Load Model",
navigationIcon = TopBarConfig.NavigationIcon.Back(handleBackWithModelCheck), navigationIcon = NavigationIcon.Back(handleBackWithModelCheck),
memoryMetrics = memoryUsage, memoryMetrics = memoryUsage,
temperatureInfo = null temperatureInfo = null
) )
} )
// Benchmark and Conversation screens // Benchmark and Conversation screens
AppDestinations.BENCHMARK_ROUTE, AppDestinations.CONVERSATION_ROUTE -> { AppDestinations.BENCHMARK_ROUTE, AppDestinations.CONVERSATION_ROUTE ->
TopBarConfig.Performance( ScaffoldConfig(
topBarConfig = TopBarConfig.Performance(
title = when(currentRoute) { title = when(currentRoute) {
AppDestinations.CONVERSATION_ROUTE -> "Chat" AppDestinations.CONVERSATION_ROUTE -> "Chat"
AppDestinations.BENCHMARK_ROUTE -> "Benchmark" AppDestinations.BENCHMARK_ROUTE -> "Benchmark"
else -> "LlamaAndroid" else -> "LlamaAndroid"
}, },
navigationIcon = TopBarConfig.NavigationIcon.Back(handleBackWithModelCheck), navigationIcon = NavigationIcon.Back(handleBackWithModelCheck),
memoryMetrics = memoryUsage, memoryMetrics = memoryUsage,
temperatureInfo = Pair(temperatureInfo, useFahrenheit) temperatureInfo = Pair(temperatureInfo, useFahrenheit)
) )
}
// Fallback for unknown routes
else -> {
TopBarConfig.Default(
title = "LlamaAndroid",
navigationIcon = TopBarConfig.NavigationIcon.None
) )
}
}
val bottomBarConfig = when (currentRoute) { // Settings screen
AppDestinations.SETTINGS_GENERAL_ROUTE ->
ScaffoldConfig(
topBarConfig = TopBarConfig.Default(
title = "Settings",
navigationIcon = NavigationIcon.Back { navigationActions.navigateUp() }
)
)
// Storage management screen
AppDestinations.MODELS_MANAGEMENT_ROUTE -> { AppDestinations.MODELS_MANAGEMENT_ROUTE -> {
// Collect the needed states // Collect the needed states
val sortOrder by modelsManagementViewModel.sortOrder.collectAsState() val sortOrder by modelsManagementViewModel.sortOrder.collectAsState()
@ -220,11 +208,11 @@ fun AppContent(
contract = ActivityResultContracts.OpenDocument() contract = ActivityResultContracts.OpenDocument()
) { uri -> uri?.let { modelsManagementViewModel.localModelFileSelected(it) } } ) { uri -> uri?.let { modelsManagementViewModel.localModelFileSelected(it) } }
BottomBarConfig.ModelsManagement( val bottomBarConfig = BottomBarConfig.ModelsManagement(
sorting = BottomBarConfig.ModelsManagement.SortingConfig( sorting = BottomBarConfig.ModelsManagement.SortingConfig(
currentOrder = sortOrder, currentOrder = sortOrder,
isMenuVisible = showSortMenu, isMenuVisible = showSortMenu,
toggleMenu = { show -> modelsManagementViewModel.toggleSortMenu(show) }, toggleMenu = { modelsManagementViewModel.toggleSortMenu(it) },
selectOrder = { selectOrder = {
modelsManagementViewModel.setSortOrder(it) modelsManagementViewModel.setSortOrder(it)
modelsManagementViewModel.toggleSortMenu(false) modelsManagementViewModel.toggleSortMenu(false)
@ -235,9 +223,9 @@ fun AppContent(
), ),
selection = BottomBarConfig.ModelsManagement.SelectionConfig( selection = BottomBarConfig.ModelsManagement.SelectionConfig(
isActive = isMultiSelectionMode, isActive = isMultiSelectionMode,
toggleMode = { enabled -> modelsManagementViewModel.toggleSelectionMode(enabled) }, toggleMode = { modelsManagementViewModel.toggleSelectionMode(it) },
selectedModels = selectedModels, selectedModels = selectedModels,
toggleAllSelection = { selectAll -> modelsManagementViewModel.toggleAllSelection(selectAll) }, toggleAllSelection = { modelsManagementViewModel.toggleAllSelection(it) },
deleteSelected = { deleteSelected = {
if (selectedModels.isNotEmpty()) { if (selectedModels.isNotEmpty()) {
modelsManagementViewModel.batchDeletionClicked(selectedModels) modelsManagementViewModel.batchDeletionClicked(selectedModels)
@ -255,10 +243,23 @@ fun AppContent(
modelsManagementViewModel.importFromHuggingFace() modelsManagementViewModel.importFromHuggingFace()
modelsManagementViewModel.toggleImportMenu(false) modelsManagementViewModel.toggleImportMenu(false)
} }
)
)
ScaffoldConfig(
topBarConfig = TopBarConfig.Storage(
title = "Models Management",
navigationIcon = NavigationIcon.Back { navigationActions.navigateUp() },
storageMetrics = storageMetrics
), ),
bottomBarConfig = bottomBarConfig
) )
} }
else -> BottomBarConfig.None
// Fallback for empty screen or unknown routes
else -> ScaffoldConfig(
topBarConfig = TopBarConfig.Default(title = "", navigationIcon = NavigationIcon.None)
)
} }
// Handle child screens' scaffold events // Handle child screens' scaffold events
@ -309,8 +310,8 @@ fun AppContent(
) { ) {
// The AppScaffold now uses the config we created // The AppScaffold now uses the config we created
AppScaffold( AppScaffold(
topBarconfig = topBarConfig, topBarconfig = scaffoldConfig.topBarConfig,
bottomBarConfig = bottomBarConfig, bottomBarConfig = scaffoldConfig.bottomBarConfig,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
) { paddingValues -> ) { paddingValues ->
// AnimatedNavHost inside the scaffold content // AnimatedNavHost inside the scaffold content

View File

@ -8,6 +8,13 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
/**
* Configuration of both [TopBarConfig] and [BottomBarConfig]
*/
data class ScaffoldConfig(
val topBarConfig: TopBarConfig,
val bottomBarConfig: BottomBarConfig = BottomBarConfig.None
)
/** /**
* Events called back from child screens * Events called back from child screens
@ -38,8 +45,8 @@ fun AppScaffold(
title = topBarconfig.title, title = topBarconfig.title,
memoryMetrics = topBarconfig.memoryMetrics, memoryMetrics = topBarconfig.memoryMetrics,
temperatureDisplay = topBarconfig.temperatureInfo, temperatureDisplay = topBarconfig.temperatureInfo,
onNavigateBack = (topBarconfig.navigationIcon as? TopBarConfig.NavigationIcon.Back)?.onNavigateBack, onNavigateBack = (topBarconfig.navigationIcon as? NavigationIcon.Back)?.onNavigateBack,
onMenuOpen = (topBarconfig.navigationIcon as? TopBarConfig.NavigationIcon.Menu)?.onMenuOpen onMenuOpen = (topBarconfig.navigationIcon as? NavigationIcon.Menu)?.onMenuOpen
) )
} }
@ -47,15 +54,15 @@ fun AppScaffold(
StorageTopBar( StorageTopBar(
title = topBarconfig.title, title = topBarconfig.title,
storageMetrics = topBarconfig.storageMetrics, storageMetrics = topBarconfig.storageMetrics,
onNavigateBack = (topBarconfig.navigationIcon as? TopBarConfig.NavigationIcon.Back)?.onNavigateBack onNavigateBack = (topBarconfig.navigationIcon as? NavigationIcon.Back)?.onNavigateBack
) )
} }
is TopBarConfig.Default -> { is TopBarConfig.Default -> {
DefaultTopBar( DefaultTopBar(
title = topBarconfig.title, title = topBarconfig.title,
onNavigateBack = (topBarconfig.navigationIcon as? TopBarConfig.NavigationIcon.Back)?.onNavigateBack, onNavigateBack = (topBarconfig.navigationIcon as? NavigationIcon.Back)?.onNavigateBack,
onMenuOpen = (topBarconfig.navigationIcon as? TopBarConfig.NavigationIcon.Menu)?.onMenuOpen onMenuOpen = (topBarconfig.navigationIcon as? NavigationIcon.Menu)?.onMenuOpen
) )
} }
} }

View File

@ -35,7 +35,13 @@ sealed class TopBarConfig {
abstract val title: String abstract val title: String
abstract val navigationIcon: NavigationIcon abstract val navigationIcon: NavigationIcon
// Data class for performance monitoring scaffolds // Default/simple top bar with only a navigation icon
data class Default(
override val title: String,
override val navigationIcon: NavigationIcon
) : TopBarConfig()
// Performance monitoring top bar with RAM and optional temperature
data class Performance( data class Performance(
override val title: String, override val title: String,
override val navigationIcon: NavigationIcon, override val navigationIcon: NavigationIcon,
@ -43,25 +49,21 @@ sealed class TopBarConfig {
val temperatureInfo: Pair<TemperatureMetrics, Boolean>?, val temperatureInfo: Pair<TemperatureMetrics, Boolean>?,
) : TopBarConfig() ) : TopBarConfig()
// Data class for storage management scaffolds // Storage management top bar with used & total storage
data class Storage( data class Storage(
override val title: String, override val title: String,
override val navigationIcon: NavigationIcon, override val navigationIcon: NavigationIcon,
val storageMetrics: StorageMetrics? val storageMetrics: StorageMetrics?
) : TopBarConfig() ) : TopBarConfig()
// Data class for default/simple scaffolds
data class Default(
override val title: String,
override val navigationIcon: NavigationIcon
) : TopBarConfig()
// Helper class for navigation icon configuration
sealed class NavigationIcon {
data class Menu(val onMenuOpen: () -> Unit) : NavigationIcon()
data class Back(val onNavigateBack: () -> Unit) : NavigationIcon()
object None : NavigationIcon()
} }
/**
* Helper class for navigation icon configuration
*/
sealed class NavigationIcon {
data class Back(val onNavigateBack: () -> Unit) : NavigationIcon()
data class Menu(val onMenuOpen: () -> Unit) : NavigationIcon()
object None : NavigationIcon()
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)