@momo-kits/native-kits 0.112.1-beta.9 → 0.113.0-rc.1

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 (34) hide show
  1. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +58 -0
  2. package/compose/src/commonMain/kotlin/vn/momo/kits/application/{Components.kt → Header.kt} +37 -164
  3. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +72 -0
  4. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +63 -0
  5. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +75 -0
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +85 -39
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +26 -0
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +38 -32
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +17 -8
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +65 -0
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +2 -2
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +4 -4
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +3 -3
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +3 -1
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +14 -23
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +1 -1
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +47 -37
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +6 -6
  19. package/ios/Application/ApplicationEnvironment.swift +34 -0
  20. package/ios/Application/Components.swift +222 -0
  21. package/ios/Application/ComposeApi.swift +22 -0
  22. package/ios/Application/FloatingButton.swift +148 -0
  23. package/ios/Application/HeaderRight.swift +249 -0
  24. package/ios/Application/Screen.swift +174 -0
  25. package/ios/Badge/BadgeDot.swift +31 -0
  26. package/ios/Button/Button.swift +1 -2
  27. package/ios/Icon/Icon.swift +1 -3
  28. package/ios/Image/Image.swift +17 -1
  29. package/ios/Input/InputSearch.swift +56 -0
  30. package/ios/Popup/PopupDisplay.swift +38 -18
  31. package/ios/Swipeable/SwipeCell.swift +39 -31
  32. package/ios/Typography/Typography.swift +2 -1
  33. package/local.properties +2 -2
  34. package/package.json +1 -1
@@ -0,0 +1,58 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.layout.Box
5
+ import androidx.compose.foundation.layout.fillMaxWidth
6
+ import androidx.compose.foundation.layout.height
7
+ import androidx.compose.foundation.layout.offset
8
+ import androidx.compose.foundation.layout.padding
9
+ import androidx.compose.foundation.layout.width
10
+ import androidx.compose.foundation.shape.RoundedCornerShape
11
+ import androidx.compose.runtime.Composable
12
+ import androidx.compose.ui.Modifier
13
+ import androidx.compose.ui.graphics.Color
14
+ import androidx.compose.ui.unit.dp
15
+ import androidx.compose.ui.zIndex
16
+ import vn.momo.kits.components.InputSearch
17
+ import vn.momo.kits.components.InputSearchProps
18
+ import vn.momo.kits.const.Radius
19
+ import vn.momo.kits.const.Spacing
20
+
21
+ @Composable
22
+ fun AnimationSearchInput(
23
+ animations: HeaderAnimations,
24
+ inputSearchProps: InputSearchProps
25
+ ) {
26
+ Box(
27
+ modifier = Modifier
28
+ .fillMaxWidth()
29
+ .offset(
30
+ x = animations.translateX.dp,
31
+ y = animations.translateY.dp
32
+ )
33
+ ) {
34
+ Box(
35
+ modifier = Modifier
36
+ .height(HEADER_HEIGHT.dp)
37
+ .padding(vertical = Spacing.S)
38
+ .zIndex(1f)
39
+ ) {
40
+ Box(
41
+ modifier = Modifier
42
+ .width(animations.width.dp)
43
+ .background(
44
+ color = animations.backgroundSearch,
45
+ shape = RoundedCornerShape(Radius.XL)
46
+ )
47
+ ) {
48
+ InputSearch(
49
+ inputSearchProps = inputSearchProps.copy(
50
+ showButtonText = false,
51
+ backgroundColor = Color.Transparent
52
+ )
53
+ )
54
+ }
55
+ }
56
+ }
57
+
58
+ }
@@ -1,7 +1,5 @@
1
1
  package vn.momo.kits.application
2
2
 
3
- import androidx.compose.animation.animateColorAsState
4
- import androidx.compose.animation.core.animateFloatAsState
5
3
  import androidx.compose.foundation.background
6
4
  import androidx.compose.foundation.border
7
5
  import androidx.compose.foundation.clickable
@@ -25,143 +23,23 @@ import androidx.compose.runtime.setValue
25
23
  import androidx.compose.runtime.snapshotFlow
26
24
  import androidx.compose.ui.Alignment
27
25
  import androidx.compose.ui.Modifier
28
- import androidx.compose.ui.draw.alpha
29
- import androidx.compose.ui.geometry.Offset
30
- import androidx.compose.ui.graphics.Brush
31
- import androidx.compose.ui.graphics.Color
32
26
  import androidx.compose.ui.graphics.graphicsLayer
