feat: add connection status indicator (Issue #28)

Adds a colored dot next to the '⚡ Hermes' brand header in the
navigation drawer:
  - Green: connected
  - Yellow: connecting / reconnecting
  - Red: disconnected

Uses a StateFlow on HermesWsClient that tracks the WebSocket
connection lifecycle and is collected in the drawer header.
This commit is contained in:
M57 committed 2026-06-19 12:07:44 +03:00
1 parent 0fa61148a3
commit 0038606c05
2 files changed
+63 -12

No files matched your search

@@ -1,5 +1,8 @@
package com.m57.hermescontrol
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
@@ -7,7 +10,10 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Chat
@@ -39,12 +45,15 @@ import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -53,6 +62,8 @@ import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay
import com.m57.hermescontrol.data.local.AuthManager
import com.m57.hermescontrol.data.ws.ConnectionStatus
import com.m57.hermescontrol.data.ws.HermesWsClient
import kotlinx.coroutines.launch
import com.m57.hermescontrol.ui.achievements.AchievementsScreen as AchievementsScreenContent
import com.m57.hermescontrol.ui.channels.ChannelsScreen as ChannelsScreenContent
@@ -188,16 +199,34 @@ fun MainNavigation() {
ModalDrawerSheet(
modifier = Modifier.verticalScroll(rememberScrollState()),
) {
// Brand header
Text(
text = "⚡ Hermes",
// Brand header with connection status
val connectionStatus by HermesWsClient.connectionStatus.collectAsState()
val statusColor = when (connectionStatus) {
ConnectionStatus.CONNECTED -> Color(0xFF4CAF50) // green
ConnectionStatus.CONNECTING,
ConnectionStatus.RECONNECTING -> Color(0xFFFFC107) // yellow
ConnectionStatus.DISCONNECTED -> Color(0xFFF44336) // red
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(start = 20.dp, top = 20.dp, end = 16.dp, bottom = 4.dp),
style =
MaterialTheme.typography.headlineSmall.copy(
fontWeight = FontWeight.Bold,
),
color = MaterialTheme.colorScheme.primary,
)
) {
Text(
text = "⚡ Hermes",
style =
MaterialTheme.typography.headlineSmall.copy(
fontWeight = FontWeight.Bold,
),
color = MaterialTheme.colorScheme.primary,
)
Spacer(modifier = Modifier.width(8.dp))
Box(
modifier =
Modifier
.size(10.dp)
.background(color = statusColor, shape = CircleShape),
)
}
Text(
text = "AI Agent Control",
modifier = Modifier.padding(start = 20.dp, bottom = 12.dp, end = 16.dp),