@momo-kits/native-kits 0.164.1-beta.7-debug → 0.164.1-beta.7

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.
Files changed (134) hide show
  1. package/package.json +1 -1
  2. package/build.gradle.kts +0 -11
  3. package/compose/build.gradle.kts +0 -190
  4. package/compose/build.gradle.kts.backup +0 -190
  5. package/compose/compose.podspec +0 -47
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  7. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  8. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -150
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -106
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -826
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -23
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -134
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -214
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -216
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -259
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -182
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -328
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -97
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -217
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -470
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -131
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -203
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -175
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -263
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -52
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -38
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -39
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -299
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -129
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -103
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -190
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -406
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -612
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -164
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -156
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -225
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -320
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -81
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -309
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -34
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -360
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -69
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -105
  121. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  122. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -118
  123. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  124. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  125. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -220
  126. package/gradle/libs.versions.toml +0 -69
  127. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  128. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  129. package/gradle.properties +0 -26
  130. package/gradlew +0 -252
  131. package/gradlew.bat +0 -94
  132. package/ios-demo/README.md +0 -120
  133. package/local.properties +0 -8
  134. package/settings.gradle.kts +0 -64
@@ -1,55 +0,0 @@
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
- }
@@ -1,15 +0,0 @@
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
- }
@@ -1,105 +0,0 @@
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
- }
@@ -1,40 +0,0 @@
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
- }
@@ -1,118 +0,0 @@
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.NavigationEvent
7
- import androidx.navigationevent.NavigationEventDispatcher
8
- import androidx.navigationevent.NavigationEventInput
9
- import kotlinx.cinterop.ExperimentalForeignApi
10
- import platform.Foundation.NSThread
11
- import platform.darwin.dispatch_async
12
- import platform.darwin.dispatch_get_main_queue
13
-
14
- /**
15
- * Kit end of the host's edge-pan recogniser.
16
- *
17
- * iOS keeps exactly one back-gesture recogniser and it belongs to the host app — the kit never
18
- * installs its own, so the `.failed -> completed` conflict between two competing recognisers is
19
- * unreachable by construction. The host replays its drag here; the events are fed into the
20
- * `NavigationEventDispatcher` that [NavigationContainer] provides, which drives NavHost's
21
- * `PredictiveBackHandler` and therefore `SeekableTransitionState.seekTo`. Parallax, scrim and edge
22
- * shadow are children of that same transition, so they follow the finger for free.
23
- *
24
- * Only primitives cross the Swift boundary: `androidx.navigationevent` is a private transitive
25
- * dependency and is absent from the generated framework header.
26
- *
27
- * Call every method from the main thread; anything else is re-posted to the main queue.
28
- */
29
- object HostBackGestureBridge {
30
- private val attachedInputs = mutableListOf<HostNavigationEventInput>()
31
- private var gestureInput: HostNavigationEventInput? = null
32
-
33
- /**
34
- * Whether the top-most mounted container has an enabled back handler, i.e. the authoritative
35
- * answer to "will Compose consume this back?". `false` means no container is mounted, or the
36
- * mounted one deliberately opts out (kill switch, overlay showing, custom back handler), and
37
- * the host should fall back to its own navigation.
38
- */
39
- val hasEnabledHandlers: Boolean
40
- get() = attachedInputs.lastOrNull()?.hasEnabledHandlers == true
41
-
42
- /** Begins a drag. Pairs with exactly one [completed] or [cancelled]. */
43
- fun started() = onMain {
44
- val input = attachedInputs.lastOrNull() ?: return@onMain
45
- gestureInput = input
46
- input.backStarted()
47
- }
48
-
49
- /** Drag progress in `0f..1f` — the fraction of the screen width travelled. */
50
- fun progressed(progress: Float) = onMain {
51
- gestureInput?.backProgressed(progress.coerceIn(0f, 1f))
52
- }
53
-
54
- /** Released past the commit threshold: the screen pops. */
55
- fun completed() = onMain {
56
- gestureInput?.backCompleted()
57
- gestureInput = null
58
- }
59
-
60
- /** Released below the commit threshold: the screen springs back. */
61
- fun cancelled() = onMain {
62
- gestureInput?.backCancelled()
63
- gestureInput = null
64
- }
65
-
66
- internal fun attach(input: HostNavigationEventInput) {
67
- attachedInputs += input
68
- }
69
-
70
- internal fun detach(input: HostNavigationEventInput) {
71
- attachedInputs -= input
72
- // A container unmounted mid-drag must not hand its pending terminal event to whichever
73
- // container is on top now: NavigationEventInput fabricates a non-predictive start for a
74
- // completed/cancelled it never saw begin, which would pop a screen out of nowhere.
75
- if (gestureInput === input) gestureInput = null
76
- }
77
- }
78
-
79
- /** Wires one [NavigationContainer]'s dispatcher to [HostBackGestureBridge] while it is composed. */
80
- @Composable
81
- internal fun AttachHostBackGesture(dispatcher: NavigationEventDispatcher) {
82
- val input = remember(dispatcher) { HostNavigationEventInput() }
83
-
84
- DisposableEffect(dispatcher, input) {
85
- dispatcher.addInput(input)
86
- HostBackGestureBridge.attach(input)
87
- onDispose {
88
- HostBackGestureBridge.detach(input)
89
- dispatcher.removeInput(input)
90
- }
91
- }
92
- }
93
-
94
- internal class HostNavigationEventInput : NavigationEventInput() {
95
- var hasEnabledHandlers: Boolean = false
96
- private set
97
-
98
- override fun onHasEnabledHandlersChanged(hasEnabledHandlers: Boolean) {
99
- this.hasEnabledHandlers = hasEnabledHandlers
100
- }
101
-
102
- // Touch coordinates are not forwarded — the stack transition is seeked by progress alone, and
103
- // leaving them out keeps the bridge's Swift-facing signatures primitive.
104
- fun backStarted() = dispatchOnBackStarted(NavigationEvent(swipeEdge = NavigationEvent.EDGE_LEFT))
105
-
106
- fun backProgressed(progress: Float) = dispatchOnBackProgressed(
107
- NavigationEvent(swipeEdge = NavigationEvent.EDGE_LEFT, progress = progress)
108
- )
109
-
110
- fun backCancelled() = dispatchOnBackCancelled()
111
-
112
- fun backCompleted() = dispatchOnBackCompleted()
113
- }
114
-
115
- @OptIn(ExperimentalForeignApi::class)
116
- private fun onMain(block: () -> Unit) {
117
- if (NSThread.isMainThread()) block() else dispatch_async(dispatch_get_main_queue()) { block() }
118
- }
@@ -1,32 +0,0 @@
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
- }
@@ -1,66 +0,0 @@
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
- }
@@ -1,220 +0,0 @@
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.AttachHostBackGesture
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
- // Detached on purpose: passing the scene's owner through would arm Compose's own
79
- // UIKitBackGestureRecognizer alongside the host's, and UIKit settles that conflict by driving
80
- // one to .failed, which UIKitNavigationEventInput turns into a fabricated completed back.
81
- // Enabled on purpose: every NavigationEventDispatcher.dispatchOn* early-returns while
82
- // isEnabled is false, which would mute the host-driven seek as well.
83
- val navigationEventDispatcherOwner = remember {
84
- object : NavigationEventDispatcherOwner {
85
- override val navigationEventDispatcher = NavigationEventDispatcher()
86
- }
87
- }
88
-
89
- AttachHostBackGesture(navigationEventDispatcherOwner.navigationEventDispatcher)
90
-
91
- CompositionLocalProvider(
92
- LocalCompatNavigationEventDispatcherOwner provides navigationEventDispatcherOwner,
93
- content = content
94
- )
95
- }
96
-
97
- @Composable
98
- actual fun getScreenHeight(): Dp {
99
- return getScreenDimensions().height.dp
100
- }
101
-
102
- actual fun getOSVersion(): OSVersion = OSVersion.IOS(
103
- major = UIDevice.currentDevice.systemVersion.substringBefore(".").toIntOrNull() ?: 0
104
- )
105
-
106
- @OptIn(ExperimentalForeignApi::class, ExperimentalComposeUiApi::class)
107
- @Composable
108
- actual fun LottieAnimation(
109
- path: String,
110
- tintColor: Color?,
111
- bgColor: Color?,
112
- placedAsOverlay: Boolean,
113
- iterations: Int,
114
- isPlaying: Boolean,
115
- onEvent: ((String) -> Unit)?,
116
- modifier: Modifier,
117
- useCompose: Boolean
118
- ) {
119
- if (useCompose) {
120
- ComposeLottieAnimation(path, tintColor, bgColor, iterations, isPlaying, onEvent, modifier)
121
- return
122
- }
123
-
124
- val loopCount = if (iterations == LottieIterateForever) -1.0 else iterations.toDouble()
125
-
126
- var animation by remember { mutableStateOf<CompatibleAnimation?>(null) }
127
- val animationView = remember { mutableStateOf<CompatibleAnimationView?>(null) }
128
-
129
- LaunchedEffect(Unit) {
130
- animation = CompatibleAnimation(name = "compose-resources/composeResources/vn.momo.compose.resources/".plus(path), subdirectory = null, NSBundle.mainBundle)
131
- }
132
-
133
- val currentOnEvent by rememberUpdatedState(onEvent)
134
-
135
- LaunchedEffect(isPlaying) {
136
- currentOnEvent?.invoke(if (isPlaying) LottieEvent.Start else LottieEvent.Pause)
137
- }
138
-
139
- LaunchedEffect(animationView.value, isPlaying) {
140
- val view = animationView.value ?: return@LaunchedEffect
141
- if (isPlaying) {
142
- view.playWithCompletion(completion = { finished -> if (finished) currentOnEvent?.invoke(LottieEvent.Finish) })
143
- } else {
144
- view.pause()
145
- }
146
- }
147
-
148
- when (val value = animation) {
149
- null -> {
150
- Box(modifier)
151
- }
152
-
153
- else -> {
154
- Box(modifier) {
155
- UIKitView(
156
- modifier = Modifier.fillMaxSize(),
157
- properties = UIKitInteropProperties(placedAsOverlay = placedAsOverlay),
158
- factory = {
159
- CompatibleAnimationView(value).apply {
160
- translatesAutoresizingMaskIntoConstraints = true
161
-
162
- setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
163
-
164
- setLoopAnimationCount(loopCount)
165
- setAnimationSpeed(1.0)
166
-
167
- if (tintColor != null) {
168
- val uiColor = tintColor.toUIColor()
169
- setColorValue(uiColor,
170
- CompatibleAnimationKeypath("**.Fill 1.Color")
171
- )
172
- setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill.Color"))
173
- setColorValue(uiColor, CompatibleAnimationKeypath("**.Color"))
174
- setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke 1.Color"))
175
- setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
176
- }
177
-
178
- animationView.value = this
179
- }
180
- },
181
-
182
- update = { view ->
183
- view.setBackgroundColor(bgColor?.toUIColor() ?: UIColor.clearColor)
184
- view.setLoopAnimationCount(loopCount)
185
-
186
- if (tintColor != null) {
187
- val uiColor = tintColor.toUIColor()
188
-
189
- view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill 1.Color"))
190
- view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Fill.Color"))
191
- view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Color"))
192
- view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke 1.Color"))
193
- view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
194
- }
195
- }
196
- )
197
- }
198
- }
199
- }
200
- }
201
-
202
- fun Color.toUIColor(): UIColor {
203
- val argb = this.toArgb()
204
-
205
- val a = ((argb shr 24) and 0xFF) / 255.0
206
- val r = ((argb shr 16) and 0xFF) / 255.0
207
- val g = ((argb shr 8) and 0xFF) / 255.0
208
- val b = (argb and 0xFF) / 255.0
209
-
210
- return UIColor(
211
- red = r,
212
- green = g,
213
- blue = b,
214
- alpha = a
215
- )
216
- }
217
-
218
- actual fun NativePaint.setColor(color: Color){
219
- this.color = color.toArgb()
220
- }