git.iko.soy/opencode-android
on fb38d12 help sign in
51 lines 2.0 kB history raw
1package soy.iko.opencode.ui.file
3import androidx.compose.runtime.Immutable
4import androidx.lifecycle.ViewModel
5import androidx.lifecycle.viewModelScope
6import soy.iko.opencode.data.model.FileContent
7import soy.iko.opencode.di.AppContainer
8import soy.iko.opencode.R
9import kotlinx.coroutines.ExperimentalCoroutinesApi
10import kotlinx.coroutines.flow.MutableStateFlow
11import kotlinx.coroutines.flow.StateFlow
12import kotlinx.coroutines.flow.asStateFlow
13import kotlinx.coroutines.flow.collectLatest
14import kotlinx.coroutines.launch
15import soy.iko.opencode.util.runCatchingCancellable
17@Immutable
18data class FileViewState(
19 val loading: Boolean = true,
20 val content: FileContent? = null,
21 val error: String? = null,
24@OptIn(ExperimentalCoroutinesApi::class)
25class FileViewModel(
26 private val container: AppContainer,
27 private val path: String,
28) : ViewModel() {
30 private val _state = MutableStateFlow(FileViewState())
31 val state: StateFlow<FileViewState> = _state.asStateFlow()
33 init {
34 // Observe the active connection so the file loads (or reloads) when a connection
35 // becomes available — including when the view opens during a reconnect window
36 // where activeConnection.value was momentarily null. collectLatest cancels the
37 // in-flight load if the connection is replaced mid-read.
38 viewModelScope.launch {
39 container.activeConnection.collectLatest { conn ->
40 if (conn == null) {
41 _state.value = FileViewState(loading = false, error = container.string(R.string.not_connected))
42 return@collectLatest
43 }
44 _state.value = FileViewState(loading = true)
45 runCatchingCancellable { conn.api.readFile(path) }
46 .onSuccess { _state.value = FileViewState(loading = false, content = it) }
47 .onFailure { _state.value = FileViewState(loading = false, error = container.friendlyError(it)) }
48 }
49 }
50 }