@momo-kits/native-kits 0.167.1-duo.17-debug → 0.167.1-duo.18

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 (154) hide show
  1. package/CLAUDE.md +1 -0
  2. package/ios/Layout/ScreenLayout.swift +49 -3
  3. package/ios/Navigation/Component/Header.swift +48 -11
  4. package/ios/Navigation/Component/HeaderRight.swift +34 -28
  5. package/ios/Navigation/Component/SideBar.swift +15 -8
  6. package/ios/Navigation/StackScreen.swift +13 -12
  7. package/package.json +1 -1
  8. package/build.gradle.kts +0 -11
  9. package/compose/build.gradle.kts +0 -204
  10. package/compose/build.gradle.kts.backup +0 -204
  11. package/compose/compose.podspec +0 -47
  12. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  13. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  14. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  15. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  16. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -153
  17. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +0 -6
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -916
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -81
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -357
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -115
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -86
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -478
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -265
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -235
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -265
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -361
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -108
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -308
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -330
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -207
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -92
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -560
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -86
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -501
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -236
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -180
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -20
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -194
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -283
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -260
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -338
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -137
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -708
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -218
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -231
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +0 -98
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +0 -312
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -408
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -103
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -106
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -366
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -39
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -185
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -133
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -74
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +0 -13
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  137. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  138. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  139. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
  140. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -78
  141. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  142. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  143. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  144. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  145. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -217
  146. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +0 -94
  147. package/gradle/libs.versions.toml +0 -69
  148. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  149. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  150. package/gradle.properties +0 -26
  151. package/gradlew +0 -252
  152. package/gradlew.bat +0 -94
  153. package/ios-demo/README.md +0 -120
  154. package/settings.gradle.kts +0 -64
