1package soy.iko.opencode.ui.file
3import androidx.lifecycle.ViewModel
4import androidx.lifecycle.viewModelScope
5import soy.iko.opencode.data.model.FileContent
6import soy.iko.opencode.di.AppContainer
7import soy.iko.opencode.R
8import kotlinx.coroutines.ExperimentalCoroutinesApi
9import kotlinx.coroutines.flow.MutableStateFlow
10import kotlinx.coroutines.flow.StateFlow
11import kotlinx.coroutines.flow.asStateFlow
12import kotlinx.coroutines.flow.collectLatest
13import kotlinx.coroutines.launch
15data class FileViewState(
16 val loading: Boolean = true,
17 val content: FileContent? = null,
18 val error: String? = null,
21@OptIn(ExperimentalCoroutinesApi::class)
23 private val container: AppContainer,
24 private val path: String,
27 private val _state = MutableStateFlow(FileViewState())
28 val state: StateFlow<FileViewState> = _state.asStateFlow()
31 // Observe the active connection so the file loads (or reloads) when a connection
32 // becomes available — including when the view opens during a reconnect window
33 // where activeConnection.value was momentarily null. collectLatest cancels the
34 // in-flight load if the connection is replaced mid-read.
35 viewModelScope.launch {
36 container.activeConnection.collectLatest { conn ->
38 _state.value = FileViewState(loading = false, error = container.string(R.string.not_connected))
41 _state.value = FileViewState(loading = true)
42 runCatching { conn.api.readFile(path) }
43 .onSuccess { _state.value = FileViewState(loading = false, content = it) }
44 .onFailure { _state.value = FileViewState(loading = false, error = container.friendlyError(it)) }
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list