@@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
1616import kotlinx.coroutines.flow.StateFlow
1717import kotlinx.coroutines.flow.asStateFlow
1818import kotlinx.coroutines.flow.collectLatest
19+import kotlinx.coroutines.flow.update
1920import kotlinx.coroutines.launch
2021
2122@Immutable
@@ -76,7 +77,7 @@ class FileBrowserViewModel(private val container: AppContainer) : ViewModel() {
7677 statusJob = viewModelScope.launch {
7778 runCatchingCancellable { client.fileStatus() }
7879 .onSuccess { entries ->
79− _state.value = _state.value.copy(statusMap = entries.associateBy { it.path })
80+ _state.update { it.copy(statusMap = entries.associateBy { it.path }) }
8081 }
8182 .onFailure {
8283 // VCS status is best-effort: don't block the file browser, but surface
@@ -88,32 +89,32 @@ class FileBrowserViewModel(private val container: AppContainer) : ViewModel() {
8889
8990 fun open(path: String) {
9091 val client = api ?: run {
91− _state.value = _state.value.copy(
92+ _state.update { it.copy(
9293 path = path,
9394 loading = false,
9495 error = container.string(R.string.not_connected),
95− )
96+ ) }
9697 return
9798 }
98− _state.value = _state.value.copy(
99+ _state.update { it.copy(
99100 path = path,
100101 query = "",
101102 results = emptyList(),
102103 searching = false,
103104 loading = true,
104105 error = null,
105− )
106+ ) }
106107 openJob?.cancel()
107108 searchJob?.cancel()
108109 openJob = viewModelScope.launch {
109110 runCatchingCancellable { client.listDirectory(path) }
110111 .onSuccess { entries ->
111− _state.value = _state.value.copy(
112+ _state.update { it.copy(
112113 entries = entries.sortedWith(compareByDescending<FileNode> { it.isDirectory }.thenBy { it.name.lowercase() }),
113114 loading = false,
114− )
115+ ) }
115116 }
116− .onFailure { _state.value = _state.value.copy(loading = false, error = container.friendlyError(it)) }
117+ .onFailure { e -> _state.update { it.copy(loading = false, error = container.friendlyError(e)) } }
117118 }
118119 }
119120
@@ -126,23 +127,23 @@ class FileBrowserViewModel(private val container: AppContainer) : ViewModel() {
126127 }
127128
128129 fun setQuery(query: String) {
129− _state.value = _state.value.copy(query = query, error = null)
130+ _state.update { it.copy(query = query, error = null) }
130131 searchJob?.cancel()
131132 openJob?.cancel()
132133 if (query.isBlank()) {
133− _state.value = _state.value.copy(results = emptyList(), searching = false)
134+ _state.update { it.copy(results = emptyList(), searching = false) }
134135 return
135136 }
136137 val client = api ?: run {
137− _state.value = _state.value.copy(searching = false, error = container.string(R.string.not_connected))
138+ _state.update { it.copy(searching = false, error = container.string(R.string.not_connected)) }
138139 return
139140 }
140141 searchJob = viewModelScope.launch {
141142 delay(NetworkConfig.fileSearchDebounceMs) // debounce
142− _state.value = _state.value.copy(searching = true)
143+ _state.update { it.copy(searching = true) }
143144 runCatchingCancellable { client.findFiles(query) }
144− .onSuccess { _state.value = _state.value.copy(results = it, searching = false) }
145− .onFailure { _state.value = _state.value.copy(searching = false, error = container.friendlyError(it)) }
145+ .onSuccess { results -> _state.update { it.copy(results = results, searching = false) } }
146+ .onFailure { e -> _state.update { it.copy(searching = false, error = container.friendlyError(e)) } }
146147 }
147148 }
148149}