mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-16 11:16:12 -04:00
fix(upgrade): Show supporter status on every upgrade screen route
The FOSS upgrade screen's view mapping only surfaced STATUS_UPGRADED on the manage route. Forced routes (the Pro-locked settings entry) deliberately don't auto-close, so a supporter completing the sponsor flow from there stayed on the sales pitch with a live sponsor button -- reading as if sponsoring didn't work, with only the transient thanks toast saying otherwise. The gplay flavour already renders ownership state route-independently on this path. The isPro branch now wins on every route, matching the adjacent comment's stated intent and gplay's behaviour. Forced routes keep their don't-auto-close semantics; the durable status view is what acknowledges the upgrade.
This commit is contained in:
@@ -42,8 +42,10 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
|
|
||||||
// Which presentation the screen shows. The manage route (settings "upgrade status" entry)
|
// Which presentation the screen shows. The manage route (settings "upgrade status" entry)
|
||||||
// gets a status view first; the pitch only appears once a free user asks for the upgrade
|
// gets a status view first; the pitch only appears once a free user asks for the upgrade
|
||||||
// options. Upgrading wins over that choice — completing the sponsor flow from the pitch must
|
// options. Upgrading wins on EVERY route, not just manage: forced routes (Pro-locked settings)
|
||||||
// land on the upgraded status, not back on the ask. null until the route is bound.
|
// stay open after the sponsor flow completes, and the pitch with its live sponsor button reads
|
||||||
|
// as "sponsoring didn't work" to a fresh supporter — the toast alone is too transient for a
|
||||||
|
// money moment without a receipt behind it. null until the route is bound.
|
||||||
internal val state: StateFlow<State?> = combine(
|
internal val state: StateFlow<State?> = combine(
|
||||||
routeFlow,
|
routeFlow,
|
||||||
upgradeRepo.upgradeInfo,
|
upgradeRepo.upgradeInfo,
|
||||||
@@ -51,7 +53,7 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
) { route, info, showOptions ->
|
) { route, info, showOptions ->
|
||||||
val view = when {
|
val view = when {
|
||||||
route == null -> null
|
route == null -> null
|
||||||
route.manage && info.isPro -> FossUpgradeView.STATUS_UPGRADED
|
info.isPro -> FossUpgradeView.STATUS_UPGRADED
|
||||||
route.manage && !showOptions -> FossUpgradeView.STATUS_FREE
|
route.manage && !showOptions -> FossUpgradeView.STATUS_FREE
|
||||||
else -> FossUpgradeView.PITCH
|
else -> FossUpgradeView.PITCH
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,35 @@ class FossUpgradeViewModelTest : BaseTest() {
|
|||||||
upgradedView.await().view shouldBe FossUpgradeView.STATUS_UPGRADED
|
upgradedView.await().view shouldBe FossUpgradeView.STATUS_UPGRADED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `forced route lands on the upgraded status when the sponsor flow completes`() = runTest2(
|
||||||
|
context = testDispatcher,
|
||||||
|
) {
|
||||||
|
// Forced routes (Pro-locked settings entry) deliberately don't auto-close, so the screen is
|
||||||
|
// still up when the unlock lands — it must flip to the supporter status instead of keeping
|
||||||
|
// the sales pitch, which reads as "sponsoring didn't work".
|
||||||
|
val info = MutableStateFlow(UpgradeRepoFoss.Info())
|
||||||
|
val vm = buildVm(repo = mockRepo(info))
|
||||||
|
|
||||||
|
val navEvents = mutableListOf<NavEvent>()
|
||||||
|
val collector = launch(start = CoroutineStart.UNDISPATCHED) { vm.navEvents.collect { navEvents.add(it) } }
|
||||||
|
|
||||||
|
val pitchView = async { vm.state.first { it != null }!! }
|
||||||
|
vm.bindRoute(Nav.Main.Upgrade(forced = true))
|
||||||
|
advanceUntilIdle()
|
||||||
|
pitchView.await().view shouldBe FossUpgradeView.PITCH
|
||||||
|
|
||||||
|
val upgradedView = async { vm.state.first { it?.view == FossUpgradeView.STATUS_UPGRADED }!! }
|
||||||
|
info.value = upgradedInfo()
|
||||||
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
upgradedView.await().view shouldBe FossUpgradeView.STATUS_UPGRADED
|
||||||
|
// The don't-auto-close semantics of forced routes are unchanged — status, not navigation,
|
||||||
|
// is what acknowledges the upgrade here.
|
||||||
|
navEvents.shouldBeEmpty()
|
||||||
|
collector.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `default route bounces an upgraded user out of the screen`() = runTest2(context = testDispatcher) {
|
fun `default route bounces an upgraded user out of the screen`() = runTest2(context = testDispatcher) {
|
||||||
val vm = buildVm(repo = mockRepo(MutableStateFlow(upgradedInfo())))
|
val vm = buildVm(repo = mockRepo(MutableStateFlow(upgradedInfo())))
|
||||||
|
|||||||
Reference in New Issue
Block a user