33
- import androidx.compose.ui.layout.ContentScale
34
- import androidx.compose.ui.platform.LocalDensity
35
27
  import androidx.compose.ui.semantics.semantics
36
28
  import androidx.compose.ui.semantics.testTag
37
- import androidx.compose.ui.text.style.TextAlign
29
+ import androidx.compose.ui.unit.Dp
38
30
  import androidx.compose.ui.unit.dp
39
31
  import androidx.compose.ui.zIndex
40
32
  import kotlinx.coroutines.flow.distinctUntilChanged
41
33
  import kotlinx.coroutines.flow.map
42
34
  import vn.momo.kits.components.Icon
43
- import vn.momo.kits.components.Image
44
35
  import vn.momo.kits.components.InputSearch
45
36
  import vn.momo.kits.components.InputSearchProps
46
- import vn.momo.kits.components.Options
47
- import vn.momo.kits.components.Text
48
37
  import vn.momo.kits.const.AppStatusBar
49
38
  import vn.momo.kits.const.AppTheme
50
39
  import vn.momo.kits.const.Colors
51
40
  import vn.momo.kits.const.Spacing
52
- import vn.momo.kits.const.Typography
53
41
  import vn.momo.kits.modifier.setAutomationId
54
42
  import vn.momo.kits.platform.getStatusBarHeight
55
- import vn.momo.kits.utils.bottomBorder
56
-
57
- enum class TitlePosition {
58
- LEFT, CENTER,
59
- }
60
-
61
-
62
- data class AnimatedHeader(
63
- val type: HeaderType = HeaderType.DEFAULT,
64
- val composable: @Composable (scrollState: Int) -> Unit = {}
65
- )
66
-
67
- @Composable
68
- fun HeaderBackground(
69
- headerType: HeaderType = HeaderType.DEFAULT,
70
- scrollState: Int
71
- ) {
72
- val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
73
- val opacityAni by animateFloatAsState(
74
- targetValue = (1 - (scrollState / 200f)).coerceIn(0f, 1f),
75
- )
76
-
77
- val backgroundColor = if (scrollState == 0) {
78
- Color.Transparent
79
- } else {
80
- AppTheme.current.colors.background.surface
81
- }
82
-
83
-
84
- when (headerType) {
85
- HeaderType.DEFAULT -> {
86
- val height = statusBarHeight + 52.dp
87
- Box(
88
- modifier = Modifier.fillMaxWidth().height(height)
89
- .background(backgroundColor)
90
- .bottomBorder(
91
- strokeWidth = 1.dp,
92
- color = AppTheme.current.colors.border.default
93
- )
94
- ) {
95
- Box(
96
- modifier = Modifier
97
- .height(height)
98
- .fillMaxWidth()
99
- .alpha(opacityAni)
100
- .background(
101
- Brush.linearGradient(
102
- colors = listOf(
103
- Color(0xFFFDCADE),
104
- Color(0x00FDCADE)
105
- ),
106
- start = Offset(0f, 0f),
107
- end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
108
- )
109
- )
110
- )
111
- if (AppTheme.current.assets.headerBackground != null) {
112
- Image(
113
- loading = false,
114
- source = AppTheme.current.assets.headerBackground!!,
115
- modifier = Modifier.fillMaxWidth().height(height),
116
- options = Options(
117
- contentScale = ContentScale.FillWidth
118
- )
119
- )
120
- }
121
- }
122
-
123
- }
124
-
125
- HeaderType.EXTENDED -> {
126
-
127
- Box(
128
- modifier = Modifier.fillMaxWidth().height(154.dp)
129
- .alpha(opacityAni)
130
- .background(
131
- Brush.linearGradient(
132
- colors = listOf(
133
- Color(0xFFFDCADE),
134
- Color(0x00FDCADE)
135
- ),
136
- start = Offset(0f, 0f),
137
- end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
138
- )
139
- )
140
- ) {
141
- if (AppTheme.current.assets.headerBackground != null) {
142
- Box(
143
- modifier = Modifier.fillMaxWidth()
144
- .background(backgroundColor)
145
- ) {
146
- Image(
147
- loading = false,
148
- source = AppTheme.current.assets.headerBackground!!,
149
- modifier = Modifier.fillMaxWidth().height(154.dp),
150
- options = Options(
151
- contentScale = ContentScale.FillWidth
152
- )
153
- )
154
- }
155
- }
156
- }
157
- }
158
-
159
- else -> {
160
- Box(modifier = Modifier.fillMaxWidth())
161
- }
162
- }
163
-
164
- }
165
43
 
