Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ jobs:
command: sudo pip install awscli
- run:
name: Deploy to S3
command: aws s3 sync ~/project/docs/9.29.0 s3://purchases-docs/android/9.29.0 --delete
command: aws s3 sync ~/project/docs/9.29.1 s3://purchases-docs/android/9.29.1 --delete
- run:
name: Update index.html
command: aws s3 cp ~/project/docs/index.html s3://purchases-docs/android/index.html
Expand Down
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9.29.0
9.29.1
17 changes: 2 additions & 15 deletions CHANGELOG.latest.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
## RevenueCat SDK
### ✨ New Features
* Use Amazon deep link for Amazon subscription management (#3291) via Cesar de la Vega (@vegaro)
* Introduce purchases codegen package (#3163) via Jaewoong Eum (@skydoves)
### 🐞 Bugfixes
* Fix Test Store Purchase dialog not cancelling purchase on outside tap (#3289) via Antonio Pallares (@ajpallares)

## RevenueCatUI SDK
### Paywallv2
#### 🐞 Bugfixes
* Fix mixed currencies in paywall price variables (PW-133) (#3119) via Facundo Menzella (@facumenzella)

### 🔄 Other Changes
* Add docs for the codegen plugin (#3288) via Jaewoong Eum (@skydoves)
* Run integration tests against all backend environments (#3278) via Toni Rico (@tonidero)
* Use merge queue for release PR merging (#3281) via Antonio Pallares (@ajpallares)
* ci: warn when pre-built material-icons are imported in :ui:revenuecatui (#3282) via Facundo Menzella (@facumenzella)
#### ✨ New Features
* PW-1178 | Support package-level visibility via visible property and overrides (#3279) via Facundo Menzella (@facumenzella)
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 9.29.1
## RevenueCatUI SDK
### Paywallv2
#### ✨ New Features
* PW-1178 | Support package-level visibility via visible property and overrides (#3279) via Facundo Menzella (@facumenzella)

## 9.29.0
## RevenueCat SDK
### ✨ New Features
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[versions]
agp = "8.13.2"
kotlin = "1.8.22"
purchases = "9.29.0"
purchases = "9.29.1"
androidxCore = "1.10.1"

[plugins]
Expand Down
2 changes: 1 addition & 1 deletion examples/MagicWeather/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
agp = "8.13.2"
androidxNavigation = "2.6.0"
kotlin = "1.9.0"
purchases = "9.29.0"
purchases = "9.29.1"
lifecycle = "2.6.1"
androidxCore = "1.10.1"

Expand Down
2 changes: 1 addition & 1 deletion examples/MagicWeatherCompose/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
agp = "8.13.2"
androidxNavigation = "2.5.3"
kotlin = "1.8.22"
purchases = "9.29.0"
purchases = "9.29.1"
lifecycle = "2.5.0"
androidxCore = "1.10.1"

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#Fri Mar 31 10:31:20 PDT 2023
GROUP=com.revenuecat.purchases

VERSION_NAME=9.29.0
VERSION_NAME=9.29.1

POM_DESCRIPTION=Mobile subscriptions in hours, not months.
POM_URL=https://github.com/RevenueCat/purchases-android
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ import com.revenuecat.purchases.api.BuildConfig
public object Config {
public var logLevel: LogLevel = LogLevel.debugLogsEnabled(BuildConfig.DEBUG)

internal const val frameworkVersion = "9.29.0"
internal const val frameworkVersion = "9.29.1"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.revenuecat.purchases.paywalls.components

import androidx.compose.runtime.Immutable
import com.revenuecat.purchases.InternalRevenueCatAPI
import com.revenuecat.purchases.paywalls.components.common.ComponentOverride
import com.revenuecat.purchases.paywalls.components.common.PromoOfferConfig
import com.revenuecat.purchases.paywalls.components.common.ResilientPromoOfferConfigSerializer
import dev.drewhamilton.poko.Poko
Expand All @@ -26,4 +27,17 @@ public class PackageComponent(
@Serializable(with = ResilientPromoOfferConfigSerializer::class)
@SerialName("play_store_offer")
public val playStoreOffer: PromoOfferConfig? = null,
@get:JvmSynthetic
public val visible: Boolean? = null,
@get:JvmSynthetic
public val overrides: List<ComponentOverride<PartialPackageComponent>> = emptyList(),
) : PaywallComponent

@InternalRevenueCatAPI
@Poko
@Serializable
@Immutable
public class PartialPackageComponent(
@get:JvmSynthetic
public val visible: Boolean? = null,
) : PartialComponent
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.revenuecat.purchases.ColorAlias
import com.revenuecat.purchases.JsonTools
import com.revenuecat.purchases.LogHandler
import com.revenuecat.purchases.common.currentLogHandler
import com.revenuecat.purchases.paywalls.components.common.ComponentOverride
import com.revenuecat.purchases.paywalls.components.common.LocalizationKey
import com.revenuecat.purchases.paywalls.components.common.PromoOfferConfig
import com.revenuecat.purchases.paywalls.components.properties.ColorInfo
Expand Down Expand Up @@ -187,6 +188,87 @@ internal class PackageComponentTests(@Suppress("UNUSED_PARAMETER") name: String,
)
),
),
arrayOf(
"visible = true",
Args(
json = """
{
"type": "package",
"package_id": "${"$"}rc_weekly",
"is_selected_by_default": true,
"visible": true,
"stack": {
"type": "stack",
"components": []
}
}
""".trimIndent(),
expected = PackageComponent(
packageId = "${"$"}rc_weekly",
isSelectedByDefault = true,
stack = StackComponent(components = emptyList()),
visible = true,
)
),
),
arrayOf(
"visible = false",
Args(
json = """
{
"type": "package",
"package_id": "${"$"}rc_weekly",
"is_selected_by_default": true,
"visible": false,
"stack": {
"type": "stack",
"components": []
}
}
""".trimIndent(),
expected = PackageComponent(
packageId = "${"$"}rc_weekly",
isSelectedByDefault = true,
stack = StackComponent(components = emptyList()),
visible = false,
)
),
),
arrayOf(
"overrides with visible = false",
Args(
json = """
{
"type": "package",
"package_id": "${"$"}rc_weekly",
"is_selected_by_default": true,
"stack": {
"type": "stack",
"components": []
},
"overrides": [
{
"conditions": [{"type": "intro_offer"}],
"properties": {"visible": false}
}
]
}
""".trimIndent(),
expected = PackageComponent(
packageId = "${"$"}rc_weekly",
isSelectedByDefault = true,
stack = StackComponent(components = emptyList()),
overrides = listOf(
ComponentOverride(
conditions = listOf(
ComponentOverride.Condition.IntroOffer
),
properties = PartialPackageComponent(visible = false),
)
),
)
),
),
)
}

Expand Down
2 changes: 1 addition & 1 deletion test-apps/sdksizetesting/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ espressoCore = "3.7.0"
lifecycleRuntimeKtx = "2.10.0"
activityCompose = "1.12.2"
composeBom = "2024.09.00"
purchases = "9.29.0"
purchases = "9.29.1"
emergeGradlePlugin = "4.4.0"

[libraries]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.revenuecat.purchases.ui.revenuecatui.components

import com.revenuecat.purchases.paywalls.components.PartialPackageComponent
import com.revenuecat.purchases.ui.revenuecatui.errors.PaywallValidationError
import com.revenuecat.purchases.ui.revenuecatui.helpers.NonEmptyList
import com.revenuecat.purchases.ui.revenuecatui.helpers.Result
import dev.drewhamilton.poko.Poko

@Poko
internal class PresentedPackagePartial(
@get:JvmSynthetic val partial: PartialPackageComponent,
) : PresentedPartial<PresentedPackagePartial> {

companion object {
@JvmSynthetic
operator fun invoke(
from: PartialPackageComponent,
): Result<PresentedPackagePartial, NonEmptyList<PaywallValidationError>> =
Result.Success(PresentedPackagePartial(partial = from))
}

override fun combine(with: PresentedPackagePartial?): PresentedPackagePartial {
val otherPartial = with?.partial
return PresentedPackagePartial(
partial = PartialPackageComponent(
visible = otherPartial?.visible ?: partial.visible,
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
@file:JvmSynthetic

package com.revenuecat.purchases.ui.revenuecatui.components.pkg

import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.window.core.layout.WindowWidthSizeClass
import com.revenuecat.purchases.ui.revenuecatui.CustomVariableValue
import com.revenuecat.purchases.ui.revenuecatui.components.ComponentViewState
import com.revenuecat.purchases.ui.revenuecatui.components.ConditionContext
import com.revenuecat.purchases.ui.revenuecatui.components.ScreenCondition
import com.revenuecat.purchases.ui.revenuecatui.components.buildPresentedPartial
import com.revenuecat.purchases.ui.revenuecatui.components.state.PackageAwareDelegate
import com.revenuecat.purchases.ui.revenuecatui.components.style.PackageComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.composables.OfferEligibility
import com.revenuecat.purchases.ui.revenuecatui.data.PaywallState

@Stable
@JvmSynthetic
@Composable
internal fun rememberUpdatedPackageComponentState(
style: PackageComponentStyle,
paywallState: PaywallState.Loaded.Components,
): PackageComponentState = rememberUpdatedPackageComponentState(
style = style,
selectedPackageInfoProvider = { paywallState.selectedPackageInfo },
selectedTabIndexProvider = { paywallState.selectedTabIndex },
selectedOfferEligibilityProvider = { paywallState.selectedOfferEligibility },
customVariablesProvider = { paywallState.mergedCustomVariables },
)

@Suppress("LongParameterList")
@Stable
@JvmSynthetic
@Composable
private fun rememberUpdatedPackageComponentState(
style: PackageComponentStyle,
selectedPackageInfoProvider: () -> PaywallState.Loaded.Components.SelectedPackageInfo?,
selectedTabIndexProvider: () -> Int,
selectedOfferEligibilityProvider: () -> OfferEligibility,
customVariablesProvider: () -> Map<String, CustomVariableValue>,
): PackageComponentState {
val windowSize = currentWindowAdaptiveInfo().windowSizeClass.windowWidthSizeClass

return remember(style) {
PackageComponentState(
initialWindowSize = windowSize,
style = style,
selectedPackageInfoProvider = selectedPackageInfoProvider,
selectedTabIndexProvider = selectedTabIndexProvider,
selectedOfferEligibilityProvider = selectedOfferEligibilityProvider,
customVariablesProvider = customVariablesProvider,
)
}.apply {
update(windowSize = windowSize)
}
}

@Suppress("LongParameterList")
@Stable
internal class PackageComponentState(
initialWindowSize: WindowWidthSizeClass,
private val style: PackageComponentStyle,
private val selectedPackageInfoProvider: () -> PaywallState.Loaded.Components.SelectedPackageInfo?,
private val selectedTabIndexProvider: () -> Int,
private val selectedOfferEligibilityProvider: () -> OfferEligibility,
private val customVariablesProvider: () -> Map<String, CustomVariableValue> = { emptyMap() },
) {
private var windowSize by mutableStateOf(initialWindowSize)

private val packageAwareDelegate = PackageAwareDelegate(
style = style,
selectedPackageInfoProvider = selectedPackageInfoProvider,
selectedTabIndexProvider = selectedTabIndexProvider,
selectedOfferEligibilityProvider = selectedOfferEligibilityProvider,
)

private val presentedPartial by derivedStateOf {
val windowCondition = ScreenCondition.from(windowSize)
val componentState =
if (packageAwareDelegate.isSelected) ComponentViewState.SELECTED else ComponentViewState.DEFAULT

style.overrides.buildPresentedPartial(
windowCondition,
packageAwareDelegate.offerEligibility,
componentState,
conditionContext = ConditionContext(
selectedPackageId = selectedPackageInfoProvider()?.rcPackage?.identifier,
customVariables = customVariablesProvider(),
),
)
}

@get:JvmSynthetic
val visible by derivedStateOf { presentedPartial?.partial?.visible ?: style.visible }

@JvmSynthetic
fun update(windowSize: WindowWidthSizeClass) {
this.windowSize = windowSize
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ internal fun PackageComponentView(
clickHandler: suspend (PaywallAction) -> Unit,
modifier: Modifier = Modifier,
) {
val packageState = rememberUpdatedPackageComponentState(style = style, paywallState = state)

if (!packageState.visible) return

StackComponentView(
style = style.stackComponentStyle,
state = state,
Expand Down
Loading