- HermesScaffold: title now @Composable () -> Unit (M3-idiomatic)
- HermesScaffold: added modifier and snackbarHost parameters
- Updated all 18 callers from title="X" to title={Text("X")}
- ChatScreen: converted from raw Scaffold to HermesScaffold
- Removed unused Menu icon import (ktlint fix)
This commit is contained in:
20 files changed
+133
-153
No files matched your search
@@ -45,7 +45,7 @@ fun AchievementsScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Agent Achievements",
|
||||
title = { Text("Agent Achievements") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadAchievements() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -59,7 +59,7 @@ fun ChannelsScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Messaging Channels",
|
||||
title = { Text("Messaging Channels") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadPlatforms() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -40,7 +40,6 @@ import androidx.compose.material.icons.automirrored.filled.Send
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.History
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Stop
|
||||
import androidx.compose.material3.AlertDialog
|
||||
@@ -49,7 +48,6 @@ import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -57,14 +55,11 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Snackbar
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -88,8 +83,8 @@ import com.m57.hermescontrol.notification.NotificationHelper
|
||||
import com.m57.hermescontrol.theme.StatusGreen
|
||||
import com.m57.hermescontrol.theme.StatusRed
|
||||
import com.m57.hermescontrol.ui.common.EmptyState
|
||||
import com.m57.hermescontrol.ui.common.HermesScaffold
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ChatScreen(
|
||||
onNavigateToSettings: () -> Unit,
|
||||
@@ -165,132 +160,29 @@ fun ChatScreen(
|
||||
),
|
||||
)
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
if (onOpenDrawer != null) {
|
||||
IconButton(onClick = onOpenDrawer) {
|
||||
Icon(
|
||||
imageVector = androidx.compose.material.icons.Icons.Filled.Menu,
|
||||
contentDescription = "Open Drawer",
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = "Hermes",
|
||||
style =
|
||||
MaterialTheme.typography.titleLarge.copy(
|
||||
fontWeight = FontWeight.Bold,
|
||||
),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
// Connection status dot
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.size(10.dp)
|
||||
.clip(CircleShape)
|
||||
.background(if (state.isConnected) StatusGreen else StatusRed),
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = { viewModel.createNewSession() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Add,
|
||||
contentDescription = "New Chat",
|
||||
)
|
||||
}
|
||||
|
||||
// Session picker
|
||||
Box {
|
||||
IconButton(onClick = {
|
||||
viewModel.loadSessions()
|
||||
viewModel.toggleSessionPicker()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.History,
|
||||
contentDescription = "Sessions",
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = state.showSessionPicker,
|
||||
onDismissRequest = { viewModel.toggleSessionPicker() },
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
Icons.Filled.Add,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(18.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text("New Session")
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
viewModel.createNewSession()
|
||||
viewModel.toggleSessionPicker()
|
||||
},
|
||||
)
|
||||
if (state.sessions.isNotEmpty()) {
|
||||
HorizontalDivider()
|
||||
}
|
||||
state.sessions.forEach { session ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Column {
|
||||
Text(
|
||||
text = session.title,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
maxLines = 1,
|
||||
)
|
||||
Text(
|
||||
text = "${session.messageCount} messages",
|
||||
style =
|
||||
MaterialTheme.typography.labelSmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = { viewModel.switchSession(session.id) },
|
||||
trailingIcon = {
|
||||
if (session.id == state.currentSessionId) {
|
||||
Icon(
|
||||
Icons.Filled.ArrowDropDown,
|
||||
contentDescription = "Current",
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(18.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Settings
|
||||
IconButton(onClick = onNavigateToSettings) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Settings,
|
||||
contentDescription = "Settings",
|
||||
)
|
||||
}
|
||||
},
|
||||
colors =
|
||||
TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
),
|
||||
)
|
||||
HermesScaffold(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = "Hermes",
|
||||
style =
|
||||
MaterialTheme.typography.titleLarge.copy(
|
||||
fontWeight = FontWeight.Bold,
|
||||
),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
// Connection status dot
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.size(10.dp)
|
||||
.clip(CircleShape)
|
||||
.background(if (state.isConnected) StatusGreen else StatusRed),
|
||||
)
|
||||
}
|
||||
},
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
snackbarHost = {
|
||||
SnackbarHost(snackbarHostState) { data ->
|
||||
Snackbar(
|
||||
@@ -300,6 +192,92 @@ fun ChatScreen(
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = { viewModel.createNewSession() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Add,
|
||||
contentDescription = "New Chat",
|
||||
)
|
||||
}
|
||||
|
||||
// Session picker
|
||||
Box {
|
||||
IconButton(onClick = {
|
||||
viewModel.loadSessions()
|
||||
viewModel.toggleSessionPicker()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.History,
|
||||
contentDescription = "Sessions",
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = state.showSessionPicker,
|
||||
onDismissRequest = { viewModel.toggleSessionPicker() },
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
Icons.Filled.Add,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(18.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text("New Session")
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
viewModel.createNewSession()
|
||||
viewModel.toggleSessionPicker()
|
||||
},
|
||||
)
|
||||
if (state.sessions.isNotEmpty()) {
|
||||
HorizontalDivider()
|
||||
}
|
||||
state.sessions.forEach { session ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Column {
|
||||
Text(
|
||||
text = session.title,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
maxLines = 1,
|
||||
)
|
||||
Text(
|
||||
text = "${session.messageCount} messages",
|
||||
style =
|
||||
MaterialTheme.typography.labelSmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = { viewModel.switchSession(session.id) },
|
||||
trailingIcon = {
|
||||
if (session.id == state.currentSessionId) {
|
||||
Icon(
|
||||
Icons.Filled.ArrowDropDown,
|
||||
contentDescription = "Current",
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(18.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Settings
|
||||
IconButton(onClick = onNavigateToSettings) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Settings,
|
||||
contentDescription = "Settings",
|
||||
)
|
||||
}
|
||||
},
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier =
|
||||
|
||||
@@ -13,7 +13,6 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -35,21 +34,24 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun HermesScaffold(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
title: @Composable () -> Unit,
|
||||
onOpenDrawer: (() -> Unit)? = null,
|
||||
onRefresh: (() -> Unit)? = null,
|
||||
onBack: (() -> Unit)? = null,
|
||||
showBack: Boolean = false,
|
||||
snackbarHost: @Composable () -> Unit = {},
|
||||
actions: @Composable () -> Unit = {},
|
||||
content: @Composable (PaddingValues) -> Unit,
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
snackbarHost = { snackbarHost() },
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text(title) },
|
||||
title = title,
|
||||
navigationIcon = {
|
||||
when {
|
||||
showBack && onBack != null -> {
|
||||
|
||||
@@ -57,7 +57,7 @@ fun ConfigScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Configuration",
|
||||
title = { Text("Configuration") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadRawConfig() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -59,7 +59,7 @@ fun CronJobsScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Cron Jobs",
|
||||
title = { Text("Cron Jobs") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadCronJobs() },
|
||||
) {
|
||||
|
||||
@@ -62,7 +62,7 @@ fun GatewayScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Gateway Control",
|
||||
title = { Text("Gateway Control") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadStatus() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -71,7 +71,7 @@ fun KanbanScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Kanban Board",
|
||||
title = { Text("Kanban Board") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadBoards() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -66,7 +66,7 @@ fun KeysScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Keys & Credentials",
|
||||
title = { Text("Keys & Credentials") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadKeys() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -59,7 +59,7 @@ fun LogsScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Logs",
|
||||
title = { Text("Logs") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadLogs() },
|
||||
) {
|
||||
|
||||
@@ -59,7 +59,7 @@ fun McpServersScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "MCP Servers",
|
||||
title = { Text("MCP Servers") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadServers() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -66,7 +66,7 @@ fun ModelScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Models",
|
||||
title = { Text("Models") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadModelOptions() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -58,7 +58,7 @@ fun PairingScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Device Pairing",
|
||||
title = { Text("Device Pairing") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadPairing() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -57,7 +57,7 @@ fun PluginsScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Plugins",
|
||||
title = { Text("Plugins") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadPlugins() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -70,7 +70,7 @@ fun ProfilesScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Profiles",
|
||||
title = { Text("Profiles") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadProfiles() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -67,7 +67,7 @@ fun SettingsScreen(
|
||||
BackHandler(onBack = onBack)
|
||||
|
||||
HermesScaffold(
|
||||
title = "Settings",
|
||||
title = { Text("Settings") },
|
||||
showBack = true,
|
||||
onBack = onBack,
|
||||
) {
|
||||
|
||||
@@ -72,7 +72,7 @@ fun SkillsScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Skills",
|
||||
title = { Text("Skills") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadSkills() },
|
||||
) {
|
||||
|
||||
@@ -65,7 +65,7 @@ fun SystemScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "System",
|
||||
title = { Text("System") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadSystemData() },
|
||||
) {
|
||||
|
||||
@@ -62,7 +62,7 @@ fun ToolsetsScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Toolsets",
|
||||
title = { Text("Toolsets") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadToolsets() },
|
||||
) { paddingValues ->
|
||||
|
||||
@@ -60,7 +60,7 @@ fun WebhooksScreen(
|
||||
}
|
||||
|
||||
HermesScaffold(
|
||||
title = "Webhooks",
|
||||
title = { Text("Webhooks") },
|
||||
onOpenDrawer = onOpenDrawer,
|
||||
onRefresh = { viewModel.loadWebhooks() },
|
||||
) { paddingValues ->
|
||||
|
||||
Reference in new issue
Block a user