git.iko.soy/opencode-android
on master help sign in
Fix stuck refresh indicator on disconnect, stale unread badges on server switch, and lost file browser navigation when offline
commit274bb6afeb4c04281636924cc036e4716b0a1ca5 authoriko <mail@iko.soy> dateTue 30 Jun 2026, 07:16 (3 months ago) parent2ea1094
4 files changed+11−3
app/src/main/java/soy/iko/opencode/di/AppContainer.kt+1 app/src/main/java/soy/iko/opencode/ui/chat/ChatViewModel.kt+4−2 app/src/main/java/soy/iko/opencode/ui/file/FileBrowserViewModel.kt+5−1 app/src/main/java/soy/iko/opencode/ui/session/SessionListViewModel.kt+1
app/src/main/java/soy/iko/opencode/di/AppContainer.kt+1
@@ -259,6 +259,7 @@ class AppContainer(context: Context) {
259259 _activeConnection.value?.close()
260260 _activeConnection.value = null
261261 activeRuns.clear()
262+ _unread.value = emptySet()
262263 val now = System.currentTimeMillis()
263264 val resolved = profileStore.resolve(profile)
264265 val needsSave = (now - resolved.lastUsed) > LAST_USED_SAVE_THRESHOLD_MS
app/src/main/java/soy/iko/opencode/ui/chat/ChatViewModel.kt+4−2
@@ -341,8 +341,10 @@ class ChatViewModel(
341341
342342 override fun onCleared() {
343343 super.onCleared()
344− // Flush any pending debounced draft so it survives navigation. Use a synchronous
345− // commit instead of runBlocking so the main thread isn't held hostage by disk I/O.
344+ // Flush any pending debounced draft so it survives navigation. Uses an
345+ // asynchronous apply() (not a synchronous commit) so the main thread isn't
346+ // blocked on disk I/O — Android's SharedPreferences framework guarantees
347+ // pending apply() writes are flushed before the process exits.
346348 val pending = _draft.value
347349 if (pending.isNotEmpty()) {
348350 container.draftStore.flushDraft(sessionId, pending)
app/src/main/java/soy/iko/opencode/ui/file/FileBrowserViewModel.kt+5−1
@@ -88,7 +88,11 @@ class FileBrowserViewModel(private val container: AppContainer) : ViewModel() {
8888
8989 fun open(path: String) {
9090 val client = api ?: run {
91− _state.value = _state.value.copy(loading = false, error = container.string(R.string.not_connected))
91+ _state.value = _state.value.copy(
92+ path = path,
93+ loading = false,
94+ error = container.string(R.string.not_connected),
95+ )
9296 return
9397 }
9498 _state.value = _state.value.copy(path = path, loading = true, error = null)
app/src/main/java/soy/iko/opencode/ui/session/SessionListViewModel.kt+1
@@ -165,6 +165,7 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
165165 _state.update { it.copy(loading = false) }
166166 _transientError.value = container.string(R.string.not_connected)
167167 }
168+ _refreshing.value = false
168169 return
169170 }
170171 _serverLabel.value = conn.profile.displayLabel