Skip to content

Commit bc2cc3f

Browse files
committed
version 3.4.0
1 parent 4c7532d commit bc2cc3f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+610
-292
lines changed

adapty-ui-video/src/main/java/com/adapty/ui/internal/ui/element/VideoElement.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ import androidx.media3.ui.AspectRatioFrameLayout
3030
import androidx.media3.ui.PlayerView
3131
import com.adapty.internal.utils.InternalAdaptyApi
3232
import com.adapty.ui.AdaptyUI.LocalizedViewConfiguration.Asset
33-
import com.adapty.ui.internal.mapping.element.Assets
34-
import com.adapty.ui.internal.text.StringId
35-
import com.adapty.ui.internal.text.StringWrapper
3633
import com.adapty.ui.internal.ui.attributes.AspectRatio
3734
import com.adapty.ui.internal.ui.fillWithBaseParams
3835
import com.adapty.ui.internal.utils.EventCallback
@@ -56,9 +53,9 @@ public class VideoElement internal constructor(
5653

5754
@UnstableApi
5855
override fun toComposable(
59-
resolveAssets: () -> Assets,
60-
resolveText: @Composable (StringId) -> StringWrapper?,
61-
resolveState: () -> Map<String, Any>,
56+
resolveAssets: ResolveAssets,
57+
resolveText: ResolveText,
58+
resolveState: ResolveState,
6259
eventCallback: EventCallback,
6360
modifier: Modifier,
6461
): @Composable () -> Unit = renderVideo@{

adapty-ui-video/src/main/java/com/adapty/ui/internal/utils/utils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,6 @@ internal fun providePlayerDeps(context: Context): Iterable<Pair<KClass<*>, Map<S
6363
)
6464
}
6565

66-
internal const val VERSION_NAME = "3.3.0"
66+
internal const val VERSION_NAME = "3.4.0"
6767
internal const val LOG_PREFIX = "UI (video) v${VERSION_NAME}:"
6868
internal const val LOG_PREFIX_ERROR = "UI (video) v${VERSION_NAME} error:"

