From 91ad09b5f2d2bed3d881ab7f40321d71bb26ed28 Mon Sep 17 00:00:00 2001 From: Hy4ri Date: Fri, 19 Jun 2026 18:02:49 +0300 Subject: [PATCH 1/3] fix(navigation): dynamically update bottom navigation items --- app/src/main/java/com/m57/hermescontrol/Navigation.kt | 11 +++++------ .../com/m57/hermescontrol/data/local/AuthManager.kt | 9 +++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/m57/hermescontrol/Navigation.kt b/app/src/main/java/com/m57/hermescontrol/Navigation.kt index c2722382..9fa9e80f 100644 --- a/app/src/main/java/com/m57/hermescontrol/Navigation.kt +++ b/app/src/main/java/com/m57/hermescontrol/Navigation.kt @@ -179,12 +179,11 @@ fun MainNavigation() { val scope = rememberCoroutineScope() // Read dynamic bottom-nav config. - // NB: deliberately NOT wrapped in remember { … } — AuthManager values change - // when the user customises items in Settings (saved to SharedPreferences). - // Without a key that tracks prefs changes, remember would cache the stale - // defaults and the NavigationBar would never reflect the user's picks. - // Reading fresh on every recomposition is negligible (pure map over 18 items). - val bottomNavItems = resolveBottomNavItems(AuthManager.getBottomNavItems()) + // AuthManager.bottomNavItemsFlow is a StateFlow that emits updates when the user + // customises items in Settings. Using collectAsState() ensures the NavigationBar + // recomposes and reflects choices instantly. + val bottomNavItemsState by AuthManager.bottomNavItemsFlow.collectAsState() + val bottomNavItems = resolveBottomNavItems(bottomNavItemsState) val bottomNavKeys = remember(bottomNavItems) { bottomNavItems.map { it.key }.toSet() } // Sync primary screens to NavigationController diff --git a/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt b/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt index fc399fd9..29389ab8 100644 --- a/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt +++ b/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt @@ -5,6 +5,9 @@ import android.content.SharedPreferences import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey import com.m57.hermescontrol.theme.ThemePreference +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow /** * Singleton that manages encrypted storage of the Hermes dashboard token @@ -29,6 +32,9 @@ object AuthManager { @Volatile private var prefs: SharedPreferences? = null + private val _bottomNavItemsFlow = MutableStateFlow>(emptyList()) + val bottomNavItemsFlow: StateFlow> = _bottomNavItemsFlow.asStateFlow() + /** * Initialise the encrypted preferences. * Call this once from Application.onCreate() or MainActivity.onCreate(). @@ -51,6 +57,8 @@ object AuthManager { EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, ) + + _bottomNavItemsFlow.value = getBottomNavItems() } } @@ -134,5 +142,6 @@ object AuthManager { /** Persist the ordered list of bottom-nav item keys (max 5, data-object names). */ fun setBottomNavItems(items: List) { requirePrefs().edit().putString(KEY_BOTTOM_NAV_ITEMS, items.joinToString(",")).apply() + _bottomNavItemsFlow.value = items } } From 9e3a7ab339f693fc8fc5c8b6e0c394207143d5af Mon Sep 17 00:00:00 2001 From: Hy4ri Date: Fri, 19 Jun 2026 18:14:41 +0300 Subject: [PATCH 2/3] fix: always show bottom bar, resolve chat input double padding, and format codebase --- .../java/com/m57/hermescontrol/Navigation.kt | 16 +++++++++---- .../notification/ChatNotificationService.kt | 2 ++ .../ui/achievements/AchievementsScreen.kt | 3 +++ .../ui/channels/ChannelsScreen.kt | 3 +++ .../m57/hermescontrol/ui/chat/ChatBubble.kt | 9 ++++---- .../m57/hermescontrol/ui/chat/ChatScreen.kt | 5 ++-- .../hermescontrol/ui/chat/ChatViewModel.kt | 4 +++- .../hermescontrol/ui/common/HermesScaffold.kt | 1 + .../ui/common/SharedComponents.kt | 23 +++++++++++++++---- .../hermescontrol/ui/config/ConfigScreen.kt | 5 +++- .../hermescontrol/ui/cron/CronJobsScreen.kt | 16 +++++++++---- .../hermescontrol/ui/gateway/GatewayScreen.kt | 5 +++- .../hermescontrol/ui/kanban/KanbanScreen.kt | 5 +++- .../m57/hermescontrol/ui/keys/KeysScreen.kt | 5 +++- .../m57/hermescontrol/ui/logs/LogsScreen.kt | 16 +++++++++---- .../hermescontrol/ui/mcp/McpServersScreen.kt | 5 +++- .../m57/hermescontrol/ui/model/ModelScreen.kt | 8 +++++-- .../hermescontrol/ui/pairing/PairingScreen.kt | 5 +++- .../hermescontrol/ui/plugins/PluginsScreen.kt | 5 +++- .../ui/profiles/ProfilesScreen.kt | 5 +++- .../hermescontrol/ui/skills/SkillsScreen.kt | 16 +++++++++---- .../hermescontrol/ui/system/SystemScreen.kt | 16 +++++++++---- .../ui/toolsets/ToolsetsScreen.kt | 5 +++- .../ui/webhooks/WebhooksScreen.kt | 5 +++- 24 files changed, 143 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/m57/hermescontrol/Navigation.kt b/app/src/main/java/com/m57/hermescontrol/Navigation.kt index 9fa9e80f..647d807d 100644 --- a/app/src/main/java/com/m57/hermescontrol/Navigation.kt +++ b/app/src/main/java/com/m57/hermescontrol/Navigation.kt @@ -128,7 +128,9 @@ private fun resolveBottomNavItems(names: List): List = // ── Drawer sections for secondary screens ────────────────────────────── -private enum class DrawerSection(val title: String) { +private enum class DrawerSection( + val title: String, +) { CONVERSE("Converse"), AUTOMATE("Automate"), CONFIGURE("Configure"), @@ -191,7 +193,7 @@ fun MainNavigation() { NavigationController.updatePrimaryScreens(bottomNavKeys) } - val isPrimaryScreen = currentScreen in bottomNavKeys + val showBottomBar = currentScreen != ConnectScreen val gesturesEnabled = currentScreen in DRAWER_GESTURE_SCREENS val openDrawer = { scope.launch { drawerState.open() } } @@ -207,10 +209,14 @@ fun MainNavigation() { val connectionStatus by HermesWsClient.connectionStatus.collectAsState() val statusColor = when (connectionStatus) { - ConnectionStatus.CONNECTED -> Color(0xFF4CAF50) // green + ConnectionStatus.CONNECTED -> Color(0xFF4CAF50) + + // green ConnectionStatus.CONNECTING, ConnectionStatus.RECONNECTING, - -> Color(0xFFFFC107) // yellow + -> Color(0xFFFFC107) + + // yellow ConnectionStatus.DISCONNECTED -> Color(0xFFF44336) // red } Row( @@ -287,7 +293,7 @@ fun MainNavigation() { Scaffold( contentWindowInsets = WindowInsets.navigationBars, bottomBar = { - if (isPrimaryScreen) { + if (showBottomBar) { NavigationBar { bottomNavItems.forEach { item -> NavigationBarItem( diff --git a/app/src/main/java/com/m57/hermescontrol/notification/ChatNotificationService.kt b/app/src/main/java/com/m57/hermescontrol/notification/ChatNotificationService.kt index 38714b49..d2944266 100644 --- a/app/src/main/java/com/m57/hermescontrol/notification/ChatNotificationService.kt +++ b/app/src/main/java/com/m57/hermescontrol/notification/ChatNotificationService.kt @@ -76,9 +76,11 @@ class ChatNotificationService : Service() { .ifBlank { "New message" } showReplyNotification(preview) } + is WsEvent.ClarifyRequest -> { showReplyNotification("Hermes needs a clarification") } + else -> {} } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/achievements/AchievementsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/achievements/AchievementsScreen.kt index c0b4b8f1..9ad5c8ff 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/achievements/AchievementsScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/achievements/AchievementsScreen.kt @@ -54,6 +54,7 @@ fun AchievementsScreen( state.isLoading && state.achievements.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null && state.achievements.isEmpty() -> { ErrorState( message = state.errorMessage ?: "", @@ -61,6 +62,7 @@ fun AchievementsScreen( modifier = Modifier.padding(paddingValues), ) } + state.achievements.isEmpty() -> { EmptyState( title = "No achievements yet", @@ -69,6 +71,7 @@ fun AchievementsScreen( modifier = Modifier.padding(paddingValues), ) } + else -> { LazyColumn( modifier = Modifier.fillMaxSize().padding(paddingValues), diff --git a/app/src/main/java/com/m57/hermescontrol/ui/channels/ChannelsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/channels/ChannelsScreen.kt index f671979f..5d14f06d 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/channels/ChannelsScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/channels/ChannelsScreen.kt @@ -68,6 +68,7 @@ fun ChannelsScreen( state.isLoading && state.platforms.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -75,6 +76,7 @@ fun ChannelsScreen( modifier = Modifier.padding(paddingValues), ) } + state.platforms.isEmpty() -> { EmptyState( title = "No channels configured", @@ -82,6 +84,7 @@ fun ChannelsScreen( modifier = Modifier.padding(paddingValues), ) } + else -> { LazyColumn( modifier = Modifier.fillMaxSize().padding(paddingValues), diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatBubble.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatBubble.kt index c0fc9916..1de3438d 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatBubble.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatBubble.kt @@ -201,8 +201,7 @@ private fun AssistantBubble( bottomStart = 16.dp, bottomEnd = 16.dp, ), - ) - .pointerInput(message.content) { + ).pointerInput(message.content) { detectTapGestures( onLongPress = { clipboardManager.setText(AnnotatedString(message.content)) @@ -459,8 +458,10 @@ private fun RichText( text = annotated, style = MaterialTheme.typography.bodyMedium.copy(color = textColor), onClick = { offset: Int -> - annotated.getStringAnnotations("URL", offset, offset) - .firstOrNull()?.let { uriHandler.openUri(it.item) } + annotated + .getStringAnnotations("URL", offset, offset) + .firstOrNull() + ?.let { uriHandler.openUri(it.item) } }, ) } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt index 850a3191..a9f264f6 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt @@ -116,10 +116,12 @@ fun ChatScreen( NotificationHelper.setAppForeground(context, true) NotificationHelper.stop(context) } + androidx.lifecycle.Lifecycle.Event.ON_STOP -> { NotificationHelper.setAppForeground(context, false) NotificationHelper.start(context) } + else -> {} } } @@ -320,12 +322,11 @@ fun ChatScreen( ) } }, - ) { paddingValues -> + ) { _ -> Column( modifier = Modifier .fillMaxSize() - .padding(paddingValues) .background(backgroundGradient) .imePadding(), ) { diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt index 3525dd25..96e7c08f 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt @@ -51,7 +51,9 @@ data class ClarifyUi( val options: List, ) -class ChatViewModel(application: Application) : AndroidViewModel(application) { +class ChatViewModel( + application: Application, +) : AndroidViewModel(application) { private val _uiState = MutableStateFlow(ChatUiState()) val uiState: StateFlow = _uiState.asStateFlow() diff --git a/app/src/main/java/com/m57/hermescontrol/ui/common/HermesScaffold.kt b/app/src/main/java/com/m57/hermescontrol/ui/common/HermesScaffold.kt index 47d32fad..210ab6c7 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/common/HermesScaffold.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/common/HermesScaffold.kt @@ -64,6 +64,7 @@ fun HermesScaffold( ) } } + onOpenDrawer != null -> { IconButton(onClick = onOpenDrawer) { Icon( diff --git a/app/src/main/java/com/m57/hermescontrol/ui/common/SharedComponents.kt b/app/src/main/java/com/m57/hermescontrol/ui/common/SharedComponents.kt index 82942e6e..b481e37d 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/common/SharedComponents.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/common/SharedComponents.kt @@ -75,13 +75,26 @@ fun StatusBadge( val statusColors = LocalHermesStatusColors.current val (bgColor, fgColor) = when (status) { - StatusBadgeType.SUCCESS -> statusColors.successContainer to statusColors.success - StatusBadgeType.WARNING -> statusColors.warningContainer to statusColors.warning - StatusBadgeType.ERROR -> statusColors.errorContainer to statusColors.error - StatusBadgeType.INFO -> statusColors.infoContainer to statusColors.info - StatusBadgeType.NEUTRAL -> + StatusBadgeType.SUCCESS -> { + statusColors.successContainer to statusColors.success + } + + StatusBadgeType.WARNING -> { + statusColors.warningContainer to statusColors.warning + } + + StatusBadgeType.ERROR -> { + statusColors.errorContainer to statusColors.error + } + + StatusBadgeType.INFO -> { + statusColors.infoContainer to statusColors.info + } + + StatusBadgeType.NEUTRAL -> { MaterialTheme.colorScheme.surfaceContainerHigh to MaterialTheme.colorScheme.onSurfaceVariant + } } Surface( modifier = modifier, diff --git a/app/src/main/java/com/m57/hermescontrol/ui/config/ConfigScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/config/ConfigScreen.kt index 22a3542c..20000ee7 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/config/ConfigScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/config/ConfigScreen.kt @@ -66,6 +66,7 @@ fun ConfigScreen( state.isLoading && state.yamlText == null -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -73,7 +74,8 @@ fun ConfigScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.yamlText == null) { CircularProgressIndicator() @@ -143,6 +145,7 @@ fun ConfigScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/cron/CronJobsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/cron/CronJobsScreen.kt index 5f9b4a46..8a1e931c 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/cron/CronJobsScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/cron/CronJobsScreen.kt @@ -65,19 +65,26 @@ fun CronJobsScreen( onRefresh = { viewModel.loadCronJobs() }, ) { when { - state.isLoading && state.jobs.isEmpty() -> LoadingState() - state.errorMessage != null -> + state.isLoading && state.jobs.isEmpty() -> { + LoadingState() + } + + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "Unknown error", onRetry = { viewModel.loadCronJobs() }, ) - state.jobs.isEmpty() -> + } + + state.jobs.isEmpty() -> { EmptyState( title = "No cron jobs", subtitle = "Scheduled tasks from Hermes will appear here.", icon = Icons.Filled.Schedule, ) - else -> + } + + else -> { LazyColumn( modifier = Modifier.fillMaxWidth(), contentPadding = listContentPadding, @@ -160,6 +167,7 @@ fun CronJobsScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/gateway/GatewayScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/gateway/GatewayScreen.kt index eb589ea0..1bb314ca 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/gateway/GatewayScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/gateway/GatewayScreen.kt @@ -71,6 +71,7 @@ fun GatewayScreen( state.isLoading && state.status == null -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -78,7 +79,8 @@ fun GatewayScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.status == null) { CircularProgressIndicator() @@ -285,6 +287,7 @@ fun GatewayScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/kanban/KanbanScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/kanban/KanbanScreen.kt index d4a757e2..206044c4 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/kanban/KanbanScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/kanban/KanbanScreen.kt @@ -80,6 +80,7 @@ fun KanbanScreen( state.isLoading && state.boards.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -87,7 +88,8 @@ fun KanbanScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading) { CircularProgressIndicator() @@ -189,6 +191,7 @@ fun KanbanScreen( ) } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/keys/KeysScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/keys/KeysScreen.kt index 3436811f..03225281 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/keys/KeysScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/keys/KeysScreen.kt @@ -75,6 +75,7 @@ fun KeysScreen( state.isLoading && state.envVars.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -82,7 +83,8 @@ fun KeysScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading) { CircularProgressIndicator() @@ -205,6 +207,7 @@ fun KeysScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt index 879e5ecd..0c7b37e7 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt @@ -65,13 +65,18 @@ fun LogsScreen( onRefresh = { viewModel.loadLogs() }, ) { when { - state.isLoading && state.logs.isEmpty() -> LoadingState() - state.errorMessage != null -> + state.isLoading && state.logs.isEmpty() -> { + LoadingState() + } + + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "Unknown error", onRetry = { viewModel.loadLogs() }, ) - state.logs.isEmpty() -> + } + + state.logs.isEmpty() -> { // B5 (Jun 18 2026, kanban t_2322818d): proper empty-state using // the shared EmptyState component instead of a bare Text. EmptyState( @@ -79,7 +84,9 @@ fun LogsScreen( subtitle = "Log output from Hermes will appear here.", icon = Icons.Filled.HistoryEdu, ) - else -> + } + + else -> { LazyColumn( state = listState, modifier = @@ -105,6 +112,7 @@ fun LogsScreen( ) } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/mcp/McpServersScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/mcp/McpServersScreen.kt index 98257b14..acb2dc14 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/mcp/McpServersScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/mcp/McpServersScreen.kt @@ -68,6 +68,7 @@ fun McpServersScreen( state.isLoading && state.servers.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -75,7 +76,8 @@ fun McpServersScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.servers.isEmpty()) { CircularProgressIndicator() @@ -181,6 +183,7 @@ fun McpServersScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt index 0ac80e88..af76873d 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt @@ -75,6 +75,7 @@ fun ModelScreen( state.isLoading && state.providers.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -82,7 +83,8 @@ fun ModelScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.providers.isEmpty()) { CircularProgressIndicator() @@ -201,7 +203,8 @@ fun ModelScreen( containerColor = if (isActive) { MaterialTheme.colorScheme - .primaryContainer.copy( + .primaryContainer + .copy( alpha = 0.3f, ) } else { @@ -264,6 +267,7 @@ fun ModelScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/pairing/PairingScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/pairing/PairingScreen.kt index 4bc1f4ef..367e51b5 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/pairing/PairingScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/pairing/PairingScreen.kt @@ -67,6 +67,7 @@ fun PairingScreen( state.isLoading && state.pairing == null -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -74,7 +75,8 @@ fun PairingScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.pairing == null) { CircularProgressIndicator() @@ -253,6 +255,7 @@ fun PairingScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/plugins/PluginsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/plugins/PluginsScreen.kt index f8b2f727..6671a315 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/plugins/PluginsScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/plugins/PluginsScreen.kt @@ -66,6 +66,7 @@ fun PluginsScreen( state.isLoading && state.plugins.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -73,7 +74,8 @@ fun PluginsScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading) { CircularProgressIndicator() @@ -150,6 +152,7 @@ fun PluginsScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/profiles/ProfilesScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/profiles/ProfilesScreen.kt index 7b794b8f..cdbd9647 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/profiles/ProfilesScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/profiles/ProfilesScreen.kt @@ -79,6 +79,7 @@ fun ProfilesScreen( state.isLoading && state.profiles.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -86,7 +87,8 @@ fun ProfilesScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.profiles.isEmpty()) { CircularProgressIndicator() @@ -222,6 +224,7 @@ fun ProfilesScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/skills/SkillsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/skills/SkillsScreen.kt index 511bcdf4..599d3902 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/skills/SkillsScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/skills/SkillsScreen.kt @@ -78,19 +78,26 @@ fun SkillsScreen( onRefresh = { viewModel.loadSkills() }, ) { when { - state.isLoading && state.skills.isEmpty() -> LoadingState() - state.errorMessage != null -> + state.isLoading && state.skills.isEmpty() -> { + LoadingState() + } + + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "Unknown error", onRetry = { viewModel.loadSkills() }, ) - state.skills.isEmpty() -> + } + + state.skills.isEmpty() -> { EmptyState( title = "No skills found", subtitle = "Skills loaded from Hermes will appear here.", icon = Icons.Filled.Extension, ) - else -> + } + + else -> { LazyColumn( modifier = Modifier.fillMaxWidth(), contentPadding = listContentPadding, @@ -162,6 +169,7 @@ fun SkillsScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt index a5333783..2a307707 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt @@ -71,18 +71,25 @@ fun SystemScreen( onRefresh = { viewModel.loadSystemData() }, ) { when { - state.isLoading && state.stats == null && state.doctorReport == null -> LoadingState() - state.errorMessage != null -> + state.isLoading && state.stats == null && state.doctorReport == null -> { + LoadingState() + } + + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "Unknown error", onRetry = { viewModel.loadSystemData() }, ) - state.stats == null && state.doctorReport == null -> + } + + state.stats == null && state.doctorReport == null -> { EmptyState( title = "No system data", subtitle = "Tap refresh to load system diagnostics.", ) - else -> + } + + else -> { LazyColumn( modifier = Modifier.fillMaxWidth(), contentPadding = @@ -200,6 +207,7 @@ fun SystemScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/toolsets/ToolsetsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/toolsets/ToolsetsScreen.kt index d81e305c..2579dda5 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/toolsets/ToolsetsScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/toolsets/ToolsetsScreen.kt @@ -71,6 +71,7 @@ fun ToolsetsScreen( state.isLoading && state.toolsets.isEmpty() -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -78,7 +79,8 @@ fun ToolsetsScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.toolsets.isEmpty()) { CircularProgressIndicator() @@ -171,6 +173,7 @@ fun ToolsetsScreen( } } } + } } } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/webhooks/WebhooksScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/webhooks/WebhooksScreen.kt index 543ed871..b6b0c958 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/webhooks/WebhooksScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/webhooks/WebhooksScreen.kt @@ -69,6 +69,7 @@ fun WebhooksScreen( state.isLoading && state.baseUrl == null -> { LoadingState(modifier = Modifier.padding(paddingValues)) } + state.errorMessage != null -> { ErrorState( message = state.errorMessage ?: "", @@ -76,7 +77,8 @@ fun WebhooksScreen( modifier = Modifier.padding(paddingValues), ) } - else -> + + else -> { Box(Modifier.fillMaxSize()) { if (state.isLoading && state.baseUrl == null) { CircularProgressIndicator() @@ -234,6 +236,7 @@ fun WebhooksScreen( } } } + } } } } From 3a610c7c804caf03e429e89a9b0e467b35ac08c0 Mon Sep 17 00:00:00 2001 From: Hy4ri Date: Fri, 19 Jun 2026 18:23:17 +0300 Subject: [PATCH 3/3] fix(ci): fix trailing spaces and revert visibility/padding changes --- app/src/main/java/com/m57/hermescontrol/Navigation.kt | 4 ++-- .../main/java/com/m57/hermescontrol/data/local/AuthManager.kt | 2 +- app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/m57/hermescontrol/Navigation.kt b/app/src/main/java/com/m57/hermescontrol/Navigation.kt index 647d807d..82870c8c 100644 --- a/app/src/main/java/com/m57/hermescontrol/Navigation.kt +++ b/app/src/main/java/com/m57/hermescontrol/Navigation.kt @@ -193,7 +193,7 @@ fun MainNavigation() { NavigationController.updatePrimaryScreens(bottomNavKeys) } - val showBottomBar = currentScreen != ConnectScreen + val isPrimaryScreen = currentScreen in bottomNavKeys val gesturesEnabled = currentScreen in DRAWER_GESTURE_SCREENS val openDrawer = { scope.launch { drawerState.open() } } @@ -293,7 +293,7 @@ fun MainNavigation() { Scaffold( contentWindowInsets = WindowInsets.navigationBars, bottomBar = { - if (showBottomBar) { + if (isPrimaryScreen) { NavigationBar { bottomNavItems.forEach { item -> NavigationBarItem( diff --git a/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt b/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt index 29389ab8..7f024aee 100644 --- a/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt +++ b/app/src/main/java/com/m57/hermescontrol/data/local/AuthManager.kt @@ -57,7 +57,7 @@ object AuthManager { EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, ) - + _bottomNavItemsFlow.value = getBottomNavItems() } } diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt index a9f264f6..a4b379c6 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt @@ -322,11 +322,12 @@ fun ChatScreen( ) } }, - ) { _ -> + ) { paddingValues -> Column( modifier = Modifier .fillMaxSize() + .padding(paddingValues) .background(backgroundGradient) .imePadding(), ) {