Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Paywalls V2] Moves more state to PaywallState #1988

Merged
merged 56 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
15ee579
Adds PaywallComponentsData to Offering, and has PaywallViewModel use …
JayShortway Dec 11, 2024
97a6d2a
Renames PaywallDataValidationTest to LegacyPaywallDataValidationTest.
JayShortway Dec 12, 2024
f039302
LoadingPaywall calls toLegacyPaywallState.
JayShortway Dec 12, 2024
9153fc0
OfferingParser parses paywall_components.
JayShortway Dec 12, 2024
0a07fd5
Adds Paywalls V2 support to PaywallsTester.
JayShortway Dec 12, 2024
8616a26
Adds missing circle MaskShape.
JayShortway Dec 12, 2024
bbe72eb
LoadedPaywallComponents will always fill the maximum available size.
JayShortway Dec 12, 2024
27837e2
ImageUrls width and height are optional.
JayShortway Dec 12, 2024
0e60bd3
Merge branch 'main' into pw2-offerings-data
JayShortway Dec 12, 2024
3d6fd64
Merge branch 'pw2-offerings-data' into pw2-tester
JayShortway Dec 12, 2024
da94c38
Reverts Constants.
JayShortway Dec 12, 2024
f849520
Merge branch 'pw2-tester' into pw2-various-fixes
JayShortway Dec 12, 2024
b669421
Fixes lint.
JayShortway Dec 12, 2024
07cfc1c
Merge branch 'pw2-offerings-data' into pw2-tester
JayShortway Dec 12, 2024
442b479
Merge branch 'pw2-tester' into pw2-various-fixes
JayShortway Dec 12, 2024
49e604a
StackComponentView changes background color when the theme changes.
JayShortway Dec 12, 2024
2b5574d
Adds a failing test to StackComponentViewTests.
JayShortway Dec 12, 2024
7271506
Adds 2 previews.
JayShortway Dec 12, 2024
dc58101
Ensures MDParagraph uses the correct fontSize.
JayShortway Dec 12, 2024
4f4bc41
Merge branch 'main' into pw2-offerings-data
JayShortway Dec 12, 2024
c7657da
Merge branch 'pw2-offerings-data' into pw2-tester
JayShortway Dec 12, 2024
4b54f33
Merge branch 'pw2-tester' into pw2-various-fixes
JayShortway Dec 12, 2024
831854a
Merge branch 'pw2-various-fixes' into pw2-fix-fontsize
JayShortway Dec 12, 2024
7bc2786
Adds another failing test to StackComponentViewTests.
JayShortway Dec 12, 2024
38401ed
Removing some redundant parameters.
JayShortway Dec 12, 2024
65affb8
Fixes the border test.
JayShortway Dec 12, 2024
453b5cf
Fixes the shadow test.
JayShortway Dec 12, 2024
4c189ee
Some cleanup.
JayShortway Dec 12, 2024
7952c6a
Merge branch 'pw2-fix-fontsize' into pw2-stack-tests
JayShortway Dec 12, 2024
a342ed8
Merge branch 'main' into pw2-tester
JayShortway Dec 13, 2024
2cc6c97
Merge branch 'pw2-tester' into pw2-various-fixes
JayShortway Dec 13, 2024
7cca77b
Merge branch 'pw2-various-fixes' into pw2-fix-fontsize
JayShortway Dec 13, 2024
c43525e
Merge branch 'pw2-fix-fontsize' into pw2-stack-tests
JayShortway Dec 13, 2024
914d9da
Adds a regression test.
JayShortway Dec 13, 2024
9abcb6a
Excludes Paywalls V1 from new font size behavior.
JayShortway Dec 13, 2024
870c577
Merge branch 'main' into pw2-fix-fontsize
JayShortway Dec 13, 2024
d5c4ae9
Merge branch 'pw2-fix-fontsize' into pw2-stack-tests
JayShortway Dec 13, 2024
43f1ecf
TextComponentStyle no longer needs a Composable context to be created.
JayShortway Dec 13, 2024
412312e
TextComponentStyle just has a single constructor now.
JayShortway Dec 13, 2024
9a6bab4
Merge branch 'main' into pw2-stack-tests
JayShortway Dec 16, 2024
8bcb10d
Moves rememberProcessedText from StyleFactory to TextComponentView.
JayShortway Dec 16, 2024
524ae3b
Removes unused StyleFactory parameters.
JayShortway Dec 16, 2024
7adc5d3
StyleFactory no longer needs a Composable context.
JayShortway Dec 16, 2024
d57b87a
Merge branch 'pw2-stack-tests' into pw2-simplify-textstyle
JayShortway Dec 16, 2024
7ef7d46
Locale and LocalizationDictionary are part of PaywallState now.
JayShortway Dec 16, 2024
ea77f24
Adds LoadedPaywallComponentsLocaleTests.
JayShortway Dec 16, 2024
8237323
Adds isEligibleForIntroOffer to PaywallState.
JayShortway Dec 16, 2024
68f3c38
Removes braces from a Preview annotation to please lint.
JayShortway Dec 16, 2024
f18ea32
Moves PackageContext to PaywallState.
JayShortway Dec 16, 2024
81bb7a6
Renames VariableContextTests to MostExpensivePricePerMonthMicrosTests.
JayShortway Dec 16, 2024
d7a1367
Moves MostExpensivePricePerMonthMicrosTests to the data package.
JayShortway Dec 16, 2024
dfc5024
TextComponentView uses PaywallState.
JayShortway Dec 16, 2024
f69c7b9
MostExpensivePricePerMonthMicrosTests uses FakePaywallState.
JayShortway Dec 16, 2024
2fdc87c
Merge branch 'main' into pw2-more-paywallstate
JayShortway Dec 17, 2024
5544518
Reorders imports in ButtonComponentView.
JayShortway Dec 17, 2024
fb75780
Fixes ButtonComponentViewTests.
JayShortway Dec 17, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import kotlinx.serialization.descriptors.buildSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

