OXYGENHUB
# 740a452b2669 oxygenhub-android / app / src / main / java / io / oxygenhub / android / ui / proposals / ProposalFiles.kt
2.7 KiB · last changed A proposal's files and their diffs: Files changed from its Changes section, the change screen's diff list shared (refs #4) 8 days ago source blame history raw
1
package io.oxygenhub.android.ui.proposals
2
3
import androidx.compose.foundation.lazy.LazyColumn
4
import androidx.compose.material.icons.Icons
5
import androidx.compose.material.icons.outlined.Description
6
import androidx.compose.runtime.Composable
7
import androidx.compose.runtime.getValue
8
import androidx.compose.runtime.mutableStateOf
9
import androidx.compose.runtime.saveable.rememberSaveable
10
import androidx.compose.runtime.setValue
11
import androidx.lifecycle.ViewModel
12
import androidx.lifecycle.compose.collectAsStateWithLifecycle
13
import io.oxygenhub.android.api.FileChange
14
import io.oxygenhub.android.api.HubApi
15
import io.oxygenhub.android.ui.code.fileDiffs
16
import io.oxygenhub.android.ui.code.openByDefault
17
import io.oxygenhub.android.ui.common.AppScreen
18
import io.oxygenhub.android.ui.common.EmptyState
19
import io.oxygenhub.android.ui.common.Load
20
import io.oxygenhub.android.ui.common.LoadContent
21
import io.oxygenhub.android.ui.common.load
22
import io.oxygenhub.android.ui.theme.LocalStatusColors
23
import kotlinx.coroutines.Job
24
import kotlinx.coroutines.flow.MutableStateFlow
25
import kotlinx.coroutines.flow.StateFlow
26
import kotlinx.coroutines.flow.asStateFlow
27
28
/** The files a proposal changes, each with its diff (#4). */
29
class ProposalFilesViewModel(private val api: HubApi, val owner: String, val name: String, val number: Long) : ViewModel() {
30
    private val _state = MutableStateFlow<Load<List<FileChange>>>(Load.Loading)
31
    val state: StateFlow<Load<List<FileChange>>> = _state.asStateFlow()
32
    private var job: Job? = null
33
34
    init {
35
        refresh()
36
    }
37
38
    fun refresh() {
39
        job = load(_state, job) { api.proposalDiff(owner, name, number) }
40
    }
41
}
42
43
/** A proposal's files, as its page on the hub shows them: each folds open to its diff. */
44
@Composable
45
fun ProposalFilesScreen(vm: ProposalFilesViewModel, onBack: () -> Unit) {
46
    val state by vm.state.collectAsStateWithLifecycle()
47
    val status = LocalStatusColors.current
48
    AppScreen(title = "Files · #${vm.number}", subtitle = "${vm.owner}/${vm.name}", onBack = onBack) {
49
        LoadContent(state, onRefresh = vm::refresh) { files ->
50
            if (files.isEmpty()) {
51
                EmptyState(Icons.Outlined.Description, "No files changed", "This proposal's changes are already on its target, or change nothing.")
52
                return@LoadContent
53
            }
54
            var open by rememberSaveable(vm.number) { mutableStateOf(openByDefault(files).toList()) }
55
            LazyColumn {
56
                fileDiffs(
57
                    files,
58
                    open,
59
                    status.ok,
60
                    status.bad,
61
                    onToggle = { path -> open = if (path in open) open - path else open + path },
62
                    onOpen = { null },
63
                )
64
            }
65
        }
66
    }
67
}