git.iko.soy/opencode-android
on 325e359 help sign in
69 lines 2.8 kB history raw
1package soy.iko.opencode.ui.components
3import androidx.compose.foundation.layout.Arrangement
4import androidx.compose.foundation.layout.Row
5import androidx.compose.foundation.layout.fillMaxWidth
6import androidx.compose.foundation.layout.padding
7import androidx.compose.foundation.layout.size
8import androidx.compose.material3.CircularProgressIndicator
9import androidx.compose.material3.MaterialTheme
10import androidx.compose.material3.Surface
11import androidx.compose.material3.Text
12import androidx.compose.runtime.Composable
13import androidx.compose.ui.Alignment
14import androidx.compose.ui.Modifier
15import androidx.compose.ui.res.stringResource
16import androidx.compose.ui.semantics.contentDescription
17import androidx.compose.ui.semantics.liveRegion
18import androidx.compose.ui.semantics.LiveRegionMode
19import androidx.compose.ui.semantics.semantics
20import androidx.compose.ui.unit.dp
21import soy.iko.opencode.R
22import soy.iko.opencode.data.network.EventStreamClient
24/**
25 * Banner shown when the SSE event stream is not connected. Shared by the chat and the
26 * session list so a dropped stream is visible everywhere, not just mid-conversation.
27 */
28@Composable
29fun ConnectionBanner(
30 state: EventStreamClient.ConnectionState,
31 modifier: Modifier = Modifier,
32) {
33 val text = when (state) {
34 EventStreamClient.ConnectionState.Connecting -> stringResource(R.string.connecting)
35 EventStreamClient.ConnectionState.Disconnected -> stringResource(R.string.reconnecting)
36 EventStreamClient.ConnectionState.Failed -> stringResource(R.string.connection_failed)
37 EventStreamClient.ConnectionState.Connected -> null
38 }
39 if (text != null) {
40 Surface(
41 modifier = modifier
42 .fillMaxWidth()
43 .semantics {
44 // Announce connection state changes to TalkBack users so they're
45 // aware the stream dropped/reconnecting without visual cues.
46 liveRegion = LiveRegionMode.Polite
47 contentDescription = text
48 },
49 color = MaterialTheme.colorScheme.tertiaryContainer,
50 ) {
51 Row(
52 modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp),
53 horizontalArrangement = Arrangement.Center,
54 verticalAlignment = Alignment.CenterVertically,
55 ) {
56 CircularProgressIndicator(
57 Modifier.size(12.dp),
58 strokeWidth = 2.dp,
59 )
60 Text(
61 text,
62 style = MaterialTheme.typography.labelMedium,
63 color = MaterialTheme.colorScheme.onTertiaryContainer,
64 modifier = Modifier.padding(start = 6.dp),
65 )
66 }
67 }
68 }