166
44
  @Composable
167
45
  fun Header(
@@ -170,10 +48,12 @@ fun Header(
170
48
  title: String,
171
49
  headerRight: @Composable (() -> Unit)? = null,
172
50
  goBack: (() -> Unit)? = null,
173
- opacity: Float? = null,
51
+ opacity: Float = 1f,
174
52
  animatedHeader: AnimatedHeader? = null,
175
53
  scrollState: Int = 0,
176
- inputSearchProps: InputSearchProps?
54
+ inputSearchProps: InputSearchProps? = null,
55
+ headerRightWidth: Dp = 0.dp,
56
+ useAnimationSearch: Boolean = false
177
57
  ) {
178
58
  val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
179
59
  val tintIconColor = AppTheme.current.colors.text.default
@@ -187,24 +67,31 @@ fun Header(
187
67
  .distinctUntilChanged()
188
68
  .collect { fraction -> colorFraction = fraction }
189
69
  }
70
+ val animations = useHeaderSearchAnimation(
71
+ opacityAni = opacity,
72
+ scrollState = scrollState,
73
+ headerRightWidth = headerRightWidth,
74
+ isBack = goBack != null
75
+ )
190
76
 
191
- val backgroundSearch by animateColorAsState(
192
- targetValue = animateColor(
193
- Colors.black_01,
194
- AppTheme.current.colors.background.default,
195
- colorFraction
196
- )
77
+ val backgroundSearch = animateColor(
78
+ Colors.black_01,
79
+ AppTheme.current.colors.background.default,
80
+ colorFraction
197
81
  )
198
82
 
83
+ val searchAnimationEnable =
84
+ inputSearchProps != null && useAnimationSearch && headerType == HeaderType.EXTENDED
85
+
199
86
  if (headerType != HeaderType.NONE) {
200
87
  BoxWithConstraints(
201
- Modifier.height(statusBarHeight + 52.dp)
88
+ Modifier.height(statusBarHeight + HEADER_HEIGHT.dp)
202
89
  .fillMaxWidth()
203
90
  .zIndex(10f),
204
91
  contentAlignment = Alignment.BottomCenter
205
92
  ) {
206
93
  Row(
207
- modifier = Modifier.height(52.dp)
94
+ modifier = Modifier.height(HEADER_HEIGHT.dp)
208
95
  .fillMaxWidth()
209
96
  .padding(horizontal = Spacing.M),
210
97
  verticalAlignment = Alignment.CenterVertically,
@@ -242,9 +129,9 @@ fun Header(
242
129
  }
243
130
  }
244
131
 
245
- if (inputSearchProps == null) {
132
+ if (useAnimationSearch || inputSearchProps == null) {
246
133
  Box(Modifier.graphicsLayer {
247
- alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
134
+ alpha = if (animatedHeader !== null) opacity else 1f
248
135
  }) {
249
136
  headerRight?.invoke()
250
137
  }
@@ -253,7 +140,7 @@ fun Header(
253
140
 
254
141
  // Title
255
142
  Row(
256
- modifier = Modifier.height(52.dp)
143
+ modifier = Modifier.height(HEADER_HEIGHT.dp)
257
144
  .fillMaxWidth()
258
145
  .padding(horizontal = Spacing.M),
259
146
  verticalAlignment = Alignment.CenterVertically,
@@ -261,15 +148,20 @@ fun Header(
261
148
  if (goBack != null && titlePosition == TitlePosition.LEFT) {
262
149
  Spacer(Modifier.width(40.dp))
263
150
  }
264
- if (inputSearchProps != null) {
151
+ if (inputSearchProps != null && !useAnimationSearch) {
265
152
  InputSearch(inputSearchProps = inputSearchProps.copy(backgroundColor = backgroundSearch))
266
153
  } else {
267
154
  Box(
268
155
  Modifier.weight(1f).graphicsLayer {
269
- alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
156
+ alpha = if (useAnimationSearch) {
157
+ 1f - (opacity)
158
+ } else {
159
+ if (animatedHeader !== null) opacity else 1f
160
+ }
270
161
  },
271
162
  contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
272
163
  ) {
164
+
273
165
  HeaderTitle(
274
166
  title = title,
275
167
  color = tintIconColor,
@@ -280,32 +172,13 @@ fun Header(
280
172
  }
281
173
  }
282
174
  }
175
+
176
+ if (searchAnimationEnable) {
177
+ AnimationSearchInput(
178
+ animations = animations,
179
+ inputSearchProps = inputSearchProps!!
180
+ )
181
+ }
283
182
  }
284
183
  }
285
- }
286
-
287
- @Composable
288
- fun HeaderTitle(
289
- title: String = "",
290
- modifier: Modifier = Modifier,
291
- textAlign: TextAlign = TextAlign.Start,
292
- color: Color? = null,
293
- ) {
294
- Text(
295
- modifier = Modifier.then(modifier).zIndex(1f),
296
- text = title,
297
- textAlign = textAlign,
298
- style = Typography.actionS,
299
- color = color,
300
- maxLines = 1
301
- )
302
- }
303
-
304
- fun animateColor(start: Color, stop: Color, fraction: Float): Color {
305
- return Color(
306
- red = start.red + fraction * (stop.red - start.red),
307
- green = start.green + fraction * (stop.green - start.green),
308
- blue = start.blue + fraction * (stop.blue - start.blue),
309
- alpha = start.alpha + fraction * (stop.alpha - start.alpha)
310
- )
311
184
  }
@@ -0,0 +1,72 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.animation.animateColorAsState
4
+ import androidx.compose.animation.core.animateFloatAsState
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.fillMaxWidth
7
+ import androidx.compose.runtime.Composable
8
+ import androidx.compose.runtime.getValue
9
+ import androidx.compose.ui.Modifier
10
+ import androidx.compose.ui.graphics.Color
11
+ import vn.momo.kits.const.AppStatusBar
12
+ import vn.momo.kits.const.AppTheme
13
+ import vn.momo.kits.platform.getStatusBarHeight
14
+
15
+ enum class TitlePosition {
16
+ LEFT, CENTER,
17
+ }
18
+
19
+ data class AnimatedHeader(
20
+ val type: HeaderType = HeaderType.DEFAULT,
21
+ val composable: @Composable (scrollState: Int) -> Unit = {}
22
+ )
23
+
24
+ fun animateColor(start: Color, stop: Color, fraction: Float): Color {
25
+ return Color(
26
+ red = start.red + fraction * (stop.red - start.red),
27
+ green = start.green + fraction * (stop.green - start.green),
28
+ blue = start.blue + fraction * (stop.blue - start.blue),
29
+ alpha = start.alpha + fraction * (stop.alpha - start.alpha)
30
+ )
31
+ }
32
+
33
+ @Composable
34
+ fun HeaderBackground(
35
+ headerType: HeaderType = HeaderType.DEFAULT,
36
+ scrollState: Int,
37
+ ) {
38
+ val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
39
+
40
+ val opacityAni by animateFloatAsState(
41
+ targetValue = (1 - (scrollState / HEADER_HEIGHT*1f)).coerceIn(0f, 1f),
42
+ )
43
+
44
+ val backgroundColor by animateColorAsState(
45
+ targetValue = animateColor(
46
+ Color.Transparent,
47
+ AppTheme.current.colors.background.surface,
48
+ opacityAni
49
+ ),
50
+ )
51
+
52
+ when (headerType) {
53
+ HeaderType.DEFAULT -> {
54
+ HeaderDefault(
55
+ opacityAni = opacityAni,
56
+ statusBarHeight = statusBarHeight,
57
+ )
58
+ }
59
+
60
+ HeaderType.EXTENDED -> {
61
+ HeaderExtended(
62
+ opacityAni = opacityAni,
63
+ statusBarHeight = statusBarHeight,
64
+ backgroundColor = backgroundColor,
65
+ )
66
+ }
67
+
68
+ else -> {
69
+ Box(modifier = Modifier.fillMaxWidth())
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,63 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.layout.Box
5
+ import androidx.compose.foundation.layout.fillMaxWidth
6
+ import androidx.compose.foundation.layout.height
7
+ import androidx.compose.runtime.Composable
8
+ import androidx.compose.ui.Modifier
9
+ import androidx.compose.ui.draw.alpha
10
+ import androidx.compose.ui.geometry.Offset
11
+ import androidx.compose.ui.graphics.Brush
12
+ import androidx.compose.ui.graphics.Color
13
+ import androidx.compose.ui.layout.ContentScale
14
+ import androidx.compose.ui.platform.LocalDensity
15
+ import androidx.compose.ui.unit.Dp
16
+ import androidx.compose.ui.unit.dp
17
+ import vn.momo.kits.components.Image
18
+ import vn.momo.kits.components.Options
19
+ import vn.momo.kits.const.AppTheme
20
+ import vn.momo.kits.utils.bottomBorder
21
+
22
+ @Composable
23
+ fun HeaderDefault(
24
+ opacityAni: Float,
25
+ statusBarHeight: Dp,
26
+ ) {
27
+ val height = statusBarHeight + HEADER_HEIGHT.dp
28
+ Box(
29
+ modifier = Modifier.fillMaxWidth().height(height)
30
+ .background(AppTheme.current.colors.background.surface)
31
+ .bottomBorder(
32
+ strokeWidth = 1.dp,
33
+ color = AppTheme.current.colors.border.default
34
+ )
35
+ ) {
36
+ Box(
37
+ modifier = Modifier
38
+ .height(height)
39
+ .fillMaxWidth()
40
+ .alpha(opacityAni)
41
+ .background(
42
+ Brush.linearGradient(
43
+ colors = listOf(
44
+ Color(0xFFFDCADE),
45
+ Color(0x00FDCADE)
46
+ ),
47
+ start = Offset(0f, 0f),
48
+ end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
49
+ )
50
+ )
51
+ )
52
+ if (AppTheme.current.assets.headerBackground != null) {
53
+ Image(
54
+ loading = false,
55
+ source = AppTheme.current.assets.headerBackground!!,
56
+ modifier = Modifier.fillMaxWidth().height(height),
57
+ options = Options(
58
+ contentScale = ContentScale.FillWidth
59
+ )
60
+ )
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,75 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.layout.Box
5
+ import androidx.compose.foundation.layout.fillMaxWidth
6
+ import androidx.compose.foundation.layout.height
7
+ import androidx.compose.runtime.Composable
8
+ import androidx.compose.ui.Modifier
9
+ import androidx.compose.ui.draw.alpha
10
+ import androidx.compose.ui.geometry.Offset
11
+ import androidx.compose.ui.graphics.Brush
12
+ import androidx.compose.ui.graphics.Color
13
+ import androidx.compose.ui.layout.ContentScale
14
+ import androidx.compose.ui.platform.LocalDensity
15
+ import androidx.compose.ui.unit.Dp
16
+ import androidx.compose.ui.unit.dp
17
+ import vn.momo.kits.components.Image
18
+ import vn.momo.kits.components.Options
19
+ import vn.momo.kits.const.AppTheme
20
+ import vn.momo.kits.utils.bottomBorder
21
+
22
+ @Composable
23
+ fun HeaderExtended(
24
+ opacityAni: Float,
25
+ statusBarHeight: Dp,
26
+ backgroundColor: Color
27
+ ) {
28
+ Box(
29
+ modifier = Modifier
30
+ .fillMaxWidth()
31
+ .height(154.dp)
32
+ .alpha(opacityAni)
33
+ .background(
34
+ Brush.linearGradient(
35
+ colors = listOf(
36
+ Color(0xFFFDCADE),
37
+ Color(0x00FDCADE)
38
+ ),
39
+ start = Offset(0f, 0f),
40
+ end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
41
+ )
42
+ )
43
+ ) {
44
+ if (AppTheme.current.assets.headerBackground != null) {
45
+ Box(
46
+ modifier = Modifier
47
+ .fillMaxWidth()
48
+ .background(backgroundColor)
49
+ ) {
50
+ Image(
51
+ loading = false,
52
+ source = AppTheme.current.assets.headerBackground!!,
53
+ modifier = Modifier.fillMaxWidth().height(154.dp),
54
+ options = Options(
55
+ contentScale = ContentScale.FillWidth
56
+ )
57
+ )
58
+ }
59
+ }
60
+ }
61
+
62
+ Box(
63
+ modifier = Modifier
64
+ .fillMaxWidth()
65
+ .alpha(1f - opacityAni)
66
+ .height(statusBarHeight + HEADER_HEIGHT.dp)
67
+ .background(
68
+ AppTheme.current.colors.background.surface
69
+ )
70
+ .bottomBorder(
71
+ strokeWidth = 1.dp,
72
+ color = AppTheme.current.colors.border.default
73
+ )
74
+ )
75
+ }