@momo-kits/native-kits 0.300.4 → 0.300.5-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 +13 -0
- package/compose/build.gradle.kts +197 -0
- package/compose/build.gradle.kts.backup +197 -0
- package/compose/compose.podspec +47 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +20 -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 +153 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +6 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +110 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/DesignSystemKits.kt +62 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +1071 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +65 -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 +81 -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 +357 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +115 -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 +49 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +86 -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 +189 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +478 -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 +265 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +223 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +265 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +185 -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 +361 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +308 -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 +330 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +220 -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 +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +92 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +560 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +501 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +176 -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 +236 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +180 -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 +17 -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 +194 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +287 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +54 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +41 -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 +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +58 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +137 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +116 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +215 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +404 -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 +732 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +148 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +233 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +217 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +97 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +377 -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 +455 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +103 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +106 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +413 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +39 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +363 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HelpCenterRequest.kt +37 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +192 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +133 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/ToolkitRequests.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +135 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +12 -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 +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +20 -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 +118 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/HelpCenterRequestTest.kt +44 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/ToolkitRequestsTest.kt +62 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +42 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +45 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +34 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +38 -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 +217 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +138 -0
- package/gradle/libs.versions.toml +68 -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/package.json +1 -1
- package/settings.gradle.kts +64 -0
|
@@ -0,0 +1,217 @@
|
|
|
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 platform.UIKit.UIUserInterfaceIdiomPhone
|
|
43
|
+
import vn.momo.kits.navigation.AttachHostBackGesture
|
|
44
|
+
import vn.momo.kits.navigation.Navigator
|
|
45
|
+
|
|
46
|
+
actual fun getPlatformName(): String = "iOS"
|
|
47
|
+
|
|
48
|
+
actual fun isPhoneIdiom(): Boolean =
|
|
49
|
+
UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone
|
|
50
|
+
|
|
51
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
52
|
+
@Composable
|
|
53
|
+
actual fun getScreenDimensions(): ScreenDimension = memScoped {
|
|
54
|
+
val config = UIScreen.mainScreen.bounds.ptr[0]
|
|
55
|
+
return ScreenDimension(
|
|
56
|
+
config.size.width.toInt(),
|
|
57
|
+
config.size.height.toInt()
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
actual fun NativePaint.setMaskFilter(blurRadius: Float) {
|
|
62
|
+
this.maskFilter = MaskFilter.makeBlur(FilterBlurMode.NORMAL, blurRadius / 2, true)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@Composable
|
|
66
|
+
actual fun getStatusBarHeight(): Dp {
|
|
67
|
+
return WindowInsets.systemBars.asPaddingValues().calculateTopPadding()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Suppress("DEPRECATION")
|
|
71
|
+
@OptIn(ExperimentalComposeUiApi::class)
|
|
72
|
+
@Composable
|
|
73
|
+
actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
|
|
74
|
+
ComposeBackHandler(enabled = enabled, onBack = onBack)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@OptIn(InternalComposeUiApi::class)
|
|
78
|
+
@Composable
|
|
79
|
+
actual fun ProvideNavigationEventDispatcherOwner(navigator: Navigator, content: @Composable () -> Unit) {
|
|
80
|
+
val navigationEventDispatcherOwner = remember {
|
|
81
|
+
object : NavigationEventDispatcherOwner {
|
|
82
|
+
override val navigationEventDispatcher = NavigationEventDispatcher()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
AttachHostBackGesture(navigationEventDispatcherOwner.navigationEventDispatcher, navigator)
|
|
87
|
+
|
|
88
|
+
CompositionLocalProvider(
|
|
89
|
+
LocalCompatNavigationEventDispatcherOwner provides navigationEventDispatcherOwner,
|
|
90
|
+
content = content
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@Composable
|
|
95
|
+
actual fun getScreenHeight(): Dp {
|
|
96
|
+
return getScreenDimensions().height.dp
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
actual fun getOSVersion(): OSVersion = OSVersion.IOS(
|
|
100
|
+
major = UIDevice.currentDevice.systemVersion.substringBefore(".").toIntOrNull() ?: 0
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
@OptIn(ExperimentalForeignApi::class, ExperimentalComposeUiApi::class)
|
|
104
|
+
@Composable
|
|
105
|
+
actual fun LottieAnimation(
|
|
106
|
+
path: String,
|
|
107
|
+
tintColor: Color?,
|
|
108
|
+
bgColor: Color?,
|
|
109
|
+
placedAsOverlay: Boolean,
|
|
110
|
+
iterations: Int,
|
|
111
|
+
isPlaying: Boolean,
|
|
112
|
+
onEvent: ((String) -> Unit)?,
|
|
113
|
+
modifier: Modifier,
|
|
114
|
+
useCompose: Boolean
|
|
115
|
+
) {
|
|
116
|
+
if (useCompose) {
|
|
117
|
+
ComposeLottieAnimation(path, tintColor, bgColor, iterations, isPlaying, onEvent, modifier)
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
val loopCount = if (iterations == LottieIterateForever) -1.0 else iterations.toDouble()
|
|
122
|
+
|
|
123
|
+
var animation by remember { mutableStateOf<CompatibleAnimation?>(null) }
|
|
124
|
+
val animationView = remember { mutableStateOf<CompatibleAnimationView?>(null) }
|
|
125
|
+
|
|
126
|
+
LaunchedEffect(Unit) {
|
|
127
|
+
animation = CompatibleAnimation(name = "compose-resources/composeResources/vn.momo.compose.resources/".plus(path), subdirectory = null, NSBundle.mainBundle)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
val currentOnEvent by rememberUpdatedState(onEvent)
|
|
131
|
+
|
|
132
|
+
LaunchedEffect(isPlaying) {
|
|
133
|
+
currentOnEvent?.invoke(if (isPlaying) LottieEvent.Start else LottieEvent.Pause)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
LaunchedEffect(animationView.value, isPlaying) {
|
|
137
|
+
val view = animationView.value ?: return@LaunchedEffect
|
|
138
|
+
if (isPlaying) {
|
|
139
|
+
view.playWithCompletion(completion = { finished -> if (finished) currentOnEvent?.invoke(LottieEvent.Finish) })
|
|
140
|
+
} else {
|
|
141
|
+
view.pause()
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
when (val value = animation) {
|
|
146
|
+
null -> {
|
|
147
|
+
Box(modifier)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
else -> {
|
|
151
|
+
Box(modifier) {
|
|
152
|
+
UIKitView(
|
|
153
|
+
modifier = Modifier.fillMaxSize(),
|
|
154
|
+
properties = UIKitInteropProperties(placedAsOverlay = placedAsOverlay),
|
|
155
|
+
factory = {
|
|
156
|
+
CompatibleAnimationView(value).apply {
|
|
157
|
+
translatesAutoresizingMaskIntoConstraints = true
|
|
158
|
+
|
|
159
|
+
setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
|
|
160
|
+
|
|
161
|
+
setLoopAnimationCount(loopCount)
|
|
162
|
+
setAnimationSpeed(1.0)
|
|
163
|
+
|
|
164
|
+
if (tintColor != null) {
|
|
165
|
+
val uiColor = tintColor.toUIColor()
|
|
166
|
+
setColorValue(uiColor,
|
|
167
|
+
CompatibleAnimationKeypath("**.Fill 1.Color")
|
|
168
|
+
)
|
|
169
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill.Color"))
|
|
170
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Color"))
|
|
171
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke 1.Color"))
|
|
172
|
+
setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
animationView.value = this
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
update = { view ->
|
|
180
|
+
view.setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
|
|
181
|
+
view.setLoopAnimationCount(loopCount)
|
|
182
|
+
|
|
183
|
+
if (tintColor != null) {
|
|
184
|
+
val uiColor = tintColor.toUIColor()
|
|
185
|
+
|
|
186
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill 1.Color"))
|
|
187
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill.Color"))
|
|
188
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Color"))
|
|
189
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke 1.Color"))
|
|
190
|
+
view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
fun Color.toUIColor(): UIColor {
|
|
200
|
+
val argb = this.toArgb()
|
|
201
|
+
|
|
202
|
+
val a = ((argb shr 24) and 0xFF) / 255.0
|
|
203
|
+
val r = ((argb shr 16) and 0xFF) / 255.0
|
|
204
|
+
val g = ((argb shr 8) and 0xFF) / 255.0
|
|
205
|
+
val b = (argb and 0xFF) / 255.0
|
|
206
|
+
|
|
207
|
+
return UIColor(
|
|
208
|
+
red = r,
|
|
209
|
+
green = g,
|
|
210
|
+
blue = b,
|
|
211
|
+
alpha = a
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
actual fun NativePaint.setColor(color: Color){
|
|
216
|
+
this.color = color.toArgb()
|
|
217
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.DisposableEffect
|
|
5
|
+
import androidx.compose.runtime.getValue
|
|
6
|
+
import androidx.compose.runtime.mutableStateOf
|
|
7
|
+
import androidx.compose.runtime.remember
|
|
8
|
+
import androidx.compose.runtime.setValue
|
|
9
|
+
import androidx.compose.ui.uikit.LocalUIViewController
|
|
10
|
+
import androidx.compose.ui.unit.dp
|
|
11
|
+
import kotlinx.cinterop.BetaInteropApi
|
|
12
|
+
import kotlinx.cinterop.CFunction
|
|
13
|
+
import kotlinx.cinterop.COpaquePointer
|
|
14
|
+
import kotlinx.cinterop.ExperimentalForeignApi
|
|
15
|
+
import kotlinx.cinterop.interpretCPointer
|
|
16
|
+
import kotlinx.cinterop.interpretObjCPointer
|
|
17
|
+
import kotlinx.cinterop.interpretObjCPointerOrNull
|
|
18
|
+
import kotlinx.cinterop.invoke
|
|
19
|
+
import kotlinx.cinterop.objcPtr
|
|
20
|
+
import kotlinx.cinterop.reinterpret
|
|
21
|
+
import kotlinx.cinterop.readValue
|
|
22
|
+
import kotlinx.cinterop.useContents
|
|
23
|
+
import platform.CoreGraphics.CGRectZero
|
|
24
|
+
import platform.Foundation.NSArray
|
|
25
|
+
import platform.Foundation.NSSelectorFromString
|
|
26
|
+
import platform.Foundation.NSValue
|
|
27
|
+
import platform.Foundation.valueForKey
|
|
28
|
+
import platform.UIKit.CGRectValue
|
|
29
|
+
import platform.UIKit.UIView
|
|
30
|
+
import platform.UIKit.UIViewAutoresizingFlexibleHeight
|
|
31
|
+
import platform.UIKit.UIViewAutoresizingFlexibleWidth
|
|
32
|
+
import platform.darwin.NSObject
|
|
33
|
+
import platform.Foundation.NSClassFromString
|
|
34
|
+
import platform.posix.RTLD_DEFAULT
|
|
35
|
+
import platform.posix.dlsym
|
|
36
|
+
|
|
37
|
+
// The API is newer than the SDK Kotlin/Native binds, so it is reached through the runtime.
|
|
38
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
39
|
+
private val regionsOfKind = NSSelectorFromString("reservedRegionsOfKind:")
|
|
40
|
+
|
|
41
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
42
|
+
private val regionsOfKindOptions = NSSelectorFromString("reservedRegionsOfKind:options:")
|
|
43
|
+
|
|
44
|
+
// a hinge never goes away, so a positive answer is kept for every later container
|
|
45
|
+
private var isKnownFoldable = false
|
|
46
|
+
|
|
47
|
+
@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
|
|
48
|
+
private fun regionKind(name: String): Any? {
|
|
49
|
+
// a class object fails `as? NSObjectProtocol` (K/N checks it as an instance), so it is reinterpreted
|
|
50
|
+
val kindClass = NSClassFromString("UIViewReservedRegionKind")
|
|
51
|
+
?.let { interpretObjCPointer<NSObject>(it.objcPtr()) } ?: return null
|
|
52
|
+
return kindClass.performSelector(NSSelectorFromString(name))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// performSelector cannot pass the NSUInteger options, so objc_msgSend is called with the method's own signature.
|
|
56
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
57
|
+
private val msgSendRegionsOfKindOptions = dlsym(RTLD_DEFAULT, "objc_msgSend")
|
|
58
|
+
?.reinterpret<CFunction<(COpaquePointer?, COpaquePointer?, COpaquePointer?, ULong) -> COpaquePointer?>>()
|
|
59
|
+
|
|
60
|
+
// Apple's foldable check: only a device with a hinge reports a `.division` region, inactive while
|
|
61
|
+
// flat (UIViewReservedRegionQueryOptionsIncludeInactive) but still there. Screen size cannot tell it
|
|
62
|
+
// apart from a large iPhone in landscape or a narrowed window.
|
|
63
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
64
|
+
private fun UIView.hasDivisionRegion(): Boolean {
|
|
65
|
+
if (window == null || !respondsToSelector(regionsOfKindOptions)) return false
|
|
66
|
+
val msgSend = msgSendRegionsOfKindOptions ?: return false
|
|
67
|
+
val kind = regionKind("divisionRegionKind") as? NSObject ?: return false
|
|
68
|
+
val result = msgSend(
|
|
69
|
+
interpretCPointer(objcPtr()),
|
|
70
|
+
regionsOfKindOptions,
|
|
71
|
+
interpretCPointer(kind.objcPtr()),
|
|
72
|
+
1uL,
|
|
73
|
+
)
|
|
74
|
+
val regions = interpretObjCPointerOrNull<NSArray>(result?.rawValue ?: return false)
|
|
75
|
+
return (regions?.count ?: 0uL) > 0uL
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
79
|
+
private fun UIView.occlusionRegions(target: UIView): List<ReservedRegion> {
|
|
80
|
+
if (window == null || !respondsToSelector(regionsOfKind)) return emptyList()
|
|
81
|
+
val kind = regionKind("occlusionRegionKind") ?: return emptyList()
|
|
82
|
+
val regions = when (val result = performSelector(regionsOfKind, withObject = kind)) {
|
|
83
|
+
is List<*> -> result
|
|
84
|
+
is NSArray -> List(result.count.toInt()) { result.objectAtIndex(it.toULong()) }
|
|
85
|
+
else -> return emptyList()
|
|
86
|
+
}
|
|
87
|
+
return regions.mapNotNull { region ->
|
|
88
|
+
val frame = ((region as? NSObject)?.valueForKey("frame") as? NSValue)?.CGRectValue ?: return@mapNotNull null
|
|
89
|
+
convertRect(frame, toView = target).useContents {
|
|
90
|
+
ReservedRegion(origin.x.dp, origin.y.dp, size.width.dp, size.height.dp)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Invisible full-size probe: reading the regions in layoutSubviews makes UIKit run it again
|
|
96
|
+
// when they change, so nothing polls.
|
|
97
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
98
|
+
private class ReservedRegionsProbe(
|
|
99
|
+
private val onChange: (ReservedRegions) -> Unit,
|
|
100
|
+
) : UIView(frame = CGRectZero.readValue()) {
|
|
101
|
+
private var last: ReservedRegions? = null
|
|
102
|
+
|
|
103
|
+
init {
|
|
104
|
+
userInteractionEnabled = false
|
|
105
|
+
autoresizingMask = UIViewAutoresizingFlexibleWidth or UIViewAutoresizingFlexibleHeight
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
override fun layoutSubviews() {
|
|
109
|
+
super.layoutSubviews()
|
|
110
|
+
// re-read until found: the window may not report the hinge on the first pass
|
|
111
|
+
if (!isKnownFoldable) isKnownFoldable = hasDivisionRegion()
|
|
112
|
+
val regions = ReservedRegions(superview?.let { occlusionRegions(it) } ?: emptyList(), isKnownFoldable)
|
|
113
|
+
if (regions != last) {
|
|
114
|
+
last = regions
|
|
115
|
+
onChange(regions)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
override fun didMoveToWindow() {
|
|
120
|
+
super.didMoveToWindow()
|
|
121
|
+
setNeedsLayout()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@OptIn(ExperimentalForeignApi::class)
|
|
126
|
+
@Composable
|
|
127
|
+
internal actual fun rememberReservedRegions(): ReservedRegions {
|
|
128
|
+
if (!isPhoneIdiom()) return ReservedRegions()
|
|
129
|
+
val host = LocalUIViewController.current.view
|
|
130
|
+
var regions by remember { mutableStateOf(ReservedRegions(isFoldable = isKnownFoldable)) }
|
|
131
|
+
DisposableEffect(host) {
|
|
132
|
+
val probe = ReservedRegionsProbe { regions = it }
|
|
133
|
+
probe.setFrame(host.bounds)
|
|
134
|
+
host.insertSubview(probe, atIndex = 0)
|
|
135
|
+
onDispose { probe.removeFromSuperview() }
|
|
136
|
+
}
|
|
137
|
+
return regions
|
|
138
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[versions]
|
|
2
|
+
android-compileSdk = "37"
|
|
3
|
+
android-minSdk = "24"
|
|
4
|
+
android-targetSdk = "36"
|
|
5
|
+
ktor-version = "3.0.0-rc-1"
|
|
6
|
+
coroutines = "1.9.0"
|
|
7
|
+
kotlin = "2.3.10"
|
|
8
|
+
kSerialize = "1.7.1"
|
|
9
|
+
compose = "1.10.3"
|
|
10
|
+
navigation-multiplatform = "2.9.2"
|
|
11
|
+
coil3-multiplatform = "3.0.0-alpha10"
|
|
12
|
+
androidGradlePlugin = "9.2.1"
|
|
13
|
+
r8 = "8.9.35"
|
|
14
|
+
kotlinx-datetime = "0.7.1"
|
|
15
|
+
airbnb-lottie = "5.2.0"
|
|
16
|
+
compottie = "2.1.0"
|
|
17
|
+
androidx-activity = "1.9.1"
|
|
18
|
+
androidx-appcompat = "1.7.0"
|
|
19
|
+
material = "1.10.0"
|
|
20
|
+
vanniktechMavenPublish = "0.34.0"
|
|
21
|
+
kits = "0.167.1-duo.1"
|
|
22
|
+
nativemaxapi = "0.3.11"
|
|
23
|
+
gif-image = "0.1.2"
|
|
24
|
+
|
|
25
|
+
[libraries]
|
|
26
|
+
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor-version" }
|
|
27
|
+
ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor-version" }
|
|
28
|
+
ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktor-version" }
|
|
29
|
+
jetbrains-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" }
|
|
30
|
+
jetbrains-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" }
|
|
31
|
+
jetbrains-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" }
|
|
32
|
+
jetbrains-serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization", version.ref = "kSerialize" }
|
|
33
|
+
jetbrains-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kSerialize" }
|
|
34
|
+
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinx-datetime" }
|
|
35
|
+
compose-ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.ref = "compose" }
|
|
36
|
+
navigation-multiplatform = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-multiplatform" }
|
|
37
|
+
coil-multiplatform-core = { module = "io.coil-kt.coil3:coil-core", version.ref = "coil3-multiplatform" }
|
|
38
|
+
coil-multiplatform-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil3-multiplatform" }
|
|
39
|
+
coil-multiplatform-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil3-multiplatform" }
|
|
40
|
+
r8 = { module = "com.android.tools:r8", version.ref = "r8" }
|
|
41
|
+
airbnb-lottie = { group = "com.airbnb.android", name = "lottie-compose", version.ref = "airbnb-lottie" }
|
|
42
|
+
# Depend on compottie-core (not the `compottie` umbrella). The umbrella drags in the
|
|
43
|
+
# separate `keight` umbrella artifact, which collides with `keight-core` on the
|
|
44
|
+
# `findRoot__at__ScriptRuntime` symbol (duplicate symbol at the iOS `ld` link of
|
|
45
|
+
# shared.framework). compottie-core pulls only `keight-core` (which declares
|
|
46
|
+
# keight.js.JsAny, so the earlier unlinked-symbol error stays fixed too).
|
|
47
|
+
compottie = { module = "io.github.alexzhirkevich:compottie-core", version.ref = "compottie" }
|
|
48
|
+
native-max-api = { group = "vn.momo.maxapi", name = "NativeMaxApi", version.ref = "nativemaxapi" }
|
|
49
|
+
kits = { module = "vn.momo.kits:kits", version.ref = "kits" }
|
|
50
|
+
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
|
|
51
|
+
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
|
|
52
|
+
material = { module = "com.google.android.material:material", version.ref = "material" }
|
|
53
|
+
|
|
54
|
+
gif-image = { module = "vn.momo.kits:gif-image", version.ref = "gif-image" }
|
|
55
|
+
[plugins]
|
|
56
|
+
jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
|
57
|
+
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
|
58
|
+
jetbrains-kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
|
|
59
|
+
jetbrains-kotlin-cocoapods = { id = "org.jetbrains.kotlin.native.cocoapods", version.ref = "kotlin" }
|
|
60
|
+
jetbrains-kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
|
61
|
+
jetbrains-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
|
62
|
+
kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
|
63
|
+
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
|
|
64
|
+
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
|
|
65
|
+
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
|
|
66
|
+
vanniktech-mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "vanniktechMavenPublish" }
|
|
67
|
+
|
|
68
|
+
android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "androidGradlePlugin" }
|
|
Binary file
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#Thu Jul 31 17:05:40 ICT 2025
|
|
2
|
+
distributionBase=GRADLE_USER_HOME
|
|
3
|
+
distributionPath=wrapper/dists
|
|
4
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
|
|
5
|
+
networkTimeout=10000
|
|
6
|
+
validateDistributionUrl=true
|
|
7
|
+
zipStoreBase=GRADLE_USER_HOME
|
|
8
|
+
zipStorePath=wrapper/dists
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#Kotlin
|
|
2
|
+
kotlin.code.style=official
|
|
3
|
+
kotlin.daemon.jvmargs=-Xmx6144M
|
|
4
|
+
|
|
5
|
+
#Gradle
|
|
6
|
+
org.gradle.jvmargs=-Xmx8192M -Dfile.encoding=UTF-8
|
|
7
|
+
org.gradle.configuration-cache=false
|
|
8
|
+
org.gradle.caching=true
|
|
9
|
+
|
|
10
|
+
#Android
|
|
11
|
+
android.nonTransitiveRClass=true
|
|
12
|
+
android.useAndroidX=true
|
|
13
|
+
|
|
14
|
+
#KMP
|
|
15
|
+
kotlin.apple.xcodeCompatibility.nowarn=true
|
|
16
|
+
|
|
17
|
+
# Publishing
|
|
18
|
+
name="ComposeKits"
|
|
19
|
+
group=vn.momo.kits
|
|
20
|
+
artifact.id=kits
|
|
21
|
+
version=0.300.5
|
|
22
|
+
|
|
23
|
+
repo=GitLab
|
|
24
|
+
url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
|
|
25
|
+
gitlab.user=
|
|
26
|
+
gitlab.password=
|