mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-16 11:16:12 -04:00
refactor(upgrade): Adopt canonical entitlement interface and gates
UpgradeRepo gains the canonical shape: settledness rides each Info emission, plus storeSite/upgradeSite/betaSite and a suspend refresh(). getSponsorUrl() is replaced by upgradeSite (FOSS only, GPlay keeps the heart icon hidden). UpgradeRepoExtensions is the canonical file with isPro/isProSettled/isProForUi. UpgradeRepoGplay folds its parallel isSettled flow into Info.isSettled (behaviour preserving) and implements refresh() as a bounded, unthrottled call to the existing billing refresh. UpgradeControlFoss is settled from its first emission and no-ops refresh(). Interactive gates move to isProForUi so a paying user isn't bounced to the upgrade screen during the GPlay cold-start race: the device-settings and press-controls pro gates, the theme setters, and the widget confirm action, which now goes through a sealed ConfirmOutcome so the activity can only return RESULT_OK for an entitled, valid configuration. Presentation paths that can't reach a suspending gate (general settings theme items, overview device limit) render the upgrade branch only when the entitlement is hard-locked: settled, error-free and not pro.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package eu.darken.capod.common.upgrade.core
|
||||
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -13,6 +15,10 @@ class UpgradeControlFoss @Inject constructor(
|
||||
private val fossCache: FossCache,
|
||||
) : UpgradeRepo {
|
||||
|
||||
override val storeSite: String = STORE_SITE
|
||||
override val upgradeSite: String = UPGRADE_SITE
|
||||
override val betaSite: String = BETA_SITE
|
||||
|
||||
override val upgradeInfo: Flow<UpgradeRepo.Info> = fossCache.upgrade.flow.map { data ->
|
||||
if (data == null) {
|
||||
Info()
|
||||
@@ -32,6 +38,12 @@ class UpgradeControlFoss @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun refresh() {
|
||||
log(TAG) { "refresh()" }
|
||||
// The FOSS entitlement is a local cache read that the upgradeInfo flow already observes,
|
||||
// there is no remote state to reconcile.
|
||||
}
|
||||
|
||||
data class Info(
|
||||
override val isPro: Boolean = false,
|
||||
override val upgradedAt: Instant? = null,
|
||||
@@ -39,8 +51,16 @@ class UpgradeControlFoss @Inject constructor(
|
||||
override val error: Throwable? = null,
|
||||
) : UpgradeRepo.Info {
|
||||
override val type: UpgradeRepo.Type = UpgradeRepo.Type.FOSS
|
||||
|
||||
// The FOSS entitlement is a local cache read — authoritative from the first emission,
|
||||
// there is no billing handshake to wait out.
|
||||
override val isSettled: Boolean = true
|
||||
}
|
||||
|
||||
override fun getSponsorUrl(): String = "https://github.com/sponsors/d4rken"
|
||||
|
||||
companion object {
|
||||
private const val STORE_SITE = "https://github.com/d4rken-org/capod/releases"
|
||||
private const val UPGRADE_SITE = "https://github.com/sponsors/d4rken"
|
||||
private const val BETA_SITE = "https://play.google.com/apps/testing/eu.darken.capod"
|
||||
private val TAG = logTag("Upgrade", "Foss", "Control")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user