OXYGENHUB

The Dashboard refreshes each time it comes back to the front (closes #35) 29a375612f92

Author
Andy McCall @andymccall <[email protected]>
via
agent agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key 99a7abe72157
When
· 2026-11-02 22:58 UTC
Signature
◈ sealed by agent:claude@andymccall
Hash
29a375612f92b252a2c034ac8f2fc1757a038393ac60df79c02382096f54c507
Depends on
144cbf7bf2b5 1dfa631436b6 57c0824300db 645469f5227b db00632a61d6 dfbc3e972872
Depended on by
nothing yet
In bookmarks
main
In tags
v0.1.8 v0.1.9
Edits
7 atoms, 0 tree operations, 4 files

Browse the tree at this change

modified CHANGELOG.md +1 −0
…
1 unchanged lines
2 2
3 3
## Unreleased
4 4
5 +
- **The Dashboard shows a landed proposal as landed (#35):** it fetched once and kept that snapshot while you moved around the app, so a proposal landed from its page still showed as open on the way back. The Dashboard and the inbox counts now refresh each time the Dashboard comes back to the front.
5 6
- **The version card notices a new release without a restart (#34):** Account › OxygenHub asked the hub for releases once, when the card first showed, so an app left open kept saying "OxygenHub 0.1.6" after 0.1.7 was out until it was force-quit. It asks again each time the app comes to the front.
6 7
7 8
## 0.1.7 (2026-11-02)
…
61 unchanged lines
modified app/src/main/java/io/oxygenhub/android/ui/dashboard/DashboardScreen.kt +11 −0
…
28 unchanged lines
29 29
import androidx.compose.material3.Text
30 30
import androidx.compose.material3.TextButton
31 31
import androidx.compose.runtime.Composable
32 +
import androidx.compose.runtime.LaunchedEffect
32 33
import androidx.compose.runtime.getValue
33 34
import androidx.compose.ui.Alignment
34 35
import androidx.compose.ui.Modifier
…
1 unchanged lines
36 37
import androidx.compose.ui.text.font.FontWeight
37 38
import androidx.compose.ui.text.style.TextOverflow
38 39
import androidx.compose.ui.unit.dp
40 +
import androidx.lifecycle.Lifecycle
41 +
import androidx.lifecycle.compose.LocalLifecycleOwner
39 42
import androidx.lifecycle.compose.collectAsStateWithLifecycle
43 +
import androidx.lifecycle.repeatOnLifecycle
40 44
import io.oxygenhub.android.api.Inbox
41 45
import io.oxygenhub.android.api.IssueBrief
42 46
import io.oxygenhub.android.api.ProposalBrief
…
27 unchanged lines
70 74
    onProjects: (() -> Unit)? = null,
71 75
) {
72 76
    val state by vm.state.collectAsStateWithLifecycle()
77 +
    val owner = LocalLifecycleOwner.current
78 +
    LaunchedEffect(owner) {
79 +
        owner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
80 +
            vm.resumed()
81 +
            onRefreshInbox()
82 +
        }
83 +
    }
73 84
    AppScreen(
74 85
        title = "Dashboard",
75 86
        subtitle = hub.substringAfter("://"),
…
179 unchanged lines
modified app/src/main/java/io/oxygenhub/android/ui/dashboard/DashboardViewModel.kt +10 −0
…
58 unchanged lines
59 59
        job = load(_state, job) { fetch() }
60 60
    }
61 61
62 +
    /**
63 +
     * The dashboard is in front again (back from a proposal, or the app
64 +
     * brought back): fetch afresh, keeping what shows meanwhile, so a
65 +
     * proposal just landed no longer shows as open (#35). Not while the
66 +
     * first load is still on its way.
67 +
     */
68 +
    fun resumed() {
69 +
        if (_state.value !is Load.Loading) refresh()
70 +
    }
71 +
62 72
    private suspend fun fetch(): Dashboard = coroutineScope {
63 73
        // The account is a nicety (a display name); the repositories are the page.
64 74
        val user = async {
…
72 unchanged lines
modified app/src/test/java/io/oxygenhub/android/ui/DashboardViewModelTest.kt +10 −0
…
51 unchanged lines
52 52
    }
53 53
54 54
    @Test
55 +
    fun fetchesAfreshWhenItComesBackToTheFront() {
56 +
        val vm = DashboardViewModel(api, session) { 9 }
57 +
        val before = api.calls.count { it == "repos" }
58 +
        // Back from landing a proposal (#35): the dashboard asks the hub again.
59 +
        vm.resumed()
60 +
        assertEquals(before + 1, api.calls.count { it == "repos" })
61 +
        assertEquals(2, ready(vm).repositoryCount)
62 +
    }
63 +
64 +
    @Test
55 65
    fun drawsYourSkyFromTheHubAndTheFieldWithoutIt() {
56 66
        val vm = DashboardViewModel(api, session) { 9 }
57 67
        val sky = ready(vm).sky!!
…
87 unchanged lines