/**
* @property value The language tag of this locale, with an underscore separating the language from the region.
*/
@InternalRevenueCatAPI
@Serializable
@JvmInline
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.revenuecat.purchases.ui.revenuecatui.components.style.ImageComponentS
import com.revenuecat.purchases.ui.revenuecatui.components.style.StackComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.components.style.TextComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.components.text.TextComponentView
import com.revenuecat.purchases.ui.revenuecatui.data.PaywallState

/**
* A Composable that can show any [ComponentStyle].
Expand All @@ -21,10 +22,11 @@ import com.revenuecat.purchases.ui.revenuecatui.components.text.TextComponentVie
@Composable
internal fun ComponentView(
style: ComponentStyle,
state: PaywallState.Loaded.Components,
modifier: Modifier = Modifier,
) = when (style) {
is StackComponentStyle -> StackComponentView(style = style, modifier = modifier)
is TextComponentStyle -> TextComponentView(style = style, modifier = modifier)
is StackComponentStyle -> StackComponentView(style = style, state = state, modifier = modifier)
is TextComponentStyle -> TextComponentView(style = style, state = state, modifier = modifier)
is ImageComponentStyle -> ImageComponentView(style = style, modifier = modifier)
is ButtonComponentStyle -> ButtonComponentView(style = style, modifier = modifier)
is ButtonComponentStyle -> ButtonComponentView(style = style, state = state, modifier = modifier)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package com.revenuecat.purchases.ui.revenuecatui.components

import android.content.res.Configuration
import android.os.LocaleList
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -50,30 +49,24 @@ import com.revenuecat.purchases.ui.revenuecatui.components.style.StyleFactory
import com.revenuecat.purchases.ui.revenuecatui.data.PaywallState
import com.revenuecat.purchases.ui.revenuecatui.helpers.getOrThrow
import java.net.URL
import java.util.Locale

@Composable
internal fun LoadedPaywallComponents(
state: PaywallState.Loaded.Components,
modifier: Modifier = Modifier,
) {
val configuration = LocalConfiguration.current
// Configured locales take precedence over the default one.
val preferredIds = configuration.locales.mapToLocaleIds() + state.data.defaultLocaleIdentifier
// Find the first locale we have a LocalizationDictionary for.
val localeId = preferredIds.first { id -> state.data.componentsLocalizations.containsKey(id) }
val localizationDictionary = state.data.componentsLocalizations.getValue(localeId)
val locale = localeId.toLocale()
state.update(localeList = configuration.locales)

val windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
val windowSize = ScreenCondition.from(windowSizeClass.windowWidthSizeClass)

val styleFactory = remember(locale, windowSize) {
val styleFactory = remember(state.locale, windowSize) {
StyleFactory(
windowSize = windowSize,
isEligibleForIntroOffer = false,
componentState = ComponentViewState.DEFAULT,
localizationDictionary = localizationDictionary,
localizationDictionary = state.localizationDictionary,
)
}

Expand All @@ -83,27 +76,13 @@ internal fun LoadedPaywallComponents(

ComponentView(
style = style,
state = state,
modifier = modifier
.fillMaxSize()
.background(background),
)
}

private fun LocaleList.mapToLocaleIds(): List<LocaleId> {
val result = ArrayList<LocaleId>(size())
for (i in 0 until size()) {
val locale = get(i)
if (locale != null) result.add(locale.toLocaleId())
}
return result
}

private fun LocaleId.toLocale(): Locale =
Locale.forLanguageTag(value)

private fun Locale.toLocaleId(): LocaleId =
LocaleId(toLanguageTag())

@Suppress("LongMethod")
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO or Configuration.UI_MODE_TYPE_NORMAL)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL)
Expand Down Expand Up @@ -184,7 +163,7 @@ private fun LoadedPaywallComponents_Preview() {
}

@Suppress("LongMethod")
@Preview()
@Preview
@Composable
private fun LoadedPaywallComponents_Preview_Bless() {
val textColor = ColorScheme(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.paywalls.components.StackComponent
import com.revenuecat.purchases.paywalls.components.common.Background
import com.revenuecat.purchases.paywalls.components.common.ComponentsConfig
import com.revenuecat.purchases.paywalls.components.common.LocaleId
import com.revenuecat.purchases.paywalls.components.common.PaywallComponentsConfig
import com.revenuecat.purchases.paywalls.components.common.PaywallComponentsData
import com.revenuecat.purchases.paywalls.components.properties.Border
import com.revenuecat.purchases.paywalls.components.properties.ColorInfo
import com.revenuecat.purchases.paywalls.components.properties.ColorScheme
Expand All @@ -37,17 +44,21 @@ import com.revenuecat.purchases.ui.revenuecatui.components.stack.StackComponentV
import com.revenuecat.purchases.ui.revenuecatui.components.style.ButtonComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.components.style.StackComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.components.style.TextComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.data.PaywallState
import kotlinx.coroutines.launch
import java.net.URL

@Composable
internal fun ButtonComponentView(
style: ButtonComponentStyle,
state: PaywallState.Loaded.Components,
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
var isClickable by remember { mutableStateOf(true) }
StackComponentView(
style.stackComponentStyle,
state,
modifier.clickable(enabled = isClickable) {
isClickable = false
coroutineScope.launch {
Expand All @@ -61,7 +72,7 @@ internal fun ButtonComponentView(
@Preview
@Composable
private fun ButtonComponentView_Preview_Default() {
ButtonComponentView(previewButtonComponentStyle())
ButtonComponentView(previewButtonComponentStyle(), previewEmptyState())
}

@Composable
Expand Down Expand Up @@ -112,3 +123,29 @@ private fun previewButtonComponentStyle(
actionHandler = actionHandler,
)
}

private fun previewEmptyState(): PaywallState.Loaded.Components {
val data = PaywallComponentsData(
templateName = "template",
assetBaseURL = URL("https://assets.pawwalls.com"),
componentsConfig = ComponentsConfig(
base = PaywallComponentsConfig(
// This would normally contain at least one ButtonComponent, but that's not needed for previews.
stack = StackComponent(components = emptyList()),
background = Background.Color(ColorScheme(light = ColorInfo.Hex(Color.White.toArgb()))),
stickyFooter = null,
),
),
componentsLocalizations = emptyMap(),
defaultLocaleIdentifier = LocaleId("en_US"),
)
val offering = Offering(
identifier = "identifier",
serverDescription = "serverDescription",
metadata = emptyMap(),
availablePackages = emptyList(),
paywallComponents = data,
)

return PaywallState.Loaded.Components(offering, data)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.paywalls.components.StackComponent
import com.revenuecat.purchases.paywalls.components.common.Background
import com.revenuecat.purchases.paywalls.components.common.ComponentsConfig
import com.revenuecat.purchases.paywalls.components.common.LocaleId
import com.revenuecat.purchases.paywalls.components.common.PaywallComponentsConfig
import com.revenuecat.purchases.paywalls.components.common.PaywallComponentsData
import com.revenuecat.purchases.paywalls.components.properties.Border
import com.revenuecat.purchases.paywalls.components.properties.ColorInfo
import com.revenuecat.purchases.paywalls.components.properties.ColorScheme
Expand Down Expand Up @@ -49,12 +56,15 @@ import com.revenuecat.purchases.ui.revenuecatui.components.properties.rememberCo
import com.revenuecat.purchases.ui.revenuecatui.components.properties.rememberShadowStyle
import com.revenuecat.purchases.ui.revenuecatui.components.style.StackComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.components.style.TextComponentStyle
import com.revenuecat.purchases.ui.revenuecatui.data.PaywallState
import com.revenuecat.purchases.ui.revenuecatui.extensions.applyIfNotNull
import java.net.URL

@Suppress("LongMethod")
@Composable
internal fun StackComponentView(
style: StackComponentStyle,
state: PaywallState.Loaded.Components,
modifier: Modifier = Modifier,
) {
if (style.visible) {
Expand All @@ -74,7 +84,7 @@ internal fun StackComponentView(
}

val content: @Composable () -> Unit = remember(style.children) {
@Composable { style.children.forEach { child -> ComponentView(style = child) } }
@Composable { style.children.forEach { child -> ComponentView(style = child, state = state) } }
}

// Show the right container composable depending on the dimension.
Expand Down Expand Up @@ -142,6 +152,7 @@ private fun StackComponentView_Preview_Vertical() {
y = 3.0,
),
),
state = previewEmptyState(),
)
}
}
Expand Down Expand Up @@ -175,6 +186,7 @@ private fun StackComponentView_Preview_Horizontal() {
y = 5.0,
),
),
state = previewEmptyState(),
)
}
}
Expand Down Expand Up @@ -247,6 +259,7 @@ private fun StackComponentView_Preview_ZLayer() {
y = 5.0,
),
),
state = previewEmptyState(),
)
}
}
Expand Down Expand Up @@ -290,3 +303,29 @@ private fun previewChildren() = listOf(
margin = Padding(top = 0.0, bottom = 0.0, leading = 0.0, trailing = 0.0).toPaddingValues(),
),
)

private fun previewEmptyState(): PaywallState.Loaded.Components {
val data = PaywallComponentsData(
templateName = "template",
assetBaseURL = URL("https://assets.pawwalls.com"),
componentsConfig = ComponentsConfig(
base = PaywallComponentsConfig(
// This would normally contain at least one StackComponent, but that's not needed for previews.
stack = StackComponent(components = emptyList()),
background = Background.Color(ColorScheme(light = ColorInfo.Hex(Color.White.toArgb()))),
stickyFooter = null,
),
),
componentsLocalizations = emptyMap(),
defaultLocaleIdentifier = LocaleId("en_US"),
)
val offering = Offering(
identifier = "identifier",
serverDescription = "serverDescription",
metadata = emptyMap(),
availablePackages = emptyList(),
paywallComponents = data,
)

return PaywallState.Loaded.Components(offering, data)
}
Loading