UI: split a nested parent settings screen into separate child settings screens
This commit is contained in:
parent
65c09b2b32
commit
a7ee3d305f
|
|
@ -3,6 +3,7 @@ package com.example.llama.revamp
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.activity.OnBackPressedDispatcher
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
|
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
|
@ -24,12 +25,10 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavType
|
|
||||||
import androidx.navigation.compose.NavHost
|
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 androidx.navigation.navArgument
|
|
||||||
import com.example.llama.revamp.engine.InferenceEngine
|
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
|
||||||
|
|
@ -37,10 +36,10 @@ import com.example.llama.revamp.ui.components.AppNavigationDrawer
|
||||||
import com.example.llama.revamp.ui.components.UnloadModelConfirmationDialog
|
import com.example.llama.revamp.ui.components.UnloadModelConfirmationDialog
|
||||||
import com.example.llama.revamp.ui.screens.BenchmarkScreen
|
import com.example.llama.revamp.ui.screens.BenchmarkScreen
|
||||||
import com.example.llama.revamp.ui.screens.ConversationScreen
|
import com.example.llama.revamp.ui.screens.ConversationScreen
|
||||||
import com.example.llama.revamp.ui.screens.ModeSelectionScreen
|
|
||||||
import com.example.llama.revamp.ui.screens.ModelSelectionScreen
|
import com.example.llama.revamp.ui.screens.ModelSelectionScreen
|
||||||
import com.example.llama.revamp.ui.screens.SettingsScreen
|
import com.example.llama.revamp.ui.screens.ModelsManagementScreen
|
||||||
import com.example.llama.revamp.ui.screens.SettingsTab
|
import com.example.llama.revamp.ui.screens.ModeSelectionScreen
|
||||||
|
import com.example.llama.revamp.ui.screens.SettingsGeneralScreen
|
||||||
import com.example.llama.revamp.ui.theme.LlamaTheme
|
import com.example.llama.revamp.ui.theme.LlamaTheme
|
||||||
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
||||||
import com.example.llama.revamp.viewmodel.MainViewModel
|
import com.example.llama.revamp.viewmodel.MainViewModel
|
||||||
|
|
@ -103,7 +102,8 @@ fun AppContent() {
|
||||||
} else {
|
} else {
|
||||||
// Only enable drawer opening by gesture on these screens
|
// Only enable drawer opening by gesture on these screens
|
||||||
currentRoute == AppDestinations.MODEL_SELECTION_ROUTE ||
|
currentRoute == AppDestinations.MODEL_SELECTION_ROUTE ||
|
||||||
currentRoute.startsWith(AppDestinations.SETTINGS_ROUTE)
|
currentRoute == AppDestinations.SETTINGS_GENERAL_ROUTE ||
|
||||||
|
currentRoute == AppDestinations.MODELS_MANAGEMENT_ROUTE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +180,8 @@ fun AppContent() {
|
||||||
AppNavigationDrawer(
|
AppNavigationDrawer(
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
navigationActions = navigationActions,
|
navigationActions = navigationActions,
|
||||||
gesturesEnabled = drawerGesturesEnabled
|
gesturesEnabled = drawerGesturesEnabled,
|
||||||
|
currentRoute = currentRoute
|
||||||
) {
|
) {
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
|
|
@ -194,7 +195,7 @@ fun AppContent() {
|
||||||
navigationActions.navigateToModeSelection()
|
navigationActions.navigateToModeSelection()
|
||||||
},
|
},
|
||||||
onManageModelsClicked = {
|
onManageModelsClicked = {
|
||||||
navigationActions.navigateToSettings(SettingsTab.MODEL_MANAGEMENT.name)
|
navigationActions.navigateToModelsManagement()
|
||||||
},
|
},
|
||||||
onMenuClicked = openDrawer,
|
onMenuClicked = openDrawer,
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
|
|
@ -255,28 +256,23 @@ fun AppContent() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings Screen
|
// Settings General Screen
|
||||||
composable(
|
composable(AppDestinations.SETTINGS_GENERAL_ROUTE) {
|
||||||
route = "${AppDestinations.SETTINGS_ROUTE}/{tab}",
|
SettingsGeneralScreen(
|
||||||
arguments = listOf(
|
|
||||||
navArgument("tab") {
|
|
||||||
type = NavType.StringType
|
|
||||||
defaultValue = SettingsTab.GENERAL.name
|
|
||||||
}
|
|
||||||
)
|
|
||||||
) { backStackEntry ->
|
|
||||||
val tabName = backStackEntry.arguments?.getString("tab") ?: SettingsTab.GENERAL.name
|
|
||||||
val tab = try {
|
|
||||||
SettingsTab.valueOf(tabName)
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
SettingsTab.GENERAL
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsScreen(
|
|
||||||
selectedTab = tab,
|
|
||||||
onBackPressed = { navController.popBackStack() },
|
onBackPressed = { navController.popBackStack() },
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
navigationActions = navigationActions
|
navigationActions = navigationActions,
|
||||||
|
onMenuClicked = openDrawer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Models Management Screen
|
||||||
|
composable(AppDestinations.MODELS_MANAGEMENT_ROUTE) {
|
||||||
|
ModelsManagementScreen(
|
||||||
|
onBackPressed = { navController.popBackStack() },
|
||||||
|
drawerState = drawerState,
|
||||||
|
navigationActions = navigationActions,
|
||||||
|
onMenuClicked = openDrawer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,15 @@ import androidx.navigation.NavController
|
||||||
* Navigation destinations for the app
|
* Navigation destinations for the app
|
||||||
*/
|
*/
|
||||||
object AppDestinations {
|
object AppDestinations {
|
||||||
|
// Primary navigation destinations
|
||||||
const val MODEL_SELECTION_ROUTE = "model_selection"
|
const val MODEL_SELECTION_ROUTE = "model_selection"
|
||||||
const val MODE_SELECTION_ROUTE = "mode_selection"
|
const val MODE_SELECTION_ROUTE = "mode_selection"
|
||||||
const val CONVERSATION_ROUTE = "conversation"
|
const val CONVERSATION_ROUTE = "conversation"
|
||||||
const val BENCHMARK_ROUTE = "benchmark"
|
const val BENCHMARK_ROUTE = "benchmark"
|
||||||
const val SETTINGS_ROUTE = "settings"
|
|
||||||
|
// Settings destinations (moved from tabs to separate routes)
|
||||||
|
const val SETTINGS_GENERAL_ROUTE = "settings_general"
|
||||||
|
const val MODELS_MANAGEMENT_ROUTE = "models_management"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,8 +41,12 @@ class NavigationActions(private val navController: NavController) {
|
||||||
navController.navigate(AppDestinations.BENCHMARK_ROUTE)
|
navController.navigate(AppDestinations.BENCHMARK_ROUTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun navigateToSettings(tab: String = "GENERAL") {
|
fun navigateToSettingsGeneral() {
|
||||||
navController.navigate("${AppDestinations.SETTINGS_ROUTE}/$tab")
|
navController.navigate(AppDestinations.SETTINGS_GENERAL_ROUTE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun navigateToModelsManagement() {
|
||||||
|
navController.navigate(AppDestinations.MODELS_MANAGEMENT_ROUTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun navigateUp() {
|
fun navigateUp() {
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,21 @@ package com.example.llama.revamp.ui.components
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Folder
|
||||||
import androidx.compose.material.icons.filled.Home
|
import androidx.compose.material.icons.filled.Home
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.DrawerState
|
import androidx.compose.material3.DrawerState
|
||||||
import androidx.compose.material3.DrawerValue
|
import androidx.compose.material3.DrawerValue
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalDrawerSheet
|
import androidx.compose.material3.ModalDrawerSheet
|
||||||
|
|
@ -23,6 +26,7 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
|
|
@ -40,6 +44,7 @@ fun AppNavigationDrawer(
|
||||||
drawerState: DrawerState,
|
drawerState: DrawerState,
|
||||||
navigationActions: NavigationActions,
|
navigationActions: NavigationActions,
|
||||||
gesturesEnabled: Boolean,
|
gesturesEnabled: Boolean,
|
||||||
|
currentRoute: String,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
@ -63,18 +68,14 @@ fun AppNavigationDrawer(
|
||||||
modifier = Modifier.width(drawerWidth)
|
modifier = Modifier.width(drawerWidth)
|
||||||
) {
|
) {
|
||||||
DrawerContent(
|
DrawerContent(
|
||||||
onHomeClicked = {
|
currentRoute = currentRoute,
|
||||||
|
onNavigate = { destination ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
drawerState.close()
|
drawerState.close()
|
||||||
navigationActions.navigateToModelSelection()
|
destination()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSettingsClicked = {
|
navigationActions = navigationActions
|
||||||
coroutineScope.launch {
|
|
||||||
drawerState.close()
|
|
||||||
navigationActions.navigateToSettings()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -84,39 +85,78 @@ fun AppNavigationDrawer(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DrawerContent(
|
private fun DrawerContent(
|
||||||
onHomeClicked: () -> Unit,
|
currentRoute: String,
|
||||||
onSettingsClicked: () -> Unit,
|
onNavigate: ((Function0<Unit>)) -> Unit,
|
||||||
|
navigationActions: NavigationActions,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
// App Header
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Local LLM",
|
text = "Local LLM",
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 16.dp)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "v1.0.0",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(top = 4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
// Navigation Items
|
// Main Navigation Items
|
||||||
|
Text(
|
||||||
|
text = "Navigation",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
DrawerNavigationItem(
|
DrawerNavigationItem(
|
||||||
icon = Icons.Default.Home,
|
icon = Icons.Default.Home,
|
||||||
label = "Home",
|
label = "Home",
|
||||||
onClick = onHomeClicked
|
isSelected = currentRoute == com.example.llama.revamp.navigation.AppDestinations.MODEL_SELECTION_ROUTE,
|
||||||
|
onClick = { onNavigate { navigationActions.navigateToModelSelection() } }
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
// Settings Group
|
||||||
|
Text(
|
||||||
|
text = "Settings",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
DrawerNavigationItem(
|
DrawerNavigationItem(
|
||||||
icon = Icons.Default.Settings,
|
icon = Icons.Default.Settings,
|
||||||
label = "Settings",
|
label = "General Settings",
|
||||||
onClick = onSettingsClicked
|
isSelected = currentRoute == com.example.llama.revamp.navigation.AppDestinations.SETTINGS_GENERAL_ROUTE,
|
||||||
|
onClick = { onNavigate { navigationActions.navigateToSettingsGeneral() } }
|
||||||
|
)
|
||||||
|
|
||||||
|
DrawerNavigationItem(
|
||||||
|
icon = Icons.Default.Folder,
|
||||||
|
label = "Models Management",
|
||||||
|
isSelected = currentRoute == com.example.llama.revamp.navigation.AppDestinations.MODELS_MANAGEMENT_ROUTE,
|
||||||
|
onClick = { onNavigate { navigationActions.navigateToModelsManagement() } }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,28 +165,47 @@ private fun DrawerContent(
|
||||||
private fun DrawerNavigationItem(
|
private fun DrawerNavigationItem(
|
||||||
icon: ImageVector,
|
icon: ImageVector,
|
||||||
label: String,
|
label: String,
|
||||||
|
isSelected: Boolean,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
val backgroundColor = if (isSelected) {
|
||||||
|
MaterialTheme.colorScheme.primaryContainer
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.surface
|
||||||
|
}
|
||||||
|
|
||||||
|
val contentColor = if (isSelected) {
|
||||||
|
MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.onSurface
|
||||||
|
}
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable(onClick = onClick)
|
.clickable(onClick = onClick)
|
||||||
.padding(vertical = 8.dp),
|
.padding(vertical = 4.dp),
|
||||||
color = MaterialTheme.colorScheme.surface
|
color = backgroundColor,
|
||||||
|
shape = MaterialTheme.shapes.small
|
||||||
) {
|
) {
|
||||||
Column(
|
Row(
|
||||||
modifier = Modifier.padding(8.dp)
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 12.dp, horizontal = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = label,
|
contentDescription = label,
|
||||||
tint = MaterialTheme.colorScheme.primary
|
tint = contentColor,
|
||||||
|
modifier = Modifier.size(24.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = label,
|
text = label,
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
modifier = Modifier.padding(start = 8.dp, top = 4.dp)
|
color = contentColor,
|
||||||
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
package com.example.llama.revamp.ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Info
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.DrawerState
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedButton
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.llama.revamp.data.model.ModelInfo
|
||||||
|
import com.example.llama.revamp.navigation.NavigationActions
|
||||||
|
import com.example.llama.revamp.ui.components.AppScaffold
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen for managing LLM models (view, download, delete)
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun ModelsManagementScreen(
|
||||||
|
onBackPressed: () -> Unit,
|
||||||
|
drawerState: DrawerState,
|
||||||
|
navigationActions: NavigationActions,
|
||||||
|
onMenuClicked: () -> Unit
|
||||||
|
) {
|
||||||
|
// For demo purposes, we'll use sample models
|
||||||
|
val installedModels = remember { ModelInfo.getSampleModels() }
|
||||||
|
|
||||||
|
AppScaffold(
|
||||||
|
title = "Models Management",
|
||||||
|
navigationActions = navigationActions,
|
||||||
|
onBackPressed = onBackPressed,
|
||||||
|
onMenuPressed = onMenuClicked
|
||||||
|
) { paddingValues ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(paddingValues)
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
// Summary card
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 16.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Models Storage",
|
||||||
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Storage Used: 14.6GB / 32GB",
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = { 0.45f },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
OutlinedButton(
|
||||||
|
onClick = { /* Download new model */ },
|
||||||
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
|
) {
|
||||||
|
Text("Add Model")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Installed models list
|
||||||
|
Text(
|
||||||
|
text = "Installed Models",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
modifier = Modifier.padding(vertical = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyColumn {
|
||||||
|
items(installedModels) { model ->
|
||||||
|
ModelManagementItem(
|
||||||
|
model = model,
|
||||||
|
onInfoClick = { /* Show model details */ },
|
||||||
|
onDeleteClick = { /* Delete model */ }
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ModelManagementItem(
|
||||||
|
model: ModelInfo,
|
||||||
|
onInfoClick: () -> Unit,
|
||||||
|
onDeleteClick: () -> Unit
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = model.name,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "${model.parameters} • ${model.quantization} • ${model.formattedSize}",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = onInfoClick) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Info,
|
||||||
|
contentDescription = "Model details",
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = onDeleteClick) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Delete,
|
||||||
|
contentDescription = "Delete model",
|
||||||
|
tint = MaterialTheme.colorScheme.error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.padding(vertical = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Location: ${model.path}",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
|
||||||
|
model.lastUsed?.let { lastUsed ->
|
||||||
|
val dateFormat = SimpleDateFormat("MMM d, yyyy", Locale.getDefault())
|
||||||
|
Text(
|
||||||
|
text = "Last used: ${dateFormat.format(Date(lastUsed))}",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
package com.example.llama.revamp.ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.DrawerState
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.example.llama.revamp.data.preferences.UserPreferences
|
||||||
|
import com.example.llama.revamp.monitoring.PerformanceMonitor
|
||||||
|
import com.example.llama.revamp.navigation.NavigationActions
|
||||||
|
import com.example.llama.revamp.ui.components.AppScaffold
|
||||||
|
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
||||||
|
import com.example.llama.revamp.viewmodel.PerformanceViewModel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen for general app settings
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun SettingsGeneralScreen(
|
||||||
|
onBackPressed: () -> Unit,
|
||||||
|
drawerState: DrawerState,
|
||||||
|
navigationActions: NavigationActions,
|
||||||
|
onMenuClicked: () -> Unit
|
||||||
|
) {
|
||||||
|
// Create dependencies for PerformanceViewModel
|
||||||
|
val context = LocalContext.current
|
||||||
|
val performanceMonitor = remember { PerformanceMonitor(context) }
|
||||||
|
val userPreferences = remember { UserPreferences(context) }
|
||||||
|
|
||||||
|
// Create factory for PerformanceViewModel
|
||||||
|
val factory = remember { ViewModelFactoryProvider.getPerformanceViewModelFactory(performanceMonitor, userPreferences) }
|
||||||
|
|
||||||
|
// Get ViewModel instance with factory
|
||||||
|
val performanceViewModel: PerformanceViewModel = viewModel(factory = factory)
|
||||||
|
|
||||||
|
// Collect state from ViewModel
|
||||||
|
val isMonitoringEnabled by performanceViewModel.isMonitoringEnabled.collectAsState()
|
||||||
|
val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState()
|
||||||
|
|
||||||
|
AppScaffold(
|
||||||
|
title = "Settings",
|
||||||
|
navigationActions = navigationActions,
|
||||||
|
onBackPressed = onBackPressed,
|
||||||
|
onMenuPressed = onMenuClicked
|
||||||
|
) { paddingValues ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(paddingValues)
|
||||||
|
.padding(16.dp)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
SettingsCategory(title = "Performance Monitoring") {
|
||||||
|
SettingsSwitch(
|
||||||
|
title = "Enable Monitoring",
|
||||||
|
description = "Display memory, battery and temperature information",
|
||||||
|
checked = isMonitoringEnabled,
|
||||||
|
onCheckedChange = { performanceViewModel.setMonitoringEnabled(it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingsSwitch(
|
||||||
|
title = "Use Fahrenheit",
|
||||||
|
description = "Display temperature in Fahrenheit instead of Celsius",
|
||||||
|
checked = useFahrenheit,
|
||||||
|
onCheckedChange = { performanceViewModel.setUseFahrenheitUnit(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsCategory(title = "Theme") {
|
||||||
|
SettingsSwitch(
|
||||||
|
title = "Dark Theme",
|
||||||
|
description = "Use dark theme throughout the app",
|
||||||
|
checked = true, // This would be connected to theme state in a real app
|
||||||
|
onCheckedChange = { /* TODO: Implement theme switching */ }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsCategory(title = "About") {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Local LLM",
|
||||||
|
style = MaterialTheme.typography.titleLarge
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Version 1.0.0",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Local inference for LLM models on your device.",
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsCategory(
|
||||||
|
title: String,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsSwitch(
|
||||||
|
title: String,
|
||||||
|
description: String,
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChange: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = description,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Switch(
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = onCheckedChange
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
|
@ -1,259 +0,0 @@
|
||||||
package com.example.llama.revamp.ui.screens
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.Card
|
|
||||||
import androidx.compose.material3.Divider
|
|
||||||
import androidx.compose.material3.DrawerState
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Switch
|
|
||||||
import androidx.compose.material3.Tab
|
|
||||||
import androidx.compose.material3.TabRow
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import com.example.llama.revamp.data.preferences.UserPreferences
|
|
||||||
import com.example.llama.revamp.monitoring.PerformanceMonitor
|
|
||||||
import com.example.llama.revamp.navigation.NavigationActions
|
|
||||||
import com.example.llama.revamp.ui.components.AppScaffold
|
|
||||||
import com.example.llama.revamp.util.ViewModelFactoryProvider
|
|
||||||
import com.example.llama.revamp.viewmodel.PerformanceViewModel
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tabs for the settings screen.
|
|
||||||
*/
|
|
||||||
enum class SettingsTab {
|
|
||||||
GENERAL,
|
|
||||||
MODEL_MANAGEMENT,
|
|
||||||
ADVANCED
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsScreen(
|
|
||||||
selectedTab: SettingsTab = SettingsTab.GENERAL,
|
|
||||||
onBackPressed: () -> Unit,
|
|
||||||
drawerState: DrawerState,
|
|
||||||
navigationActions: NavigationActions
|
|
||||||
) {
|
|
||||||
// State for tab selection
|
|
||||||
var currentTab by remember { mutableStateOf(selectedTab) }
|
|
||||||
|
|
||||||
// Create dependencies for PerformanceViewModel
|
|
||||||
val context = LocalContext.current
|
|
||||||
val performanceMonitor = remember { PerformanceMonitor(context) }
|
|
||||||
val userPreferences = remember { UserPreferences(context) }
|
|
||||||
|
|
||||||
// Create factory for PerformanceViewModel
|
|
||||||
val factory = remember { ViewModelFactoryProvider.getPerformanceViewModelFactory(performanceMonitor, userPreferences) }
|
|
||||||
|
|
||||||
// Get ViewModel instance with factory
|
|
||||||
val performanceViewModel: PerformanceViewModel = viewModel(factory = factory)
|
|
||||||
|
|
||||||
AppScaffold(
|
|
||||||
title = "Settings",
|
|
||||||
drawerState = drawerState,
|
|
||||||
navigationActions = navigationActions,
|
|
||||||
onBackPressed = onBackPressed
|
|
||||||
) { paddingValues ->
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(paddingValues)
|
|
||||||
) {
|
|
||||||
// Tabs for different settings categories
|
|
||||||
TabRow(selectedTabIndex = currentTab.ordinal) {
|
|
||||||
Tab(
|
|
||||||
selected = currentTab == SettingsTab.GENERAL,
|
|
||||||
onClick = { currentTab = SettingsTab.GENERAL },
|
|
||||||
text = { Text("General") }
|
|
||||||
)
|
|
||||||
|
|
||||||
Tab(
|
|
||||||
selected = currentTab == SettingsTab.MODEL_MANAGEMENT,
|
|
||||||
onClick = { currentTab = SettingsTab.MODEL_MANAGEMENT },
|
|
||||||
text = { Text("Models") }
|
|
||||||
)
|
|
||||||
|
|
||||||
Tab(
|
|
||||||
selected = currentTab == SettingsTab.ADVANCED,
|
|
||||||
onClick = { currentTab = SettingsTab.ADVANCED },
|
|
||||||
text = { Text("Advanced") }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Content for the selected tab
|
|
||||||
when (currentTab) {
|
|
||||||
SettingsTab.GENERAL -> GeneralSettings(performanceViewModel)
|
|
||||||
SettingsTab.MODEL_MANAGEMENT -> ModelManagementSettings()
|
|
||||||
SettingsTab.ADVANCED -> AdvancedSettings()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun GeneralSettings(performanceViewModel: PerformanceViewModel) {
|
|
||||||
val isMonitoringEnabled by performanceViewModel.isMonitoringEnabled.collectAsState()
|
|
||||||
val useFahrenheit by performanceViewModel.useFahrenheitUnit.collectAsState()
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
SettingsCategory(title = "Performance Monitoring") {
|
|
||||||
SettingsSwitch(
|
|
||||||
title = "Enable Monitoring",
|
|
||||||
description = "Display memory, battery and temperature information",
|
|
||||||
checked = isMonitoringEnabled,
|
|
||||||
onCheckedChange = { performanceViewModel.setMonitoringEnabled(it) }
|
|
||||||
)
|
|
||||||
|
|
||||||
SettingsSwitch(
|
|
||||||
title = "Use Fahrenheit",
|
|
||||||
description = "Display temperature in Fahrenheit instead of Celsius",
|
|
||||||
checked = useFahrenheit,
|
|
||||||
onCheckedChange = { performanceViewModel.setUseFahrenheitUnit(it) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsCategory(title = "Theme") {
|
|
||||||
SettingsSwitch(
|
|
||||||
title = "Dark Theme",
|
|
||||||
description = "Use dark theme throughout the app",
|
|
||||||
checked = true, // This would be connected to theme state in a real app
|
|
||||||
onCheckedChange = { /* TODO: Implement theme switching */ }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ModelManagementSettings() {
|
|
||||||
// This would be populated with actual functionality in a real implementation
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Model Management",
|
|
||||||
style = MaterialTheme.typography.titleLarge,
|
|
||||||
modifier = Modifier.padding(bottom = 16.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = "This section will allow you to download, delete, and manage LLM models.",
|
|
||||||
style = MaterialTheme.typography.bodyMedium
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AdvancedSettings() {
|
|
||||||
// This would be populated with actual functionality in a real implementation
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Advanced Settings",
|
|
||||||
style = MaterialTheme.typography.titleLarge,
|
|
||||||
modifier = Modifier.padding(bottom = 16.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = "This section will contain advanced settings such as memory management, cache configuration, and debugging options.",
|
|
||||||
style = MaterialTheme.typography.bodyMedium
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsCategory(
|
|
||||||
title: String,
|
|
||||||
content: @Composable () -> Unit
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
style = MaterialTheme.typography.titleMedium,
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Card(
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Column {
|
|
||||||
content()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsSwitch(
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
checked: Boolean,
|
|
||||||
onCheckedChange: (Boolean) -> Unit
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
style = MaterialTheme.typography.titleMedium
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = description,
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Switch(
|
|
||||||
checked = checked,
|
|
||||||
onCheckedChange = onCheckedChange
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue