git.iko.soy/opencode-android
on master help sign in
Fix expand/collapse state loss on rotation and stale error snackbars re-showing after navigation
2db74cbiko
app/src/main/java/soy/iko/opencode/ui/chat/ChatScreen.kt+9−6
@@ -200,13 +200,16 @@ fun ChatScreen(
200 val retryLabel = stringResource(R.string.retry)
200 val retryLabel = stringResource(R.string.retry)
201 LaunchedEffect(error) {
201 LaunchedEffect(error) {
202 val msg = error ?: return@LaunchedEffect
202 val msg = error ?: return@LaunchedEffect
203+ try {
203− val result = if (failedDraft != null) {
204+ val result = if (failedDraft != null) {
204− snackbar.showSnackbar(message = msg, actionLabel = retryLabel)
205+ snackbar.showSnackbar(message = msg, actionLabel = retryLabel)
205− } else {
206+ } else {
206− snackbar.showSnackbar(msg)
207+ snackbar.showSnackbar(msg)
208+ }
209+ if (result == androidx.compose.material3.SnackbarResult.ActionPerformed) vm.retryFailed()
210+ } finally {
211+ vm.clearError()
207 }
212 }
208− if (result == androidx.compose.material3.SnackbarResult.ActionPerformed) vm.retryFailed()
209− vm.clearError()
210 }
213 }
211
214
212 fun doSend() {
215 fun doSend() {
app/src/main/java/soy/iko/opencode/ui/chat/PartRenderer.kt+3−2
@@ -29,6 +29,7 @@ import androidx.compose.runtime.Composable
29import androidx.compose.runtime.getValue
29import androidx.compose.runtime.getValue
30import androidx.compose.runtime.mutableStateOf
30import androidx.compose.runtime.mutableStateOf
31import androidx.compose.runtime.remember
31import androidx.compose.runtime.remember
32+import androidx.compose.runtime.saveable.rememberSaveable
32import androidx.compose.runtime.setValue
33import androidx.compose.runtime.setValue
33import androidx.compose.ui.Alignment
34import androidx.compose.ui.Alignment
34import androidx.compose.ui.Modifier
35import androidx.compose.ui.Modifier
@@ -94,7 +95,7 @@ fun PartView(part: Part, modifier: Modifier = Modifier, isRunning: Boolean = fal
94private fun ReasoningBlock(text: String, streaming: Boolean, modifier: Modifier) {
95private fun ReasoningBlock(text: String, streaming: Boolean, modifier: Modifier) {
95 if (text.isBlank()) return
96 if (text.isBlank()) return
96 val context = LocalContext.current
97 val context = LocalContext.current
97− var expanded by remember { mutableStateOf(false) }
98+ var expanded by rememberSaveable { mutableStateOf(false) }
98 val expandedState = stringResource(R.string.state_expanded)
99 val expandedState = stringResource(R.string.state_expanded)
99 val collapsedState = stringResource(R.string.state_collapsed)
100 val collapsedState = stringResource(R.string.state_collapsed)
100 Column(modifier = modifier.fillMaxWidth()) {
101 Column(modifier = modifier.fillMaxWidth()) {
@@ -177,7 +178,7 @@ private fun ToolCallView(part: ToolPart, modifier: Modifier) {
177 }
178 }
178 if (detail != null) {
179 if (detail != null) {
179 val collapsed = remember(detail) { detail.take(COLLAPSED_LIMIT) }
180 val collapsed = remember(detail) { detail.take(COLLAPSED_LIMIT) }
180− var expanded by remember(detail) { mutableStateOf(false) }
181+ var expanded by rememberSaveable(detail) { mutableStateOf(false) }
181 val expandedState = stringResource(R.string.state_expanded)
182 val expandedState = stringResource(R.string.state_expanded)
182 val collapsedState = stringResource(R.string.state_collapsed)
183 val collapsedState = stringResource(R.string.state_collapsed)
183 val display = if (expanded || detail.length <= COLLAPSED_LIMIT) detail else collapsed
184 val display = if (expanded || detail.length <= COLLAPSED_LIMIT) detail else collapsed
app/src/main/java/soy/iko/opencode/ui/file/FileBrowserScreen.kt+5−2
@@ -70,8 +70,11 @@ fun FileBrowserScreen(
70
70
71 LaunchedEffect(transientError) {
71 LaunchedEffect(transientError) {
72 val msg = transientError ?: return@LaunchedEffect
72 val msg = transientError ?: return@LaunchedEffect
73+ try {
73− snackbar.showSnackbar(msg)
74+ snackbar.showSnackbar(msg)
75+ } finally {
74− vm.clearTransientError()
76+ vm.clearTransientError()
77+ }
75 }
78 }
76
79
77 Scaffold(
80 Scaffold(
app/src/main/java/soy/iko/opencode/ui/server/ServerListScreen.kt+4−2
@@ -77,8 +77,10 @@ fun ServerListScreen(
77 val connectedId = activeConnection?.profile?.id
77 val connectedId = activeConnection?.profile?.id
78
78
79 LaunchedEffect(error) {
79 LaunchedEffect(error) {
80− error?.let {
80+ val msg = error ?: return@LaunchedEffect
81+ try {
81− snackbar.showSnackbar(it)
82+ snackbar.showSnackbar(msg)
83+ } finally {
82 vm.clearError()
84 vm.clearError()
83 }
85 }
84 }
86 }
app/src/main/java/soy/iko/opencode/ui/session/SessionListScreen.kt+5−2
@@ -109,8 +109,11 @@ fun SessionListScreen(
109
109
110 LaunchedEffect(transientError) {
110 LaunchedEffect(transientError) {
111 val msg = transientError ?: return@LaunchedEffect
111 val msg = transientError ?: return@LaunchedEffect
112+ try {
112− snackbar.showSnackbar(msg)
113+ snackbar.showSnackbar(msg)
114+ } finally {
113− vm.clearTransientError()
115+ vm.clearTransientError()
116+ }
114 }
117 }
115
118
116 Scaffold(
119 Scaffold(