git.iko.soy/opencode-android
on master help sign in
Fix file browser search debounce flash, SessionListViewModel indentation, and DiagnosticsScreen dead error handling
3996399iko
app/src/main/java/soy/iko/opencode/ui/file/FileBrowserViewModel.kt+4−2
@@ -140,14 +140,16 @@ class FileBrowserViewModel(private val container: AppContainer) : ViewModel() {
140 }
140 }
141 // The search view replaces the directory listing; clear loading so the spinner
141 // The search view replaces the directory listing; clear loading so the spinner
142 // from a cancelled open() doesn't persist into the search results view.
142 // from a cancelled open() doesn't persist into the search results view.
143+ // Set searching=true immediately (not after the debounce) so the spinner shows
144+ // during the debounce delay — otherwise the UI briefly renders SearchResults
145+ // with an empty list, flashing "no matches" before the search even starts.
143− _state.update { it.copy(loading = false) }
146+ _state.update { it.copy(loading = false, searching = true) }
144 val client = api ?: run {
147 val client = api ?: run {
145 _state.update { it.copy(searching = false, error = container.string(R.string.not_connected)) }
148 _state.update { it.copy(searching = false, error = container.string(R.string.not_connected)) }
146 return
149 return
147 }
150 }
148 searchJob = viewModelScope.launch {
151 searchJob = viewModelScope.launch {
149 delay(NetworkConfig.fileSearchDebounceMs) // debounce
152 delay(NetworkConfig.fileSearchDebounceMs) // debounce
150− _state.update { it.copy(searching = true) }
151 runCatchingCancellable { client.findFiles(query) }
153 runCatchingCancellable { client.findFiles(query) }
152 .onSuccess { results -> _state.update { it.copy(results = results, searching = false) } }
154 .onSuccess { results -> _state.update { it.copy(results = results, searching = false) } }
153 .onFailure { e -> _state.update { it.copy(searching = false, error = container.friendlyError(e)) } }
155 .onFailure { e -> _state.update { it.copy(searching = false, error = container.friendlyError(e)) } }
app/src/main/java/soy/iko/opencode/ui/session/SessionListViewModel.kt+10−10
@@ -136,18 +136,18 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
136 loadPreview(session.id)
136 loadPreview(session.id)
137 }
137 }
138 is SessionDeleted -> {
138 is SessionDeleted -> {
139− val id = event.properties.info?.id ?: event.properties.sessionID
139+ val id = event.properties.info?.id ?: event.properties.sessionID
140− if (id != null) {
140+ if (id != null) {
141− synchronized(previewLock) { livePreviewJobs.remove(id)?.cancel() }
141+ synchronized(previewLock) { livePreviewJobs.remove(id)?.cancel() }
142− container.draftStore.remove(id)
142+ container.draftStore.remove(id)
143− _state.update { s ->
143+ _state.update { s ->
144− s.copy(
144+ s.copy(
145− sessions = s.sessions.filterNot { it.id == id },
145+ sessions = s.sessions.filterNot { it.id == id },
146− previews = s.previews - id,
146+ previews = s.previews - id,
147− )
147+ )
148+ }
148 }
149 }
149 }
150 }
150− }
151 else -> {}
151 else -> {}
152 }
152 }
153 }
153 }
app/src/main/java/soy/iko/opencode/ui/settings/DiagnosticsScreen.kt+2−8
@@ -75,10 +75,7 @@ fun DiagnosticsScreen(onBack: () -> Unit) {
75 actions = {
75 actions = {
76 if (reports.isNotEmpty()) {
76 if (reports.isNotEmpty()) {
77 IconButton(onClick = {
77 IconButton(onClick = {
78− shareScope.launch(Dispatchers.IO) {
79− runCatching { logger.clearAll() }
78+ logger.clearAll()
80− .onFailure { Log.w("Diagnostics", "Failed to clear crash reports", it) }
81− }
82 }) {
79 }) {
83 Icon(Icons.Filled.DeleteSweep, contentDescription = stringResource(R.string.clear_all))
80 Icon(Icons.Filled.DeleteSweep, contentDescription = stringResource(R.string.clear_all))
84 }
81 }
@@ -185,10 +182,7 @@ fun DiagnosticsScreen(onBack: () -> Unit) {
185 }) { Text(stringResource(R.string.share)) }
182 }) { Text(stringResource(R.string.share)) }
186 Spacer(Modifier.size(8.dp))
183 Spacer(Modifier.size(8.dp))
187 TextButton(onClick = {
184 TextButton(onClick = {
188− shareScope.launch(Dispatchers.IO) {
189− runCatching { logger.deleteReport(reportName) }
185+ logger.deleteReport(reportName)
190− .onFailure { Log.w("Diagnostics", "Failed to delete crash report", it) }
191− }
192 viewing = null
186 viewing = null
193 }) { Text(stringResource(R.string.delete)) }
187 }) { Text(stringResource(R.string.delete)) }
194 }
188 }