@momo-kits/native-kits 0.164.1-beta.8 → 0.164.1-beta.9-debug
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.gradle.kts +11 -0
- package/compose/build.gradle.kts +190 -0
- package/compose/build.gradle.kts.backup +190 -0
- package/compose/compose.podspec +47 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +19 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +150 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +52 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +106 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +183 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +39 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +293 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +826 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +110 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +378 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +82 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +356 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +113 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +542 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +134 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +475 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +214 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +240 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +216 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +259 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +182 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +328 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +97 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +310 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +323 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +217 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +199 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +470 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +88 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +131 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +203 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +498 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +175 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +234 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +188 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +325 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +16 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +188 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +263 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +52 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +38 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +39 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +299 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +129 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +103 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +192 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +406 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +612 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +164 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +156 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +225 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +320 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +81 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +309 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +34 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +360 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +132 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +127 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +15 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +69 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +105 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +40 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ComposeBackGesture.ios.kt +65 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +32 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +35 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +228 -0
- package/gradle/libs.versions.toml +69 -0
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/gradle.properties +26 -0
- package/gradlew +252 -0
- package/gradlew.bat +94 -0
- package/ios/native-kits.podspec +1 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/ios-demo/README.md +120 -0
- package/local.properties +8 -0
- package/package.json +1 -1
- package/settings.gradle.kts +64 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package vn.momo.kits.utils
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.*
|
|
4
|
+
import org.jetbrains.compose.resources.DrawableResource
|
|
5
|
+
import org.jetbrains.compose.resources.InternalResourceApi
|
|
6
|
+
import org.jetbrains.compose.resources.ResourceItem
|
|
7
|
+
import org.jetbrains.compose.resources.readResourceBytes
|
|
8
|
+
@OptIn(InternalResourceApi::class)
|
|
9
|
+
@Composable
|
|
10
|
+
internal fun readJson(name: String): String {
|
|
11
|
+
val path = name.plus(".json")
|
|
12
|
+
val candidatePaths = listOf(
|
|
13
|
+
path,
|
|
14
|
+
"composeResources/vn.momo.compose.resources/$path",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
val jsonContent by rememberState(path, { "" }) {
|
|
18
|
+
val cached = resourceCache.getOrPut(path) {
|
|
19
|
+
var content = ""
|
|
20
|
+
for (candidate in candidatePaths) {
|
|
21
|
+
try {
|
|
22
|
+
content = readResourceBytes(candidate).decodeToString()
|
|
23
|
+
break
|
|
24
|
+
} catch (_: Exception) {
|
|
25
|
+
// try next candidate
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
ResourceCache.JSON(content)
|
|
29
|
+
} as ResourceCache.JSON
|
|
30
|
+
|
|
31
|
+
cached.json
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return jsonContent
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
private val resourceCache = mutableMapOf<String, ResourceCache>()
|
|
39
|
+
|
|
40
|
+
private sealed interface ResourceCache {
|
|
41
|
+
class JSON(val json: String) : ResourceCache
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Composable
|
|
45
|
+
fun <T> rememberState(
|
|
46
|
+
key: Any,
|
|
47
|
+
getDefault: () -> T,
|
|
48
|
+
block: suspend () -> T
|
|
49
|
+
): MutableState<T> {
|
|
50
|
+
val state = remember(key) { mutableStateOf(getDefault()) }
|
|
51
|
+
LaunchedEffect(key) {
|
|
52
|
+
state.value = block()
|
|
53
|
+
}
|
|
54
|
+
return state
|
|
55
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package vn.momo.kits.utils
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import vn.momo.kits.application.LocalComponentInformation
|
|
5
|
+
|
|
6
|
+
@Composable
|
|
7
|
+
internal fun getComponentId(
|
|
8
|
+
componentName: String? = null,
|
|
9
|
+
accessibilityLabel: String? = null,
|
|
10
|
+
): String {
|
|
11
|
+
val componentInformation = LocalComponentInformation.current
|
|
12
|
+
if (accessibilityLabel != null) return accessibilityLabel
|
|
13
|
+
if (componentInformation?.componentId != null) return componentInformation.componentId
|
|
14
|
+
return ""
|
|
15
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
package vn.momo.kits.utils
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
4
|
+
import androidx.compose.foundation.layout.asPaddingValues
|
|
5
|
+
import androidx.compose.foundation.layout.systemBars
|
|
6
|
+
import androidx.compose.runtime.Composable
|
|
7
|
+
import androidx.compose.ui.Modifier
|
|
8
|
+
import androidx.compose.ui.composed
|
|
9
|
+
import androidx.compose.ui.draw.drawBehind
|
|
10
|
+
import androidx.compose.ui.geometry.Offset
|
|
11
|
+
import androidx.compose.ui.graphics.Color
|
|
12
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
13
|
+
import androidx.compose.ui.unit.Dp
|
|
14
|
+
import androidx.compose.ui.unit.dp
|
|
15
|
+
import androidx.compose.ui.unit.min
|
|
16
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
17
|
+
import vn.momo.kits.const.AppStatusBar
|
|
18
|
+
import vn.momo.kits.platform.getPlatformName
|
|
19
|
+
import kotlin.math.abs
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
internal fun Modifier.bottomBorder(strokeWidth: Dp, color: Color) = composed(
|
|
23
|
+
factory = {
|
|
24
|
+
val density = LocalDensity.current
|
|
25
|
+
val strokeWidthPx = density.run { strokeWidth.toPx() }
|
|
26
|
+
if (strokeWidth > 0.dp) {
|
|
27
|
+
Modifier.drawBehind {
|
|
28
|
+
val width = size.width
|
|
29
|
+
val height = size.height - strokeWidthPx / 2
|
|
30
|
+
|
|
31
|
+
drawLine(
|
|
32
|
+
color = color,
|
|
33
|
+
start = Offset(x = 0f, y = height),
|
|
34
|
+
end = Offset(x = width, y = height),
|
|
35
|
+
strokeWidth = strokeWidthPx
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
Modifier
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
fun <T> Boolean.ifTrue(trueCase: T, falseCase: T): T = if (this) trueCase else falseCase
|
|
45
|
+
fun <T> String.ifNotNull(trueCase: T, falseCase: T): T =
|
|
46
|
+
if (this.isBlank()) falseCase else trueCase
|
|
47
|
+
|
|
48
|
+
fun formatNumberToMoney(number: Long, currency: String = "đ"): String {
|
|
49
|
+
if (number == 0L) {
|
|
50
|
+
return "0$currency"
|
|
51
|
+
}
|
|
52
|
+
val array = mutableListOf<Char>()
|
|
53
|
+
var result = ""
|
|
54
|
+
var isNegative = false
|
|
55
|
+
|
|
56
|
+
if (number < 0) {
|
|
57
|
+
isNegative = true
|
|
58
|
+
}
|
|
59
|
+
val numberString = abs(number).toString() // Convert to Int to avoid decimal places
|
|
60
|
+
if (numberString.length < 3) {
|
|
61
|
+
return numberString + currency
|
|
62
|
+
}
|
|
63
|
+
var count = 0
|
|
64
|
+
for (i in numberString.length - 1 downTo 0) {
|
|
65
|
+
count += 1
|
|
66
|
+
array.add(numberString[i])
|
|
67
|
+
if (count == 3 && i >= 1) {
|
|
68
|
+
array.add('.')
|
|
69
|
+
count = 0
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (i in array.size - 1 downTo 0) {
|
|
74
|
+
result += array[i]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isNegative) {
|
|
78
|
+
result = "-$result"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return result + currency
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Composable
|
|
85
|
+
fun getAppStatusBarHeight(): Dp {
|
|
86
|
+
return if (AppStatusBar.current == 0.dp) {
|
|
87
|
+
WindowInsets.systemBars.asPaddingValues().calculateTopPadding()
|
|
88
|
+
} else {
|
|
89
|
+
AppStatusBar.current
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@Composable
|
|
94
|
+
internal fun getNavigationBarHeight(): Dp {
|
|
95
|
+
return if (AppNavigationBar.current == 0.dp) {
|
|
96
|
+
val systemBottomPadding = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
|
|
97
|
+
if (getPlatformName() == "iOS") {
|
|
98
|
+
min(systemBottomPadding, 21.dp)
|
|
99
|
+
} else {
|
|
100
|
+
systemBottomPadding
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
AppNavigationBar.current
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
|
|
2
|
+
|
|
3
|
+
package vn.momo.kits.const
|
|
4
|
+
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import androidx.compose.runtime.remember
|
|
7
|
+
import androidx.compose.ui.text.font.FontFamily
|
|
8
|
+
import androidx.compose.ui.text.platform.Font
|
|
9
|
+
import kotlinx.cinterop.ExperimentalForeignApi
|
|
10
|
+
import kotlinx.cinterop.addressOf
|
|
11
|
+
import kotlinx.cinterop.usePinned
|
|
12
|
+
import platform.Foundation.NSBundle
|
|
13
|
+
import platform.Foundation.NSData
|
|
14
|
+
import platform.Foundation.dataWithContentsOfFile
|
|
15
|
+
import platform.posix.memcpy
|
|
16
|
+
|
|
17
|
+
@Composable
|
|
18
|
+
internal actual fun hostFontFamily(fileName: String): FontFamily? = remember(fileName) {
|
|
19
|
+
val name = fileName.substringBeforeLast('.')
|
|
20
|
+
val ext = fileName.substringAfterLast('.', "")
|
|
21
|
+
// Font từ font-source nằm rời ở bundle root, không nằm trong compose-resources.
|
|
22
|
+
val path = NSBundle.mainBundle.pathForResource(name, ext) ?: return@remember null
|
|
23
|
+
FontFamily(
|
|
24
|
+
Font(
|
|
25
|
+
identity = fileName,
|
|
26
|
+
getData = {
|
|
27
|
+
NSData.dataWithContentsOfFile(path)?.toByteArray() ?: ByteArray(0)
|
|
28
|
+
},
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
34
|
+
private fun NSData.toByteArray(): ByteArray {
|
|
35
|
+
val size = length.toInt()
|
|
36
|
+
if (size == 0) return ByteArray(0)
|
|
37
|
+
return ByteArray(size).apply {
|
|
38
|
+
usePinned { pinned -> memcpy(pinned.addressOf(0), bytes, length) }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
package vn.momo.kits.navigation
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.DisposableEffect
|
|
5
|
+
import androidx.compose.runtime.remember
|
|
6
|
+
import androidx.navigationevent.NavigationEventDispatcher
|
|
7
|
+
import androidx.navigationevent.NavigationEventInput
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Read-only answer to "will Compose consume this back?", for the iOS host.
|
|
11
|
+
*
|
|
12
|
+
* Compose owns the edge-pan gesture through its own `UIKitBackGestureRecognizer`; the host reads
|
|
13
|
+
* this to decide whether to stand down or keep driving its own recogniser, instead of guessing.
|
|
14
|
+
* Nothing here dispatches — [ObserveBackGestureOwnership] only listens.
|
|
15
|
+
*
|
|
16
|
+
* Pair it with [Navigator.canPop]: the mini-app root reports an enabled handler too (it swallows
|
|
17
|
+
* back to reach `maxApi.dismiss`), yet there the host still owns the gesture.
|
|
18
|
+
*/
|
|
19
|
+
object ComposeBackGesture {
|
|
20
|
+
private val observers = mutableListOf<BackHandlerObserver>()
|
|
21
|
+
|
|
22
|
+
/** State of the top-most mounted container; `false` when none is mounted. */
|
|
23
|
+
val hasEnabledHandlers: Boolean
|
|
24
|
+
get() = observers.lastOrNull()?.hasEnabledHandlers == true
|
|
25
|
+
|
|
26
|
+
internal fun attach(observer: BackHandlerObserver) {
|
|
27
|
+
observers += observer
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
internal fun detach(observer: BackHandlerObserver) {
|
|
31
|
+
observers -= observer
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Publishes one [NavigationContainer]'s back-handling state to [ComposeBackGesture] while composed.
|
|
37
|
+
*
|
|
38
|
+
* Only called for a container whose dispatcher is the scene's — a bare-`UIView` host gets the
|
|
39
|
+
* detached fallback dispatcher, which can never receive an edge pan, so reporting its handlers
|
|
40
|
+
* would tell the host to stand down in favour of a gesture that does not exist.
|
|
41
|
+
*/
|
|
42
|
+
@Composable
|
|
43
|
+
internal fun ObserveBackGestureOwnership(dispatcher: NavigationEventDispatcher) {
|
|
44
|
+
val observer = remember(dispatcher) { BackHandlerObserver() }
|
|
45
|
+
|
|
46
|
+
DisposableEffect(dispatcher, observer) {
|
|
47
|
+
dispatcher.addInput(observer)
|
|
48
|
+
ComposeBackGesture.attach(observer)
|
|
49
|
+
onDispose {
|
|
50
|
+
ComposeBackGesture.detach(observer)
|
|
51
|
+
dispatcher.removeInput(observer)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// A NavigationEventInput that never dispatches: adding an input is the only way to observe the
|
|
57
|
+
// dispatcher's enabled-handler state without registering a handler, which would consume the gesture.
|
|
58
|
+
internal class BackHandlerObserver : NavigationEventInput() {
|
|
59
|
+
var hasEnabledHandlers: Boolean = false
|
|
60
|
+
private set
|
|
61
|
+
|
|
62
|
+
override fun onHasEnabledHandlersChanged(hasEnabledHandlers: Boolean) {
|
|
63
|
+
this.hasEnabledHandlers = hasEnabledHandlers
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package vn.momo.kits.navigation
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.DisposableEffect
|
|
5
|
+
import platform.Foundation.NSNotification
|
|
6
|
+
import platform.Foundation.NSNotificationCenter
|
|
7
|
+
import platform.Foundation.NSOperationQueue
|
|
8
|
+
import platform.darwin.NSObjectProtocol
|
|
9
|
+
|
|
10
|
+
private const val STATUS_BAR_TAPPED_NOTIFICATION = "statusBarSelected"
|
|
11
|
+
|
|
12
|
+
@Composable
|
|
13
|
+
internal actual fun RegisterScrollToTop(callback: (() -> Unit)?) {
|
|
14
|
+
val maxApi = LocalMaxApi.current
|
|
15
|
+
DisposableEffect(callback) {
|
|
16
|
+
val token: NSObjectProtocol? = if (callback != null) {
|
|
17
|
+
NSNotificationCenter.defaultCenter.addObserverForName(
|
|
18
|
+
name = STATUS_BAR_TAPPED_NOTIFICATION,
|
|
19
|
+
`object` = null,
|
|
20
|
+
queue = NSOperationQueue.mainQueue,
|
|
21
|
+
) { _: NSNotification? ->
|
|
22
|
+
runCatching { callback() }.onFailure {
|
|
23
|
+
maxApi?.logFile("[ScrollToTop] callback threw: ${it.message}") {}
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} else null
|
|
28
|
+
onDispose {
|
|
29
|
+
token?.let { NSNotificationCenter.defaultCenter.removeObserver(it) }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
5
|
+
import androidx.compose.runtime.State
|
|
6
|
+
import androidx.compose.runtime.mutableStateOf
|
|
7
|
+
import androidx.compose.runtime.remember
|
|
8
|
+
import androidx.compose.ui.InternalComposeUiApi
|
|
9
|
+
import androidx.compose.ui.backhandler.LocalCompatNavigationEventDispatcherOwner
|
|
10
|
+
import androidx.navigationevent.NavigationEventTransitionState
|
|
11
|
+
|
|
12
|
+
// NavigationEventDispatcher.transitionState is a passive observer: UIKitNavigationEventInput
|
|
13
|
+
// publishes every edge-pan event to it without any handler consuming the gesture. Its `progress`
|
|
14
|
+
// is touch.x / view width, i.e. a plain fraction of the screen width.
|
|
15
|
+
@OptIn(InternalComposeUiApi::class)
|
|
16
|
+
@Composable
|
|
17
|
+
actual fun rememberBackGestureProgress(): State<Float?> {
|
|
18
|
+
val dispatcher = LocalCompatNavigationEventDispatcherOwner.current?.navigationEventDispatcher
|
|
19
|
+
val progress = remember { mutableStateOf<Float?>(null) }
|
|
20
|
+
|
|
21
|
+
LaunchedEffect(dispatcher) {
|
|
22
|
+
if (dispatcher == null) {
|
|
23
|
+
progress.value = null
|
|
24
|
+
return@LaunchedEffect
|
|
25
|
+
}
|
|
26
|
+
dispatcher.transitionState.collect { state ->
|
|
27
|
+
progress.value = (state as? NavigationEventTransitionState.InProgress)
|
|
28
|
+
?.takeIf { it.direction == NavigationEventTransitionState.TRANSITIONING_BACK }
|
|
29
|
+
?.latestEvent
|
|
30
|
+
?.progress
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return progress
|
|
35
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
5
|
+
import androidx.compose.runtime.DisposableEffect
|
|
6
|
+
import androidx.compose.runtime.mutableStateOf
|
|
7
|
+
import androidx.compose.runtime.remember
|
|
8
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
9
|
+
import androidx.compose.ui.unit.Density
|
|
10
|
+
import kotlinx.cinterop.ExperimentalForeignApi
|
|
11
|
+
import kotlinx.cinterop.ObjCAction
|
|
12
|
+
import platform.Foundation.NSNotification
|
|
13
|
+
import platform.Foundation.NSNotificationCenter
|
|
14
|
+
import platform.Foundation.NSSelectorFromString
|
|
15
|
+
import platform.UIKit.UIContentSizeCategoryDidChangeNotification
|
|
16
|
+
import platform.UIKit.UIFont
|
|
17
|
+
import platform.UIKit.UIFontTextStyleBody
|
|
18
|
+
import platform.darwin.NSObject
|
|
19
|
+
|
|
20
|
+
// Compose MP iOS reads LocalDensity.fontScale once at ComposeUIViewController creation and does not
|
|
21
|
+
// recompose it when UIContentSizeCategory changes (Android tracks Configuration.fontScale live). We
|
|
22
|
+
// observe the notification and override LocalDensity.fontScale so scaleSize() recomposes live. The
|
|
23
|
+
// formula matches the SwiftUI kit (UIFont body point size / 17) so both iOS surfaces scale alike.
|
|
24
|
+
private const val DEFAULT_BODY_POINT_SIZE = 17.0
|
|
25
|
+
|
|
26
|
+
private fun currentOsFontScale(): Float =
|
|
27
|
+
(UIFont.preferredFontForTextStyle(UIFontTextStyleBody).pointSize / DEFAULT_BODY_POINT_SIZE).toFloat()
|
|
28
|
+
|
|
29
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
30
|
+
@Composable
|
|
31
|
+
actual fun ProvideOsFontScale(content: @Composable () -> Unit) {
|
|
32
|
+
val osFontScale = remember { mutableStateOf(currentOsFontScale()) }
|
|
33
|
+
|
|
34
|
+
val listener = remember {
|
|
35
|
+
object : NSObject() {
|
|
36
|
+
@Suppress("unused")
|
|
37
|
+
@ObjCAction
|
|
38
|
+
fun contentSizeChanged(arg: NSNotification) {
|
|
39
|
+
osFontScale.value = currentOsFontScale()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
DisposableEffect(Unit) {
|
|
45
|
+
NSNotificationCenter.defaultCenter.addObserver(
|
|
46
|
+
observer = listener,
|
|
47
|
+
selector = NSSelectorFromString(listener::contentSizeChanged.name + ":"),
|
|
48
|
+
name = UIContentSizeCategoryDidChangeNotification,
|
|
49
|
+
`object` = null,
|
|
50
|
+
)
|
|
51
|
+
onDispose {
|
|
52
|
+
NSNotificationCenter.defaultCenter.removeObserver(
|
|
53
|
+
observer = listener,
|
|
54
|
+
name = UIContentSizeCategoryDidChangeNotification,
|
|
55
|
+
`object` = null,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
val density = LocalDensity.current
|
|
61
|
+
CompositionLocalProvider(
|
|
62
|
+
LocalDensity provides Density(density.density, osFontScale.value),
|
|
63
|
+
) {
|
|
64
|
+
content()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Box
|
|
4
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
5
|
+
import androidx.compose.foundation.layout.asPaddingValues
|
|
6
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
7
|
+
import androidx.compose.foundation.layout.systemBars
|
|
8
|
+
import androidx.compose.runtime.Composable
|
|
9
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
10
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
11
|
+
import androidx.compose.runtime.getValue
|
|
12
|
+
import androidx.compose.runtime.mutableStateOf
|
|
13
|
+
import androidx.compose.runtime.remember
|
|
14
|
+
import androidx.compose.runtime.rememberUpdatedState
|
|
15
|
+
import androidx.compose.runtime.setValue
|
|
16
|
+
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
17
|
+
import androidx.compose.ui.InternalComposeUiApi
|
|
18
|
+
import androidx.compose.ui.Modifier
|
|
19
|
+
import androidx.compose.ui.backhandler.LocalCompatNavigationEventDispatcherOwner
|
|
20
|
+
import androidx.compose.ui.backhandler.BackHandler as ComposeBackHandler
|
|
21
|
+
import androidx.compose.ui.graphics.Color
|
|
22
|
+
import androidx.compose.ui.graphics.NativePaint
|
|
23
|
+
import androidx.compose.ui.graphics.toArgb
|
|
24
|
+
import androidx.compose.ui.unit.Dp
|
|
25
|
+
import androidx.compose.ui.unit.dp
|
|
26
|
+
import androidx.compose.ui.viewinterop.UIKitInteropProperties
|
|
27
|
+
import androidx.compose.ui.viewinterop.UIKitView
|
|
28
|
+
import cocoapods.lottie_ios.CompatibleAnimation
|
|
29
|
+
import cocoapods.lottie_ios.CompatibleAnimationKeypath
|
|
30
|
+
import cocoapods.lottie_ios.CompatibleAnimationView
|
|
31
|
+
import kotlinx.cinterop.ExperimentalForeignApi
|
|
32
|
+
import kotlinx.cinterop.get
|
|
33
|
+
import kotlinx.cinterop.memScoped
|
|
34
|
+
import androidx.navigationevent.NavigationEventDispatcher
|
|
35
|
+
import androidx.navigationevent.NavigationEventDispatcherOwner
|
|
36
|
+
import org.jetbrains.skia.FilterBlurMode
|
|
37
|
+
import org.jetbrains.skia.MaskFilter
|
|
38
|
+
import platform.Foundation.NSBundle
|
|
39
|
+
import platform.UIKit.UIColor
|
|
40
|
+
import platform.UIKit.UIDevice
|
|
41
|
+
import platform.UIKit.UIScreen
|
|
42
|
+
import vn.momo.kits.navigation.ObserveBackGestureOwnership
|
|
43
|
+
|
|
44
|
+
actual fun getPlatformName(): String = "iOS"
|
|
45
|
+
|
|
46
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
47
|
+
@Composable
|
|
48
|
+
actual fun getScreenDimensions(): ScreenDimension = memScoped {
|
|
49
|
+
val config = UIScreen.mainScreen.bounds.ptr[0]
|
|
50
|
+
return ScreenDimension(
|
|
51
|
+
config.size.width.toInt(),
|
|
52
|
+
config.size.height.toInt()
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
actual fun NativePaint.setMaskFilter(blurRadius: Float) {
|
|
57
|
+
this.maskFilter = MaskFilter.makeBlur(FilterBlurMode.NORMAL, blurRadius / 2, true)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@Composable
|
|
61
|
+
actual fun getStatusBarHeight(): Dp {
|
|
62
|
+
return WindowInsets.systemBars.asPaddingValues().calculateTopPadding()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// An enabled kit BackHandler is registered inside the NavHost destination, so it out-ranks
|
|
66
|
+
// NavHost's own predictive-back handler and swallows the gesture — that is how a screen opts out
|
|
67
|
+
// of swipe-back (the port of RN's `hasCustomBackHandling`).
|
|
68
|
+
@Suppress("DEPRECATION")
|
|
69
|
+
@OptIn(ExperimentalComposeUiApi::class)
|
|
70
|
+
@Composable
|
|
71
|
+
actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
|
|
72
|
+
ComposeBackHandler(enabled = enabled, onBack = onBack)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@OptIn(InternalComposeUiApi::class)
|
|
76
|
+
@Composable
|
|
77
|
+
actual fun ProvideNavigationEventDispatcherOwner(content: @Composable () -> Unit) {
|
|
78
|
+
val platformOwner = LocalCompatNavigationEventDispatcherOwner.current
|
|
79
|
+
if (platformOwner != null) {
|
|
80
|
+
// UIKitNavigationEventInput is registered on the scene's dispatcher, and that dispatcher
|
|
81
|
+
// having enabled handlers is what arms Compose's UIKitBackGestureRecognizer. Providing a
|
|
82
|
+
// fresh NavigationEventDispatcher() here would shadow it with an input-less one that never
|
|
83
|
+
// sees a single edge-pan event — no recogniser, and no finger-following seek.
|
|
84
|
+
ObserveBackGestureOwnership(platformOwner.navigationEventDispatcher)
|
|
85
|
+
content()
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Bare UIView hosts have no scene dispatcher, and BackHandler/PredictiveBackHandler error() on
|
|
90
|
+
// a null owner. Disabled: nothing can feed it, so it exists only to keep those from throwing.
|
|
91
|
+
val fallbackOwner = remember {
|
|
92
|
+
object : NavigationEventDispatcherOwner {
|
|
93
|
+
override val navigationEventDispatcher = NavigationEventDispatcher().apply {
|
|
94
|
+
isEnabled = false
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
CompositionLocalProvider(
|
|
100
|
+
LocalCompatNavigationEventDispatcherOwner provides fallbackOwner,
|
|
101
|
+
content = content
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@Composable
|
|
106
|
+
actual fun getScreenHeight(): Dp {
|
|
107
|
+
return getScreenDimensions().height.dp
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
actual fun getOSVersion(): OSVersion = OSVersion.IOS(
|
|
111
|
+
major = UIDevice.currentDevice.systemVersion.substringBefore(".").toIntOrNull() ?: 0
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@OptIn(ExperimentalForeignApi::class, ExperimentalComposeUiApi::class)
|
|
115
|
+
@Composable
|
|
116
|
+
actual fun LottieAnimation(
|
|
117
|
+
path: String,
|
|
118
|
+
tintColor: Color?,
|
|
119
|
+
bgColor: Color?,
|
|
120
|
+
placedAsOverlay: Boolean,
|
|
121
|
+
iterations: Int,
|
|
122
|
+
isPlaying: Boolean,
|
|
123
|
+
onEvent: ((String) -> Unit)?,
|
|
124
|
+
modifier: Modifier,
|
|
125
|
+
useCompose: Boolean
|
|
126
|
+
) {
|
|
127
|
+
if (useCompose) {
|
|
128
|
+
ComposeLottieAnimation(path, tintColor, bgColor, iterations, isPlaying, onEvent, modifier)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
val loopCount = if (iterations == LottieIterateForever) -1.0 else iterations.toDouble()
|
|
133
|
+
|
|
134
|
+
var animation by remember { mutableStateOf<CompatibleAnimation?>(null) }
|
|
135
|
+
val animationView = remember { mutableStateOf<CompatibleAnimationView?>(null) }
|
|
136
|
+
|
|
137
|
+
LaunchedEffect(Unit) {
|
|
138
|
+
animation = CompatibleAnimation(name = "compose-resources/composeResources/vn.momo.compose.resources/".plus(path), subdirectory = null, NSBundle.mainBundle)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
val currentOnEvent by rememberUpdatedState(onEvent)
|
|
142
|
+
|
|
143
|
+
LaunchedEffect(isPlaying) {
|
|
144
|
+
currentOnEvent?.invoke(if (isPlaying) LottieEvent.Start else LottieEvent.Pause)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
LaunchedEffect(animationView.value, isPlaying) {
|
|
148
|
+
val view = animationView.value ?: return@LaunchedEffect
|
|
149
|
+
if (isPlaying) {
|
|
150
|
+
view.playWithCompletion(completion = { finished -> if (finished) currentOnEvent?.invoke(LottieEvent.Finish) })
|
|
151
|
+
} else {
|
|
152
|
+
view.pause()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
when (val value = animation) {
|
|
157
|
+
null -> {
|
|
158
|
+
Box(modifier)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
else -> {
|
|
162
|
+
Box(modifier) {
|
|
163
|
+
UIKitView(
|
|
164
|
+
modifier = Modifier.fillMaxSize(),
|
|
165
|
+
properties = UIKitInteropProperties(placedAsOverlay = placedAsOverlay),
|
|
166
|
+
factory = {
|
|
167
|
+
CompatibleAnimationView(value).apply {
|
|
168
|
+
translatesAutoresizingMaskIntoConstraints = true
|
|
169
|
+
|
|
170
|
+
setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
|
|
171
|
+
|
|
172
|
+
setLoopAnimationCount(loopCount)
|
|
173
|
+
setAnimationSpeed(1.0)
|
|
174
|
+
|
|
175
|
+
if (tintColor != null) {
|
|
176
|
+
val uiColor = tintColor.toUIColor()
|
|
177
|
+
setColorValue(uiColor,
|
|
178
|
+
CompatibleAnimationKeypath("**.Fill 1.Color")
|
|
179
|
+
)
|
|
180
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill.Color"))
|
|
181
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Color"))
|
|
182
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke 1.Color"))
|
|
183
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
animationView.value = this
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
update = { view ->
|
|
191
|
+
view.setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
|
|
192
|
+
view.setLoopAnimationCount(loopCount)
|
|
193
|
+
|
|
194
|
+
if (tintColor != null) {
|
|
195
|
+
val uiColor = tintColor.toUIColor()
|
|
196
|
+
|
|
197
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill 1.Color"))
|
|
198
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill.Color"))
|
|
199
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Color"))
|
|
200
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke 1.Color"))
|
|
201
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
fun Color.toUIColor(): UIColor {
|
|
211
|
+
val argb = this.toArgb()
|
|
212
|
+
|
|
213
|
+
val a = ((argb shr 24) and 0xFF) / 255.0
|
|
214
|
+
val r = ((argb shr 16) and 0xFF) / 255.0
|
|
215
|
+
val g = ((argb shr 8) and 0xFF) / 255.0
|
|
216
|
+
val b = (argb and 0xFF) / 255.0
|
|
217
|
+
|
|
218
|
+
return UIColor(
|
|
219
|
+
red = r,
|
|
220
|
+
green = g,
|
|
221
|
+
blue = b,
|
|
222
|
+
alpha = a
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
actual fun NativePaint.setColor(color: Color){
|
|
227
|
+
this.color = color.toArgb()
|
|
228
|
+
}
|