@@ -19,9 +19,11 @@ import androidx.compose.material.icons.Icons
1919import androidx.compose.material.icons.automirrored.filled.ArrowBack
2020import androidx.compose.material.icons.filled.Add
2121import androidx.compose.material.icons.filled.ChatBubbleOutline
22+import androidx.compose.material.icons.filled.ChevronRight
2223import androidx.compose.material.icons.filled.DeleteOutline
2324import androidx.compose.material.icons.filled.Refresh
2425import androidx.compose.material3.AlertDialog
26+import androidx.compose.material3.CircularProgressIndicator
2527import androidx.compose.material3.ExperimentalMaterial3Api
2628import androidx.compose.material3.ExtendedFloatingActionButton
2729import androidx.compose.material3.HorizontalDivider
@@ -31,6 +33,7 @@ import androidx.compose.material3.LinearProgressIndicator
3133import androidx.compose.material3.MaterialTheme
3234import androidx.compose.material3.OutlinedTextField
3335import androidx.compose.material3.Scaffold
36+import androidx.compose.material3.Surface
3437import androidx.compose.material3.SwipeToDismissBox
3538import androidx.compose.material3.SwipeToDismissBoxValue
3639import androidx.compose.material3.Text
@@ -117,6 +120,9 @@ fun SessionsScreen(state: UiState, dispatch: (Event) -> Unit) {
117120 },
118121 ) { padding ->
119122 Column(Modifier.fillMaxSize().padding(padding)) {
123+ if (!state.sseConnected) {
124+ ReconnectingBanner()
125+ }
120126 if (state.loading && !isPullRefreshing) {
121127 LinearProgressIndicator(Modifier.fillMaxWidth())
122128 }
@@ -217,6 +223,12 @@ private fun SessionRow(session: SessionView, onOpen: () -> Unit, onDelete: () ->
217223 overflow = TextOverflow.Ellipsis,
218224 )
219225 }
226+ Icon(
227+ Icons.Filled.ChevronRight,
228+ contentDescription = null,
229+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
230+ modifier = Modifier.padding(horizontal = 4.dp),
231+ )
220232 IconButton(onClick = onDelete) {
221233 Icon(
222234 Icons.Filled.DeleteOutline,
@@ -245,6 +257,32 @@ private fun SwipeDeleteBackground() {
245257 }
246258}
247259
260+/** Shown at the top of the list while the SSE stream is down, since session updates stall too. */
261+@Composable
262+private fun ReconnectingBanner() {
263+ Surface(
264+ modifier = Modifier.fillMaxWidth(),
265+ color = MaterialTheme.colorScheme.tertiaryContainer,
266+ ) {
267+ Row(
268+ modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 6.dp),
269+ verticalAlignment = Alignment.CenterVertically,
270+ horizontalArrangement = Arrangement.spacedBy(8.dp),
271+ ) {
272+ CircularProgressIndicator(
273+ modifier = Modifier.size(14.dp),
274+ strokeWidth = 2.dp,
275+ color = MaterialTheme.colorScheme.onTertiaryContainer,
276+ )
277+ Text(
278+ text = "Reconnecting…",
279+ style = MaterialTheme.typography.bodySmall,
280+ color = MaterialTheme.colorScheme.onTertiaryContainer,
281+ )
282+ }
283+ }
284+}
285+
248286/** Shorten a session ID for display: "abc12345…" instead of the full UUID. */
249287private fun shortSessionId(id: String): String =
250288 if (id.length > 12) id.take(8) + "…" else id