diff --git a/app/androidApp/src/main/kotlin/com/example/aiapp/SessionListScreen.kt b/app/androidApp/src/main/kotlin/com/example/aiapp/SessionListScreen.kt index c36d310..e702d75 100644 --- a/app/androidApp/src/main/kotlin/com/example/aiapp/SessionListScreen.kt +++ b/app/androidApp/src/main/kotlin/com/example/aiapp/SessionListScreen.kt @@ -57,11 +57,25 @@ fun SessionListScreen( var listState by remember { mutableStateOf>>(LoadState.Loading) } var confirmingDelete by remember { mutableStateOf(null) } + // Failures that belong to one session rather than to the list, keyed by + // its id and shown on its own card. The two scopes are decided by + // whether the server answered: it answered and refused, so this says + // nothing about the other rows, where a server that has stopped + // answering leaves every row stale and is `listState`'s to report. + // + // Cleared on the next successful load below -- an entry outlives its + // session otherwise, and would reappear against whatever the phone + // fetched next. + var deleteErrors by remember { mutableStateOf>(emptyMap()) } + fun refresh() { listState = LoadState.Loading scope.launch { listState = try { - withContext(Dispatchers.IO) { LoadState.Loaded(fetchSessions(settings)) } + val loaded = + withContext(Dispatchers.IO) { LoadState.Loaded(fetchSessions(settings)) } + deleteErrors = emptyMap() + loaded } catch (e: ApiException) { LoadState.failed(e) } @@ -114,6 +128,7 @@ fun SessionListScreen( items(ordered, key = { it.id }) { session -> SessionCard( session = session, + error = deleteErrors[session.id], onOpen = { onOpen(session) }, onLongPress = { confirmingDelete = session }, ) @@ -143,7 +158,8 @@ fun SessionListScreen( withContext(Dispatchers.IO) { deleteSession(settings, session.id) } refresh() } catch (e: ApiException) { - listState = LoadState.Error(e.message ?: "Delete failed") + deleteErrors = + deleteErrors + (session.id to (e.message ?: "Delete failed")) } } }) { Text("Delete") } @@ -159,6 +175,8 @@ fun SessionListScreen( @Composable private fun SessionCard( session: SessionSummary, + /** What went wrong acting on *this* session, if anything has. */ + error: String?, onOpen: () -> Unit, onLongPress: () -> Unit, ) { @@ -194,6 +212,16 @@ private fun SessionCard( color = MaterialTheme.colorScheme.onSurfaceVariant, ) } + error?.let { + Spacer(Modifier.height(8.dp)) + // The server's own words, unprefixed, the way every other + // failure in this app is shown. + Text( + it, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.error, + ) + } } } }