mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-16 19:26:12 -04:00
fix(upgrade): Only count a sponsor visit when the page actually opened
The sponsor unlock heuristic armed itself on every tap, regardless of whether a browser ever opened the page. An unrelated later background round-trip could then hand out supporter status with no page ever shown. WebpageTool.open() now reports whether an activity was actually started and the FOSS repo passes that through synchronously, so the ViewModel can only arm after a successful launch. A second tap while a launch is still pending is ignored, and the upgraded status view's donate button gets its own unarmed entry point - an existing supporter has nothing left to unlock, and re-persisting would rewrite their "supporter since" date.
This commit is contained in:
@@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
@@ -49,9 +48,11 @@ class UpgradeRepoFoss @Inject constructor(
|
||||
.setupCommonEventHandlers(TAG) { "upgradeInfo" }
|
||||
.shareIn(appScope, SharingStarted.WhileSubscribed(3000L, 0L), replay = 1)
|
||||
|
||||
fun openGithubSponsorsPage() = appScope.launch {
|
||||
// Synchronous so the caller learns whether the page actually opened: the FOSS unlock heuristic
|
||||
// only arms on a successful launch, and a fire-and-forget coroutine can't report that back.
|
||||
fun openGithubSponsorsPage(): Boolean {
|
||||
log(TAG) { "openGithubSponsorsPage()" }
|
||||
webpageTool.open(upgradeSite)
|
||||
return webpageTool.open(upgradeSite)
|
||||
}
|
||||
|
||||
// Writes capod's RETAINED persistence schema: existing supporter records are serialized with
|
||||
|
||||
@@ -95,6 +95,7 @@ fun UpgradeScreenHost(
|
||||
supporterSince = state?.supporterSince,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onGithubSponsors = vm::goGithubSponsors,
|
||||
onOpenSponsors = vm::openSponsors,
|
||||
onShowUpgradeOptions = vm::onShowUpgradeOptions,
|
||||
onNavigateUp = vm::navUp,
|
||||
)
|
||||
@@ -106,6 +107,7 @@ internal fun UpgradeScreen(
|
||||
supporterSince: Instant? = null,
|
||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||
onGithubSponsors: () -> Unit = {},
|
||||
onOpenSponsors: () -> Unit = {},
|
||||
onShowUpgradeOptions: () -> Unit = {},
|
||||
onNavigateUp: () -> Unit = {},
|
||||
) {
|
||||
@@ -140,7 +142,7 @@ internal fun UpgradeScreen(
|
||||
FossUpgradeView.STATUS_UPGRADED -> UpgradeStatusUpgradedContent(
|
||||
paddingValues = paddingValues,
|
||||
supporterSince = supporterSince,
|
||||
onGithubSponsors = onGithubSponsors,
|
||||
onOpenSponsors = onOpenSponsors,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -234,7 +236,7 @@ private fun UpgradeStatusFreeContent(
|
||||
private fun UpgradeStatusUpgradedContent(
|
||||
paddingValues: PaddingValues,
|
||||
supporterSince: Instant? = null,
|
||||
onGithubSponsors: () -> Unit,
|
||||
onOpenSponsors: () -> Unit,
|
||||
) {
|
||||
UpgradeScreenContent(
|
||||
paddingValues = paddingValues,
|
||||
@@ -273,7 +275,7 @@ private fun UpgradeStatusUpgradedContent(
|
||||
) {
|
||||
UpgradeSectionBody(text = stringResource(R.string.upgrade_screen_recurring_body))
|
||||
OutlinedButton(
|
||||
onClick = onGithubSponsors,
|
||||
onClick = onOpenSponsors,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(UpgradeScreenTags.FOSS_DONATE),
|
||||
|
||||
@@ -106,9 +106,28 @@ class UpgradeViewModel @Inject constructor(
|
||||
handle[KEY_SHOW_UPGRADE_OPTIONS] = true
|
||||
}
|
||||
|
||||
/** Armed variant: the pitch's sponsor button, which starts the return-after-5s unlock heuristic. */
|
||||
fun goGithubSponsors() {
|
||||
log(TAG) { "goGithubSponsors()" }
|
||||
if (hasPendingSponsorLaunch()) {
|
||||
log(TAG) { "A sponsor launch is already awaiting its return" }
|
||||
return
|
||||
}
|
||||
// Only arm the heuristic if the page actually opened; otherwise an unrelated later
|
||||
// background/foreground round-trip would grant supporter status with no page ever shown.
|
||||
if (!upgradeRepo.openGithubSponsorsPage()) {
|
||||
log(TAG) { "Sponsor page didn't open; not arming the unlock heuristic" }
|
||||
return
|
||||
}
|
||||
handle[KEY_SPONSOR_PRESSED_AT] = SystemClock.elapsedRealtime()
|
||||
}
|
||||
|
||||
/**
|
||||
* Unarmed variant: the status view's donate button. An existing supporter re-visiting the page
|
||||
* must not re-arm the unlock heuristic — there is nothing left to unlock.
|
||||
*/
|
||||
fun openSponsors() {
|
||||
log(TAG) { "openSponsors()" }
|
||||
upgradeRepo.openGithubSponsorsPage()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user