@@ -1,542 +0,0 @@
1
- package vn.momo.kits.components
2
-
3
- import androidx.compose.animation.core.AnimationState
4
- import androidx.compose.animation.core.VectorConverter
5
- import androidx.compose.animation.core.animateTo
6
- import androidx.compose.animation.core.spring
7
- import androidx.compose.foundation.OverscrollEffect
8
- import androidx.compose.material.ExperimentalMaterialApi
9
- import androidx.compose.runtime.Stable
10
- import androidx.compose.runtime.State
11
- import androidx.compose.runtime.getValue
12
- import androidx.compose.runtime.mutableStateOf
13
- import androidx.compose.runtime.setValue
14
- import androidx.compose.ui.Modifier
15
- import androidx.compose.ui.geometry.Offset
16
- import androidx.compose.ui.geometry.Rect
17
- import androidx.compose.ui.geometry.Size
18
- import androidx.compose.ui.geometry.toRect
19
- import androidx.compose.ui.graphics.drawscope.ContentDrawScope
20
- import androidx.compose.ui.graphics.drawscope.clipRect
21
- import androidx.compose.ui.input.nestedscroll.NestedScrollSource
22
- import androidx.compose.ui.input.pointer.PointerEvent
23
- import androidx.compose.ui.input.pointer.PointerEventPass
24
- import androidx.compose.ui.input.pointer.PointerEventType
25
- import androidx.compose.ui.layout.Measurable
26
- import androidx.compose.ui.layout.MeasureResult
27
- import androidx.compose.ui.layout.MeasureScope
28
- import androidx.compose.ui.node.DelegatableNode
29
- import androidx.compose.ui.node.DrawModifierNode
30
- import androidx.compose.ui.node.LayoutAwareModifierNode
31
- import androidx.compose.ui.node.LayoutModifierNode
32
- import androidx.compose.ui.node.PointerInputModifierNode
33
- import androidx.compose.ui.unit.Constraints
34
- import androidx.compose.ui.unit.Density
35
- import androidx.compose.ui.unit.Dp
36
- import androidx.compose.ui.unit.IntOffset
37
- import androidx.compose.ui.unit.IntSize
38
- import androidx.compose.ui.unit.Velocity
39
- import androidx.compose.ui.unit.dp
40
- import androidx.compose.ui.unit.round
41
- import androidx.compose.ui.unit.toOffset
42
- import androidx.compose.ui.unit.toSize
43
- import kotlinx.coroutines.CoroutineScope
44
- import kotlinx.coroutines.cancel
45
- import kotlinx.coroutines.currentCoroutineContext
46
- import kotlinx.coroutines.isActive
47
- import kotlin.math.abs
48
- import kotlin.math.sign
49
-
50
- private enum class CupertinoScrollSource {
51
- DRAG, FLING
52
- }
53
-
54
- private enum class CupertinoOverscrollDirection {
55
- UNKNOWN, VERTICAL, HORIZONTAL
56
- }
57
-
58
- private enum class CupertinoSpringAnimationReason {
59
- FLING_FROM_OVERSCROLL, POSSIBLE_SPRING_IN_THE_END
60
- }
61
-
62
-
63
- private data class CupertinoOverscrollAvailableDelta(
64
-
65
- val availableDelta: Float,
66
-
67
-
68
- val newOverscrollValue: Float
69
- )
70
-
71
- data class PullToRefreshCustomState(
72
- val refreshingState: State<Boolean>,
73
- val onRefresh: () -> Unit,
74
- val threadHold: Dp = 140.dp,
75
- val refreshOffset: Dp = 100.dp,
76
- val sendHaptic: (() -> Unit)? = null,
77
- ) {
78
- val position = mutableStateOf(0f)
79
-
80
- fun updatePercentage(percentage: Float) {
81
- position.value = percentage.coerceIn(0f, 1f)
82
- }
83
- }
84
-
85
- /**
86
- * CupertinoOverscrollEffect
87
- *
88
- * @param density to be taken into consideration during computations;
89
- * Cupertino formulas use DPs, and scroll machinery uses raw values.
90
- *
91
- * @param applyClip Some consumers of overscroll effect apply clip by themselves and some don't,
92
- * thus this flag is needed to update our modifier chain and make the clipping correct in every case while avoiding redundancy
93
- */
94
- internal class CupertinoOverscrollEffect(
95
- val pullRefreshState: PullToRefreshCustomState? = null,
96
- private val density: Float,
97
- val applyClip: Boolean
98
- ) : OverscrollEffect {
99
- /*
100
- * Direction of scrolling for this overscroll effect, derived from arguments during
101
- * [applyToScroll] calls. Technically this effect supports both dimensions, but current API requires
102
- * that different stages of animations spawned by this effect for both dimensions
103
- * end at the same time, which is not the case:
104
- * Spring->Fling->Spring, Fling->Spring, Spring->Fling effects can have different timing per dimension
105
- * (see Notes of https://github.com/JetBrains/compose-multiplatform-core/pull/609),
106
- * which is not possible to express without changing API. Hence, this effect will be fixed to latest
107
- * received delta.
108
- */
109
- private var direction: CupertinoOverscrollDirection = CupertinoOverscrollDirection.UNKNOWN
110
-
111
- /*
112
- * Size of container is taking into consideration when computing rubber banding
113
- */
114
- private var scrollSize: Size = Size.Zero
115
-
116
- /*
117
- * Current offset in overscroll area
118
- * Negative for bottom-right
119
- * Positive for top-left
120
- * Zero if within the scrollable range
121
- * It will be mapped to the actual visible offset using the rubber banding rule inside
122
- * [Modifier.offset] within [effectModifier]
123
- */
124
- private var overscrollOffsetState = mutableStateOf(Offset.Zero)
125
- private var overscrollOffset: Offset
126
- get() = overscrollOffsetState.value
127
- set(value) {
128
- overscrollOffsetState.value = value
129
- drawCallScheduledByOffsetChange = true
130
- }
131
- private var drawCallScheduledByOffsetChange = true
132
-
133
- private var lastFlingUnconsumedDelta: Offset = Offset.Zero
134
- private val visibleOverscrollOffset: IntOffset
135
- get() = overscrollOffsetState.value.rubberBanded().round()
136
-
137
- override val isInProgress: Boolean
138
- get() =
139
- // If visible overscroll offset has at least one pixel
140
- // this effect is considered to be in progress
141
- visibleOverscrollOffset.toOffset().getDistance() > 0.5f
142
-
143
- @OptIn(ExperimentalMaterialApi::class)
144
- private val overscrollNode = CupertinoOverscrollNode(
145
- pullRefreshState = pullRefreshState,
146
- offset = { visibleOverscrollOffset },
147
- onNodeRemeasured = { scrollSize = it.toSize() },
148
- onDraw = ::onDraw,
149
- applyClip = applyClip
150
- )
151
- override val node: DelegatableNode get() = overscrollNode
152
-
153
- private fun onDraw() {
154
- // Fix an issue where scrolling was canceled but the overscroll effect was not completed.
155
- // Reset the overscroll effect when no ongoing animation or interaction is applied.
156
- if (!drawCallScheduledByOffsetChange && isInProgress && overscrollNode.pointersDown == 0) {
157
- overscrollOffsetState.value = Offset.Zero
158
- }
159
-
160
- drawCallScheduledByOffsetChange = false
161
- }
162
-
163
- private fun NestedScrollSource.toCupertinoScrollSource(): CupertinoScrollSource? =
164
- when (this) {
165
- NestedScrollSource.UserInput -> CupertinoScrollSource.DRAG
166
- NestedScrollSource.SideEffect -> CupertinoScrollSource.FLING
167
- else -> null
168
- }
169
-
170
- /*
171
- * Takes input scroll delta, current overscroll value, and scroll source, return [CupertinoOverscrollAvailableDelta]
172
- */
173
- @Stable
174
- private fun availableDelta(
175
- delta: Float,
176
- overscroll: Float,
177
- source: CupertinoScrollSource
178
- ): CupertinoOverscrollAvailableDelta {
179
- // if source is fling:
180
- // 1. no delta will be consumed
181
- // 2. overscroll will stay the same
182
- if (source == CupertinoScrollSource.FLING) {
183
- return CupertinoOverscrollAvailableDelta(delta, overscroll)
184
- }
185
-
186
- val newOverscroll = overscroll + delta
187
-
188
- return if (delta >= 0f && overscroll <= 0f) {
189
- if (newOverscroll > 0f) {
190
- CupertinoOverscrollAvailableDelta(newOverscroll, 0f)
191
- } else {
192
- CupertinoOverscrollAvailableDelta(0f, newOverscroll)
193
- }
194
- } else if (delta <= 0f && overscroll >= 0f) {
195
- if (newOverscroll < 0f) {
196
- CupertinoOverscrollAvailableDelta(newOverscroll, 0f)
197
- } else {
198
- CupertinoOverscrollAvailableDelta(0f, newOverscroll)
199
- }
200
- } else {
201
- CupertinoOverscrollAvailableDelta(0f, newOverscroll)
202
- }
203
- }
204
-
205
- /*
206
- * Returns the amount of scroll delta available after user performed scroll inside overscroll area
207
- * It will update [overscroll] resulting in visual change because of [Modifier.offset] depending on it
208
- */
209
- private fun availableDelta(delta: Offset, source: CupertinoScrollSource): Offset {
210
- val (x, overscrollX) = availableDelta(delta.x, overscrollOffset.x, source)
211
- val (y, overscrollY) = availableDelta(delta.y, overscrollOffset.y, source)
212
- overscrollOffset = Offset(overscrollX, overscrollY)
213
-
214
- return Offset(x, y)
215
- }
216
-
217
- /*
218
- * Semantics of this method match the [OverscrollEffect.applyToScroll] one,
219
- * The only difference is NestedScrollSource being remapped to CupertinoScrollSource to narrow
220
- * processed states invariant
221
- */
222
- private fun applyToScroll(
223
- delta: Offset,
224
- source: CupertinoScrollSource,
225
- performScroll: (Offset) -> Offset
226
- ): Offset {
227
- // Calculate how much delta is available after being consumed by scrolling inside overscroll area
228
- val deltaLeftForPerformScroll = availableDelta(delta, source)
229
-
230
- // Then pass remaining delta to scroll closure
231
- val deltaConsumedByPerformScroll = performScroll(deltaLeftForPerformScroll)
232
-
233
- // Delta which is left after `performScroll` was invoked with availableDelta
234
- val unconsumedDelta = deltaLeftForPerformScroll - deltaConsumedByPerformScroll
235
-
236
- return when (source) {
237
- CupertinoScrollSource.DRAG -> {
238
- // [unconsumedDelta] is going into overscroll again in case a user drags and hits the
239
- // overscroll->content->overscroll or content->overscroll scenario within single frame
240
- overscrollOffset += unconsumedDelta
241
- lastFlingUnconsumedDelta = Offset.Zero
242
- delta - unconsumedDelta
243
- }
244
-
245
- CupertinoScrollSource.FLING -> {
246
- // If unconsumedDelta is not Zero, [CupertinoOverscrollEffect] will cancel fling and
247
- // start spring animation instead
248
- lastFlingUnconsumedDelta = unconsumedDelta
249
- delta - unconsumedDelta
250
- }
251
- }
252
- }
253
-
254
- override fun applyToScroll(
255
- delta: Offset,
256
- source: NestedScrollSource,
257
- performScroll: (Offset) -> Offset
258
- ): Offset {
259
- springAnimationScope?.cancel()
260
- springAnimationScope = null
261
-
262
- direction = direction.combinedWith(delta.toCupertinoOverscrollDirection())
263
-
264
- return source.toCupertinoScrollSource()?.let {
265
- applyToScroll(delta, it, performScroll)
266
- } ?: performScroll(delta)
267
- }
268
-
269
- override suspend fun applyToFling(
270
- velocity: Velocity,
271
- performFling: suspend (Velocity) -> Velocity
272
- ) {
273
- val availableFlingVelocity = playInitialSpringAnimationIfNeeded(velocity)
274
- val velocityConsumedByFling = performFling(availableFlingVelocity)
275
- val postFlingVelocity = availableFlingVelocity - velocityConsumedByFling
276
-
277
- val unconsumedDelta = lastFlingUnconsumedDelta.toFloat()
278
- if (unconsumedDelta == 0f && overscrollOffset == Offset.Zero) {
279
- return
280
- }
281
- applyPullToRefresh()
282
-
283
- playSpringAnimation(
284
- unconsumedDelta,
285
- postFlingVelocity.toFloat(),
286
- CupertinoSpringAnimationReason.POSSIBLE_SPRING_IN_THE_END
287
- )
288
- }
289
-
290
- private fun applyPullToRefresh() {
291
- val (isRefresh, refresh, threshHold, _, _) = pullRefreshState ?: return
292
- val overscrollY = overscrollOffset.y
293
- if (isRefresh.value || overscrollY < threshHold.value * density) return
294
- refresh.invoke()
295
- }
296
-
297
- private fun Offset.toCupertinoOverscrollDirection(): CupertinoOverscrollDirection {
298
- val hasXPart = abs(x) > 0f
299
- val hasYPart = abs(y) > 0f
300
-
301
- return if (hasXPart xor hasYPart) {
302
- if (hasXPart) {
303
- CupertinoOverscrollDirection.HORIZONTAL
304
- } else {
305
- // hasYPart != hasXPart and hasXPart is false
306
- CupertinoOverscrollDirection.VERTICAL
307
- }
308
- } else {
309
- // hasXPart and hasYPart are equal
310
- CupertinoOverscrollDirection.UNKNOWN
311
- }
312
- }
313
-
314
- private fun CupertinoOverscrollDirection.combinedWith(other: CupertinoOverscrollDirection): CupertinoOverscrollDirection =
315
- when (this) {
316
- CupertinoOverscrollDirection.UNKNOWN -> when (other) {
317
- CupertinoOverscrollDirection.UNKNOWN -> CupertinoOverscrollDirection.UNKNOWN
318
- CupertinoOverscrollDirection.VERTICAL -> CupertinoOverscrollDirection.VERTICAL
319
- CupertinoOverscrollDirection.HORIZONTAL -> CupertinoOverscrollDirection.HORIZONTAL
320
- }
321
-
322
- CupertinoOverscrollDirection.VERTICAL -> when (other) {
323
- CupertinoOverscrollDirection.UNKNOWN, CupertinoOverscrollDirection.VERTICAL -> CupertinoOverscrollDirection.VERTICAL
324
- CupertinoOverscrollDirection.HORIZONTAL -> CupertinoOverscrollDirection.HORIZONTAL
325
- }
326
-
327
- CupertinoOverscrollDirection.HORIZONTAL -> when (other) {
328
- CupertinoOverscrollDirection.UNKNOWN, CupertinoOverscrollDirection.HORIZONTAL -> CupertinoOverscrollDirection.HORIZONTAL
329
- CupertinoOverscrollDirection.VERTICAL -> CupertinoOverscrollDirection.VERTICAL
330
- }
331
- }
332
-
333
- private fun Velocity.toFloat(): Float =
334
- toOffset().toFloat()
335
-
336
- private fun Float.toVelocity(): Velocity =
337
- toOffset().toVelocity()
338
-
339
- private fun Offset.toFloat(): Float =
340
- when (direction) {
341
- CupertinoOverscrollDirection.UNKNOWN -> 0f
342
- CupertinoOverscrollDirection.VERTICAL -> y
343
- CupertinoOverscrollDirection.HORIZONTAL -> x
344
- }
345
-
346
- private fun Float.toOffset(): Offset =
347
- when (direction) {
348
- CupertinoOverscrollDirection.UNKNOWN -> Offset.Zero
349
- CupertinoOverscrollDirection.VERTICAL -> Offset(0f, this)
350
- CupertinoOverscrollDirection.HORIZONTAL -> Offset(this, 0f)
351
- }
352
-
353
- private suspend fun playInitialSpringAnimationIfNeeded(initialVelocity: Velocity): Velocity {
354
- val velocity = initialVelocity.toFloat()
355
- val overscroll = overscrollOffset.toFloat()
356
-
357
- return if ((velocity <= 0f && overscroll > 0f) || (velocity >= 0f && overscroll < 0f)) {
358
- playSpringAnimation(
359
- unconsumedDelta = 0f,
360
- velocity,
361
- CupertinoSpringAnimationReason.FLING_FROM_OVERSCROLL
362
- ).toVelocity()
363
- } else {
364
- initialVelocity
365
- }
366
- }
367
-
368
- private var springAnimationScope: CoroutineScope? = null
369
-
370
- private suspend fun playSpringAnimation(
371
- unconsumedDelta: Float,
372
- initialVelocity: Float,
373
- reason: CupertinoSpringAnimationReason
374
- ): Float {
375
- val initialValue = overscrollOffset.toFloat() + unconsumedDelta
376
- val initialSign = sign(initialValue)
377
- var currentVelocity = initialVelocity
378
-
379
- // All input values are divided by density so all internal calculations are performed as if
380
- // they operated on DPs. Callback value is then scaled back to raw pixels.
381
- val visibilityThreshold = 0.5f / density
382
-
383
- val spec = when (reason) {
384
- CupertinoSpringAnimationReason.FLING_FROM_OVERSCROLL -> {
385
- spring(
386
- stiffness = 300f,
387
- visibilityThreshold = visibilityThreshold
388
- )
389
- }
390
-
391
- CupertinoSpringAnimationReason.POSSIBLE_SPRING_IN_THE_END -> {
392
- spring(
393
- stiffness = 120f,
394
- visibilityThreshold = visibilityThreshold
395
- )
396
- }
397
- }
398
-
399
- springAnimationScope?.cancel()
400
- springAnimationScope = CoroutineScope(currentCoroutineContext())
401
- springAnimationScope?.run {
402
- AnimationState(
403
- Float.VectorConverter,
404
- initialValue / density,
405
- initialVelocity / density
406
- ).animateTo(
407
- targetValue = 0f,
408
- animationSpec = spec
409
- ) {
410
- overscrollOffset = pullRefreshState?.let { (refreshing, _, _, refreshOffset) ->
411
- if (!refreshing.value) return@let null
412
- value.coerceAtLeast(refreshOffset.value * density).toOffset()
413
- } ?: (value * density).toOffset()
414
- currentVelocity = velocity * density
415
-
416
- // If it was flung from overscroll, cancel animation and return velocity
417
- if (reason == CupertinoSpringAnimationReason.FLING_FROM_OVERSCROLL &&
418
- initialSign != 0f &&
419
- sign(value) != initialSign
420
- ) {
421
- this.cancelAnimation()
422
- }
423
- }
424
- springAnimationScope = null
425
- }
426
-
427
- if (currentCoroutineContext().isActive) {
428
- // The spring is critically damped, so in case spring-fling-spring sequence is slightly
429
- // offset and velocity is of the opposite sign, it will end up with no animation
430
- overscrollOffset = Offset.Zero
431
- }
432
-
433
- if (reason == CupertinoSpringAnimationReason.POSSIBLE_SPRING_IN_THE_END) {
434
- currentVelocity = 0f
435
- }
436
-
437
- return currentVelocity
438
- }
439
-
440
- private fun Offset.rubberBanded(): Offset {
441
- if (scrollSize.width == 0f || scrollSize.height == 0f) {
442
- return Offset.Zero
443
- }
444
-
445
- val dpOffset = this / density
446
- val dpSize = scrollSize / density
447
-
448
- return Offset(
449
- rubberBandedValue(dpOffset.x, dpSize.width),
450
- rubberBandedValue(dpOffset.y, dpSize.height)
451
- ) * density
452
- }
453
-
454
- /*
455
- * Maps raw delta offset [value] on an axis within scroll container with [dimension]
456
- * to actual visible offset
457
- */
458
- private fun rubberBandedValue(value: Float, dimension: Float) =
459
- sign(value) * (1f - (1f / (abs(value) * RUBBER_BAND_COEFFICIENT / dimension + 1f))) * dimension
460
-
461
- companion object Companion {
462
- private const val RUBBER_BAND_COEFFICIENT = 0.55f
463
- }
464
- }
465
-
466
- private class CupertinoOverscrollNode @OptIn(ExperimentalMaterialApi::class) constructor(
467
- val pullRefreshState: PullToRefreshCustomState?,
468
- val offset: Density.() -> IntOffset,
469
- val onNodeRemeasured: (IntSize) -> Unit,
470
- val onDraw: () -> Unit,
471
- val applyClip: Boolean
472
- ) : Modifier.Node(),
473
- LayoutModifierNode,
474
- LayoutAwareModifierNode,
475
- DrawModifierNode,
476
- PointerInputModifierNode {
477
- override fun onRemeasured(size: IntSize) = onNodeRemeasured(size)
478
-
479
- var pointersDown by mutableStateOf(0)
480
-
481
- override fun onPointerEvent(
482
- pointerEvent: PointerEvent,
483
- pass: PointerEventPass,
484
- bounds: IntSize
485
- ) {
486
- if (pass == PointerEventPass.Final) {
487
- if (pointerEvent.type == PointerEventType.Press) {
488
- pointersDown++
489
- } else if (pointerEvent.type == PointerEventType.Release) {
490
- pointersDown--
491
- // assert(pointersDown >= 0) { "pointersDown cannot be negative" }
492
- }
493
- }
494
- }
495
-
496
- override fun onCancelPointerInput() {
497
- pointersDown = 0
498
- }
499
-
500
- override fun ContentDrawScope.draw() {
501
- onDraw()
502
- if (applyClip) {
503
- val bounds = Rect(-offset().toOffset(), size)
504
- val rect = size.toRect().intersect(bounds)
505
- clipRect(
506
- left = rect.left,
507
- top = rect.top,
508
- right = rect.right,
509
- bottom = rect.bottom,
510
- ) { this@draw.drawContent() }
511
- } else {
512
- this@draw.drawContent()
513
- }
514
- }
515
-
516
- override fun MeasureScope.measure(
517
- measurable: Measurable,
518
- constraints: Constraints
519
- ): MeasureResult {
520
- val placeable = measurable.measure(constraints)
521
- return layout(placeable.width, placeable.height) {
522
- var position = offset()
523
-
524
- with(pullRefreshState) {
525
- this ?: return@with
526
- if (refreshingState.value) {
527
- position = position.copy(
528
- y = position.y.coerceAtLeast(refreshOffset.roundToPx())
529
- )
530
- }
531
- updatePercentage(position.y / refreshOffset.toPx())
532
- }
533
- placeable.placeWithLayer(position)
534
- }
535
- }
536
- }
537
-
538
- private fun Velocity.toOffset(): Offset =
539
- Offset(x, y)
540
-
541
- private fun Offset.toVelocity(): Velocity =
542
- Velocity(x, y)
@@ -1,49 +0,0 @@
1
- package vn.momo.kits.components
2
-
3
- import androidx.compose.foundation.Canvas
4
- import androidx.compose.foundation.background
5
- import androidx.compose.foundation.layout.Box
6
- import androidx.compose.foundation.layout.fillMaxWidth
7
- import androidx.compose.foundation.layout.height
8
- import androidx.compose.foundation.layout.padding
9
- import androidx.compose.runtime.Composable
10
- import androidx.compose.ui.Modifier
11
- import androidx.compose.ui.geometry.Offset
12
- import androidx.compose.ui.graphics.PathEffect
13
- import androidx.compose.ui.graphics.StrokeCap
14
- import androidx.compose.ui.unit.dp
15
- import vn.momo.kits.const.AppTheme
16
- import vn.momo.kits.const.Spacing
17
-
18
- enum class DividerType { DEFAULT, DASH }
19
-
20
- @Composable
21
- fun Divider(useMargin: Boolean = false, type: DividerType = DividerType.DEFAULT) {
22
- val color = AppTheme.current.colors.border.default
23
- val margin = if (useMargin) Spacing.XS else 0.dp
24
- if (type == DividerType.DASH) {
25
- Canvas(
26
- modifier = Modifier
27
- .fillMaxWidth()
28
- .padding(vertical = margin)
29
- .height(1.dp),
30
- ) {
31
- drawLine(
32
- color = color,
33
- start = Offset(0f, size.height / 2f),
34
- end = Offset(size.width, size.height / 2f),
35
- strokeWidth = size.height,
36
- cap = StrokeCap.Round,
37
- pathEffect = PathEffect.dashPathEffect(floatArrayOf(4.dp.toPx(), 4.dp.toPx())),
38
- )
39
- }
40
- return
41
- }
42
- Box(
43
- modifier = Modifier
44
- .fillMaxWidth()
45
- .padding(vertical = margin)
46
- .height(1.dp)
47
- .background(color = color),
48
- )
49
- }
@@ -1,86 +0,0 @@
1
- package vn.momo.kits.components
2
-
3
- import androidx.compose.foundation.border
4
- import androidx.compose.foundation.layout.Box
5
- import androidx.compose.foundation.layout.size
6
- import androidx.compose.runtime.Composable
7
- import androidx.compose.runtime.remember
8
- import androidx.compose.ui.Modifier
9
- import androidx.compose.ui.graphics.Color
10
- import androidx.compose.ui.graphics.ColorFilter
11
- import androidx.compose.ui.layout.ContentScale
12
- import androidx.compose.ui.semantics.contentDescription
13
- import androidx.compose.ui.semantics.semantics
14
- import androidx.compose.ui.unit.Dp
15
- import androidx.compose.ui.unit.dp
16
- import coil3.compose.AsyncImage
17
- import coil3.compose.LocalPlatformContext
18
- import coil3.request.ImageRequest
19
- import vn.momo.kits.application.IsShowBaseLineDebug
20
- import vn.momo.kits.const.AppTheme
21
- import vn.momo.kits.const.Colors
22
- import vn.momo.kits.gifimage.GifImage
23
- import vn.momo.kits.modifier.conditional
24
- import vn.momo.kits.utils.Icons
25
- import vn.momo.kits.utils.noThemeIcons
26
-
27
- @Composable
28
- fun Icon(
29
- source: String,
30
- size: Dp = 24.dp,
31
- color: Color? = AppTheme.current.colors.text.default,
32
- modifier: Modifier = Modifier,
33
- ) {
34
- // decode image without downscaling it
35
- val context = LocalPlatformContext.current
36
-
37
- val iconUrl = remember(source) {
38
- if (source.contains("https")) {
39
- source
40
- } else {
41
- Icons[source] ?: ""
42
- }
43
- }
44
-
45
- val iconColor = remember(source, color) {
46
- if (noThemeIcons.contains(source)) null else color
47
- }
48
-
49
- val colorFilter = remember(iconColor) {
50
- iconColor?.let { ColorFilter.tint(it) }
51
- }
52
-
53
- val contentDesc = remember(iconUrl) { "img|$iconUrl" }
54
-
55
- Box(
56
- modifier = modifier
57
- .size(size)
58
- .conditional(IsShowBaseLineDebug) {
59
- border(1.dp, Colors.blue_03)
60
- }
61
- .semantics { contentDescription = contentDesc }
62
- ) {
63
- if (isGifUrl(iconUrl)) {
64
- GifImage(
65
- modifier = Modifier.matchParentSize(),
66
- url = iconUrl,
67
- contentDescription = null,
68
- contentScale = ContentScale.Fit,
69
- )
70
- } else {
71
- AsyncImage(
72
- modifier = Modifier.matchParentSize(),
73
- model = ImageRequest.Builder(context)
74
- .data(iconUrl)
75
- .size(
76
- coil3.size.Dimension.Undefined,
77
- coil3.size.Dimension.Undefined
78
- )
79
- .build(),
80
- contentDescription = null,
81
- contentScale = ContentScale.Fit,
82
- colorFilter = colorFilter,
83
- )
84
- }
85
- }
86
- }