git.iko.soy/opencode-android
on master help sign in
Fix streaming auto-scroll not firing on text part updates and add loading indicator to crash report dialog
commitf2ff2ebfb244da98e4694a7d4c832e73ea71773f authoriko <mail@iko.soy> dateTue 30 Jun 2026, 12:11 (3 months ago) parentf4d8754
2 files changed+31−7
app/src/main/java/soy/iko/opencode/ui/chat/ChatScreen.kt+13−2 app/src/main/java/soy/iko/opencode/ui/settings/DiagnosticsScreen.kt+18−5
app/src/main/java/soy/iko/opencode/ui/chat/ChatScreen.kt+13−2
@@ -85,6 +85,7 @@ import kotlinx.coroutines.Dispatchers
8585import kotlinx.coroutines.flow.collectLatest
8686import kotlinx.coroutines.launch
8787import kotlinx.coroutines.withContext
88+import soy.iko.opencode.data.model.TextPart
8889import soy.iko.opencode.data.network.EventStreamClient
8990import soy.iko.opencode.di.AppContainer
9091import soy.iko.opencode.R
@@ -188,9 +189,19 @@ fun ChatScreen(
188189 // churn that keying on lastPartLen (which changes on every streaming token) caused.
189190 // collectLatest cancels the in-flight scroll when a newer snapshot arrives, so
190191 // streaming stays smooth without dozens of competing animations per second.
192+ //
193+ // The second Triple component tracks the total text length of the last message's
194+ // parts. When a streaming token updates an existing TextPart (same part ID, longer
195+ // text), messages.size and parts.size don't change — without the text length, the
196+ // snapshotFlow wouldn't emit and the view wouldn't auto-scroll to follow the stream.
191197 LaunchedEffect(Unit) {
192− snapshotFlow { Triple(messages.size, messages.lastOrNull()?.parts?.size, isPinnedToBottom) }
193− .collectLatest { (_, _, pinned) ->
198+ snapshotFlow {
199+ Triple(
200+ messages.size,
201+ messages.lastOrNull()?.parts?.sumOf { (it as? TextPart)?.text?.length ?: 0 } ?: 0,
202+ isPinnedToBottom,
203+ )
204+ }.collectLatest { (_, _, pinned) ->
194205 if (messages.isNotEmpty() && pinned) {
195206 listState.animateScrollToItem(messages.lastIndex)
196207 }
app/src/main/java/soy/iko/opencode/ui/settings/DiagnosticsScreen.kt+18−5
@@ -4,6 +4,7 @@ import android.content.Intent
44import android.util.Log
55import androidx.compose.foundation.clickable
66import androidx.compose.foundation.layout.Arrangement
7+import androidx.compose.foundation.layout.Box
78import androidx.compose.foundation.layout.Column
89import androidx.compose.foundation.layout.Row
910import androidx.compose.foundation.layout.Spacer
@@ -19,6 +20,7 @@ import androidx.compose.material.icons.filled.BugReport
1920import androidx.compose.material.icons.filled.DeleteSweep
2021import androidx.compose.material.icons.filled.Share
2122import androidx.compose.material3.AlertDialog
23+import androidx.compose.material3.CircularProgressIndicator
2224import androidx.compose.material3.ExperimentalMaterial3Api
2325import androidx.compose.material3.HorizontalDivider
2426import androidx.compose.material3.Icon
@@ -44,6 +46,7 @@ import androidx.compose.ui.Modifier
4446import androidx.compose.ui.platform.LocalContext
4547import androidx.compose.ui.res.stringResource
4648import androidx.compose.ui.semantics.Role
49+import androidx.compose.ui.semantics.contentDescription
4750import androidx.compose.ui.semantics.heading
4851import androidx.compose.ui.semantics.role
4952import androidx.compose.ui.semantics.semantics
@@ -189,11 +192,21 @@ fun DiagnosticsScreen(onBack: () -> Unit) {
189192 },
190193 title = { Text(stringResource(R.string.crash_report)) },
191194 text = {
192− Text(
193− content ?: "",
194− style = MaterialTheme.typography.bodySmall,
195− modifier = Modifier.fillMaxWidth(),
196− )
195+ if (content != null) {
196+ Text(
197+ content,
198+ style = MaterialTheme.typography.bodySmall,
199+ modifier = Modifier.fillMaxWidth(),
200+ )
201+ } else {
202+ val loadingLabel = stringResource(R.string.loading)
203+ Box(
204+ modifier = Modifier.fillMaxWidth().padding(vertical = 24.dp),
205+ contentAlignment = Alignment.Center,
206+ ) {
207+ CircularProgressIndicator(Modifier.semantics { contentDescription = loadingLabel })
208+ }
209+ }
197210 },
198211 )
199212 }