adapty-ui/src/main/java/com/adapty/ui/internal/text/ComposeTextAttrs.kt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,20 @@ internal class ComposeTextAttrs(
2525
) {
2626
companion object {
2727
@Composable
28-
fun from(attrs: RichText.Attributes, assets: Assets): ComposeTextAttrs {
28+
fun from(
29+
richTextAttrs: RichText.Attributes,
30+
textElementAttrs: BaseTextElement.Attributes?,
31+
assets: Assets,
32+
): ComposeTextAttrs {
2933
return from(
30-
textColorAssetId = attrs.textColorAssetId,
31-
backgroundColorAssetId = attrs.backgroundAssetId,
32-
fontAssetId = attrs.fontAssetId,
33-
fontSize = attrs.size,
34-
underline = attrs.underline,
35-
strikethrough = attrs.strikethrough,
34+
textColorAssetId = richTextAttrs.textColorAssetId
35+
?: textElementAttrs?.textColor?.assetId,
36+
backgroundColorAssetId = richTextAttrs.backgroundAssetId,
37+
fontAssetId = richTextAttrs.fontAssetId,
38+
fontSize = richTextAttrs.size
39+
?: Float.NaN,
40+
underline = richTextAttrs.underline,
41+
strikethrough = richTextAttrs.strikethrough,
3642
assets = assets,
3743
)
3844
}
@@ -65,7 +71,7 @@ internal class ComposeTextAttrs(
6571
return ComposeTextAttrs(
6672
resolveColorAsset(textColorAssetId, assets) ?: resolveColor(fontAsset?.color),
6773
resolveColorAsset(backgroundColorAssetId, assets),
68-
fontSize ?: fontAsset?.size,
74+
(fontSize ?: fontAsset?.size)?.takeIf { !it.isNaN() },
6975
resolveTextDecoration(underline, strikethrough),
7076
resolveFontFamily(fontAsset, context),
7177
)

adapty-ui/src/main/java/com/adapty/ui/internal/text/TagResolver.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.adapty.models.AdaptyPeriodUnit.YEAR
1414
import com.adapty.ui.AdaptyUI.LocalizedViewConfiguration.RichText
1515
import com.adapty.ui.internal.mapping.element.Assets
1616
import com.adapty.ui.internal.mapping.element.Products
17+
import com.adapty.ui.internal.ui.element.BaseTextElement.Attributes
1718
import com.adapty.ui.internal.utils.firstDiscountOfferOrNull
1819
import com.adapty.ui.listeners.AdaptyUiTagResolver
1920
import java.math.RoundingMode
@@ -28,6 +29,7 @@ internal class TagResolver(
2829
fun tryResolveProductTag(
2930
item: RichText.Item.Tag,
3031
productId: String?,
32+
textElementAttrs: Attributes?,
3133
assets: Assets,
3234
products: Products,
3335
): StringWrapper.Str? {
@@ -51,7 +53,7 @@ internal class TagResolver(
5153
}
5254
}
5355
}.orEmpty()
54-
return StringWrapper.Str(text, item.attrs?.let { ComposeTextAttrs.from(it, assets) })
56+
return StringWrapper.Str(text, item.attrs?.let { ComposeTextAttrs.from(it, textElementAttrs, assets) })
5557
}
5658

5759
private fun createPricePerPeriodText(product: AdaptyPaywallProduct, targetUnit: AdaptyPeriodUnit): String? {
@@ -83,6 +85,7 @@ internal class TagResolver(
8385
@Composable
8486
fun tryResolveTimerTag(
8587
item: RichText.Item.Tag,
88+
textElementAttrs: Attributes?,
8689
assets: Assets,
8790
): StringWrapper.TimerSegmentStr? {
8891
val tag = item.tag
@@ -96,7 +99,7 @@ internal class TagResolver(
9699
return StringWrapper.TimerSegmentStr(
97100
"%0${numberOfDigits}d",
98101
timeUnit,
99-
item.attrs?.let { ComposeTextAttrs.from(it, assets) },
102+
item.attrs?.let { ComposeTextAttrs.from(it, textElementAttrs, assets) },
100103
)
101104
}
102105
}
@@ -110,7 +113,7 @@ internal class TagResolver(
110113
return StringWrapper.TimerSegmentStr(
111114
"%0${numberOfDigits}d",
112115
timeUnit,
113-
item.attrs?.let { ComposeTextAttrs.from(it, assets) },
116+
item.attrs?.let { ComposeTextAttrs.from(it, textElementAttrs, assets) },
114117
)
115118
}
116119

@@ -130,6 +133,7 @@ internal class TagResolver(
130133
@Composable
131134
fun tryResolveCustomTag(
132135
item: RichText.Item.Tag,
136+
textElementAttrs: Attributes?,
133137
assets: Assets,
134138
ignoreMissingCustomTag: Boolean,
135139
): StringWrapper.Str {
@@ -138,7 +142,7 @@ internal class TagResolver(
138142
return StringWrapper.CUSTOM_TAG_NOT_FOUND
139143
item.tag
140144
}
141-
return StringWrapper.Str(text, item.attrs?.let { ComposeTextAttrs.from(it, assets) })
145+
return StringWrapper.Str(text, item.attrs?.let { ComposeTextAttrs.from(it, textElementAttrs, assets) })
142146
}
143147
}
144148

adapty-ui/src/main/java/com/adapty/ui/internal/text/TextResolver.kt

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.adapty.ui.internal.mapping.element.Products
2525
import com.adapty.ui.internal.mapping.element.StateMap
2626
import com.adapty.ui.internal.mapping.element.Texts
2727
import com.adapty.ui.internal.ui.attributes.toComposeFill
28+
import com.adapty.ui.internal.ui.element.BaseTextElement.Attributes
2829
import com.adapty.ui.internal.utils.firstDiscountOfferOrNull
2930
import com.adapty.ui.internal.utils.getBitmap
3031
import com.adapty.ui.internal.utils.getForCurrentSystemTheme
@@ -38,13 +39,14 @@ internal class TextResolver(
3839
@Composable
3940
fun resolve(
4041
stringId: StringId,
42+
textElementAttrs: Attributes?,
4143
texts: Texts,
4244
products: Products,
4345
assets: Assets,
4446
state: StateMap,
4547
): StringWrapper? {
4648
when (stringId) {
47-
is StringId.Str -> return texts[stringId.value]?.toComposeString(assets, products)
49+
is StringId.Str -> return texts[stringId.value]?.toComposeString(textElementAttrs, assets, products)
4850
is StringId.Product -> {
4951
val desiredProductId = stringId.productId?.takeIf { it.isNotEmpty() }
5052
?: state[getProductGroupKey(stringId.productGroupId)] as? String
@@ -63,7 +65,7 @@ internal class TextResolver(
6365
} else {
6466
texts[listOfNotNull("PRODUCT_not_selected", stringId.suffix).joinToString(separator = "_")]
6567
}
66-
return desiredLocalText?.toComposeString(assets, products, desiredProductId)
68+
return desiredLocalText?.toComposeString(textElementAttrs, assets, products, desiredProductId)
6769
}
6870
}
6971
}
@@ -73,17 +75,18 @@ internal class TextResolver(
7375
}
7476

7577
@Composable
76-
private fun TextItem.toComposeString(assets: Assets, products: Products, productId: String? = null): StringWrapper? {
77-
return value.toComposeString(assets, products, fallback == null, productId).let { actualStr ->
78+
private fun TextItem.toComposeString(textElementAttrs: Attributes?, assets: Assets, products: Products, productId: String? = null): StringWrapper? {
79+
return value.toComposeString(textElementAttrs, assets, products, fallback == null, productId).let { actualStr ->
7880
if (actualStr === StringWrapper.CUSTOM_TAG_NOT_FOUND)
79-
fallback?.toComposeString(assets, products, true, productId)
81+
fallback?.toComposeString(textElementAttrs, assets, products, true, productId)
8082
else
8183
actualStr
8284
}
8385
}
8486

8587
@Composable
8688
private fun RichText.toComposeString(
89+
textElementAttrs: Attributes?,
8790
assets: Assets,
8891
products: Products,
8992
ignoreMissingCustomTag: Boolean,
@@ -94,22 +97,30 @@ internal class TextResolver(
9497
if (items.size == 1) {
9598
val item = items.first()
9699
if (item is RichText.Item.Text)
97-
return processRichTextItemText(item, assets)
100+
return processRichTextItemText(item, textElementAttrs, assets)
98101
if (item is RichText.Item.Tag)
99-
return processRichTextItemTag(item, productId, ignoreMissingCustomTag, assets, products)
102+
return processRichTextItemTag(
103+
item,
104+
productId,
105+
textElementAttrs,
106+
ignoreMissingCustomTag,
107+
assets,
108+
products,
109+
)
100110
}
101111
val inlineContent = mutableMapOf<String, InlineTextContent>()
102112
val parts = mutableListOf<StringWrapper.ComplexStr.ComplexStrPart>()
103113
items.forEach { item ->
104114
when (item) {
105115
is RichText.Item.Text -> {
106-
val processedItem = processRichTextItemText(item, assets)
116+
val processedItem = processRichTextItemText(item, textElementAttrs, assets)
107117
parts.add(StringWrapper.ComplexStr.ComplexStrPart.Text(processedItem))
108118
}
109119
is RichText.Item.Tag -> {
110120
val processedItem = processRichTextItemTag(
111121
item,
112122
productId,
123+
textElementAttrs,
113124
ignoreMissingCustomTag,
114125
assets,
115126
products,
@@ -159,21 +170,23 @@ internal class TextResolver(
159170
@Composable
160171
private fun processRichTextItemText(
161172
item: RichText.Item.Text,
173+
textElementAttrs: Attributes?,
162174
assets: Assets,
163175
): StringWrapper.Str {
164-
return StringWrapper.Str(item.text, item.attrs?.let { ComposeTextAttrs.from(it, assets) })
176+
return StringWrapper.Str(item.text, item.attrs?.let { ComposeTextAttrs.from(it, textElementAttrs, assets) })
165177
}
166178

167179
@Composable
168180
private fun processRichTextItemTag(
169181
item: RichText.Item.Tag,
170182
productId: String?,
183+
textElementAttrs: Attributes?,
171184
ignoreMissingCustomTag: Boolean,
172185
assets: Assets,
173186
products: Products,
174187
): StringWrapper.Single {
175-
return tagResolver.tryResolveProductTag(item, productId, assets, products)
176-
?: tagResolver.tryResolveTimerTag(item, assets)
177-
?: tagResolver.tryResolveCustomTag(item, assets, ignoreMissingCustomTag)
188+
return tagResolver.tryResolveProductTag(item, productId, textElementAttrs, assets, products)
189+
?: tagResolver.tryResolveTimerTag(item, textElementAttrs, assets)
190+
?: tagResolver.tryResolveCustomTag(item, textElementAttrs, assets, ignoreMissingCustomTag)
178191
}
179192
}

adapty-ui/src/main/java/com/adapty/ui/internal/ui/AdaptyPaywallInternal.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.adapty.models.AdaptyPurchaseResult
3030
import com.adapty.ui.AdaptyUI
3131
import com.adapty.ui.internal.text.StringId
3232
import com.adapty.ui.internal.ui.element.Action
33+
import com.adapty.ui.internal.ui.element.BaseTextElement.Attributes
3334
import com.adapty.ui.internal.ui.element.SectionElement
3435
import com.adapty.ui.internal.ui.element.fillModifierWithScopedParams
3536
import com.adapty.ui.internal.ui.element.render
@@ -89,7 +90,7 @@ internal fun AdaptyPaywallInternal(viewModel: PaywallViewModel) {
8990
}
9091
val context = LocalContext.current
9192
val resolveAssets = { viewModel.assets }
92-
val resolveText = @Composable { stringId: StringId -> viewModel.resolveText(stringId) }
93+
val resolveText = @Composable { stringId: StringId, textAttrs: Attributes? -> viewModel.resolveText(stringId, textAttrs) }
9394
val resolveState = { viewModel.state }
9495
val sheetState = rememberBottomSheetState()
9596
val scope = rememberCoroutineScope()

adapty-ui/src/main/java/com/adapty/ui/internal/ui/Modifier.kt

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,25 @@ import androidx.compose.foundation.layout.padding
1515
import androidx.compose.foundation.layout.width
1616
import androidx.compose.foundation.layout.widthIn
1717
import androidx.compose.runtime.Composable
18+
import androidx.compose.runtime.remember
1819
import androidx.compose.ui.Modifier
20+
import androidx.compose.ui.composed
1921
import androidx.compose.ui.draw.clip
2022
import androidx.compose.ui.draw.drawBehind
23+
import androidx.compose.ui.draw.drawWithContent
24+
import androidx.compose.ui.geometry.Size
2125
import androidx.compose.ui.graphics.Outline
2226
import androidx.compose.ui.graphics.Path
2327
import androidx.compose.ui.graphics.RectangleShape
2428
import androidx.compose.ui.graphics.Shape
2529
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
2630
import androidx.compose.ui.graphics.nativeCanvas
31+
import androidx.compose.ui.platform.LocalDensity
32+
import androidx.compose.ui.platform.LocalLayoutDirection
2733
import androidx.compose.ui.unit.Dp
2834
import androidx.compose.ui.unit.dp
2935
import com.adapty.internal.utils.InternalAdaptyApi
3036
import com.adapty.ui.AdaptyUI.LocalizedViewConfiguration.Asset
31-
import com.adapty.ui.internal.mapping.element.Assets
3237
import com.adapty.ui.internal.ui.attributes.DimSpec
3338
import com.adapty.ui.internal.ui.attributes.EdgeEntities
3439
import com.adapty.ui.internal.ui.attributes.Offset
@@ -37,12 +42,13 @@ import com.adapty.ui.internal.ui.attributes.toComposeFill
3742
import com.adapty.ui.internal.ui.attributes.toComposeShape
3843
import com.adapty.ui.internal.ui.attributes.toExactDp
3944
import com.adapty.ui.internal.ui.attributes.verticalSumOrDefault
45+
import com.adapty.ui.internal.ui.element.ResolveAssets
4046
import com.adapty.ui.internal.ui.element.UIElement
4147
import com.adapty.ui.internal.utils.getForCurrentSystemTheme
4248

4349
@InternalAdaptyApi
4450
@Composable
45-
public fun Modifier.fillWithBaseParams(element: UIElement, resolveAssets: () -> Assets): Modifier {
51+
public fun Modifier.fillWithBaseParams(element: UIElement, resolveAssets: ResolveAssets): Modifier {
4652
return this
4753
.sizeAndMarginsOrSkip(element)
4854
.offsetOrSkip(element.baseProps.offset)
@@ -52,17 +58,17 @@ public fun Modifier.fillWithBaseParams(element: UIElement, resolveAssets: () ->
5258
@Composable
5359
internal fun Modifier.backgroundOrSkip(
5460
decorator: com.adapty.ui.internal.ui.attributes.Shape?,
55-
resolveAssets: () -> Assets,
61+
resolveAssets: ResolveAssets,
5662
): Modifier {
5763
val decorator = decorator ?: return this
5864
var modifier = this
5965
val backgroundShape = decorator.type.toComposeShape()
66+
modifier = modifier.clipToShape(backgroundShape)
6067
if (decorator.fill != null) {
6168
val backgroundAsset = resolveAssets().getForCurrentSystemTheme(decorator.fill.assetId) as? Asset.Filling.Local
6269
if (backgroundAsset != null)
6370
modifier = modifier.background(backgroundAsset, backgroundShape)
6471
}
65-
modifier = modifier.clip(backgroundShape)
6672

6773
if (decorator.border != null) {
6874
when (val borderAsset = resolveAssets().getForCurrentSystemTheme(decorator.border.color) as? Asset.Filling.Local) {
@@ -86,6 +92,32 @@ internal fun Modifier.backgroundOrSkip(
8692
return modifier
8793
}
8894

95+
private fun Modifier.clipToShape(
96+
shape: Shape,
97+
) = composed {
98+
val density = LocalDensity.current
99+
val layoutDirection = LocalLayoutDirection.current
100+
101+
val useCustomClip = remember(shape) {
102+
shape.createOutline(Size(100f, 100f), layoutDirection, density) is Outline.Generic
103+
}
104+
105+
if (useCustomClip) {
106+
drawWithContent {
107+
val outline = shape.createOutline(size, layoutDirection, density)
108+
val path = (outline as Outline.Generic).path
109+
110+
val canvas = drawContext.canvas
111+
canvas.save()
112+
canvas.clipPath(path)
113+
drawContent()
114+
canvas.restore()
115+
}
116+
} else {
117+
clip(shape)
118+
}
119+
}
120+
89121
private fun Modifier.background(
90122
asset: Asset.Filling.Local,
91123
shape: Shape,

adapty-ui/src/main/java/com/adapty/ui/internal/ui/PaywallViewModel.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.adapty.ui.internal.text.PriceConverter
3030
import com.adapty.ui.internal.text.StringId
3131
import com.adapty.ui.internal.text.TagResolver
3232
import com.adapty.ui.internal.text.TextResolver
33+
import com.adapty.ui.internal.ui.element.BaseTextElement.Attributes
3334
import com.adapty.ui.internal.utils.EventCallback
3435
import com.adapty.ui.internal.utils.LOADING_PRODUCTS_RETRY_DELAY
3536
import com.adapty.ui.internal.utils.LOG_PREFIX
@@ -339,8 +340,8 @@ internal class PaywallViewModel(
339340
}
340341

341342
@Composable
342-
fun resolveText(stringId: StringId) =
343-
textResolver.resolve(stringId, texts, products, assets, state)
343+
fun resolveText(stringId: StringId, textAttrs: Attributes?) =
344+
textResolver.resolve(stringId, textAttrs, texts, products, assets, state)
344345

345346
fun getTimerStartTimestamp(placementId: String, timerId: String, isPersisted: Boolean): Long? {
346347
return cacheRepository.getLongValue(getTimerStartTimestampId(placementId, timerId), isPersisted)

0 commit comments

Comments
 (0)