@momo-kits/native-kits 0.113.2-beta.16 → 0.113.2-beta.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +9 -38
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +39 -25
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +5 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +41 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +2 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +12 -13
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +22 -14
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +11 -20
- package/ios/Popup/PopupDisplay.swift +9 -5
- package/package.json +1 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package vn.momo.kits.application
|
|
2
2
|
|
|
3
|
-
import androidx.compose.animation.animateColorAsState
|
|
4
3
|
import androidx.compose.foundation.background
|
|
5
4
|
import androidx.compose.foundation.border
|
|
6
5
|
import androidx.compose.foundation.clickable
|
|
@@ -24,7 +23,6 @@ import androidx.compose.runtime.setValue
|
|
|
24
23
|
import androidx.compose.runtime.snapshotFlow
|
|
25
24
|
import androidx.compose.ui.Alignment
|
|
26
25
|
import androidx.compose.ui.Modifier
|
|
27
|
-
import androidx.compose.ui.graphics.Color
|
|
28
26
|
import androidx.compose.ui.graphics.graphicsLayer
|
|
29
27
|
import androidx.compose.ui.semantics.semantics
|
|
30
28
|
import androidx.compose.ui.semantics.testTag
|
|
@@ -42,15 +40,6 @@ import vn.momo.kits.const.Spacing
|
|
|
42
40
|
import vn.momo.kits.modifier.setAutomationId
|
|
43
41
|
import vn.momo.kits.platform.getStatusBarHeight
|
|
44
42
|
|
|
45
|
-
enum class TitlePosition {
|
|
46
|
-
LEFT, CENTER,
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
data class AnimatedHeader(
|
|
50
|
-
val type: HeaderType = HeaderType.DEFAULT,
|
|
51
|
-
val composable: @Composable (scrollState: Int) -> Unit = {}
|
|
52
|
-
)
|
|
53
|
-
|
|
54
43
|
@Composable
|
|
55
44
|
fun Header(
|
|
56
45
|
headerType: HeaderType = HeaderType.DEFAULT,
|
|
@@ -77,24 +66,15 @@ fun Header(
|
|
|
77
66
|
.collect { fraction -> colorFraction = fraction }
|
|
78
67
|
}
|
|
79
68
|
|
|
80
|
-
val backgroundSearch
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
colorFraction
|
|
85
|
-
)
|
|
69
|
+
val backgroundSearch = animateColor(
|
|
70
|
+
Colors.black_01,
|
|
71
|
+
AppTheme.current.colors.background.default,
|
|
72
|
+
colorFraction
|
|
86
73
|
)
|
|
87
74
|
|
|
88
|
-
val backgroundColor = if (scrollState == 0) {
|
|
89
|
-
Color.Transparent
|
|
90
|
-
} else {
|
|
91
|
-
AppTheme.current.colors.background.surface
|
|
92
|
-
}
|
|
93
|
-
|
|
94
75
|
if (headerType != HeaderType.NONE) {
|
|
95
76
|
BoxWithConstraints(
|
|
96
77
|
Modifier.height(statusBarHeight + 52.dp)
|
|
97
|
-
.background(backgroundColor)
|
|
98
78
|
.fillMaxWidth()
|
|
99
79
|
.zIndex(10f),
|
|
100
80
|
contentAlignment = Alignment.BottomCenter
|
|
@@ -138,9 +118,9 @@ fun Header(
|
|
|
138
118
|
}
|
|
139
119
|
}
|
|
140
120
|
|
|
141
|
-
if (
|
|
121
|
+
if (useAnimationSearch || inputSearchProps == null) {
|
|
142
122
|
Box(Modifier.graphicsLayer {
|
|
143
|
-
alpha = if (
|
|
123
|
+
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
144
124
|
}) {
|
|
145
125
|
headerRight?.invoke()
|
|
146
126
|
}
|
|
@@ -162,7 +142,7 @@ fun Header(
|
|
|
162
142
|
} else {
|
|
163
143
|
Box(
|
|
164
144
|
Modifier.weight(1f).graphicsLayer {
|
|
165
|
-
alpha = if (useAnimationSearch
|
|
145
|
+
alpha = if (useAnimationSearch) {
|
|
166
146
|
1f - (opacity ?: 1f)
|
|
167
147
|
} else {
|
|
168
148
|
if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
@@ -170,6 +150,7 @@ fun Header(
|
|
|
170
150
|
},
|
|
171
151
|
contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
|
|
172
152
|
) {
|
|
153
|
+
|
|
173
154
|
HeaderTitle(
|
|
174
155
|
title = title,
|
|
175
156
|
color = tintIconColor,
|
|
@@ -182,14 +163,4 @@ fun Header(
|
|
|
182
163
|
}
|
|
183
164
|
}
|
|
184
165
|
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
fun animateColor(start: Color, stop: Color, fraction: Float): Color {
|
|
189
|
-
return Color(
|
|
190
|
-
red = start.red + fraction * (stop.red - start.red),
|
|
191
|
-
green = start.green + fraction * (stop.green - start.green),
|
|
192
|
-
blue = start.blue + fraction * (stop.blue - start.blue),
|
|
193
|
-
alpha = start.alpha + fraction * (stop.alpha - start.alpha)
|
|
194
|
-
)
|
|
195
|
-
}
|
|
166
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
package vn.momo.kits.application
|
|
2
2
|
|
|
3
|
+
import androidx.compose.animation.animateColorAsState
|
|
4
|
+
import androidx.compose.animation.core.animateFloatAsState
|
|
3
5
|
import androidx.compose.foundation.layout.Box
|
|
4
6
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
5
7
|
import androidx.compose.runtime.Composable
|
|
8
|
+
import androidx.compose.runtime.getValue
|
|
6
9
|
import androidx.compose.ui.Modifier
|
|
7
10
|
import androidx.compose.ui.graphics.Color
|
|
8
11
|
import androidx.compose.ui.unit.Dp
|
|
@@ -10,11 +13,25 @@ import androidx.compose.ui.unit.dp
|
|
|
10
13
|
import vn.momo.kits.components.InputSearchProps
|
|
11
14
|
import vn.momo.kits.const.AppStatusBar
|
|
12
15
|
import vn.momo.kits.const.AppTheme
|
|
13
|
-
import vn.momo.kits.platform.getScreenDimensions
|
|
14
16
|
import vn.momo.kits.platform.getStatusBarHeight
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
enum class TitlePosition {
|
|
19
|
+
LEFT, CENTER,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
data class AnimatedHeader(
|
|
23
|
+
val type: HeaderType = HeaderType.DEFAULT,
|
|
24
|
+
val composable: @Composable (scrollState: Int) -> Unit = {}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
fun animateColor(start: Color, stop: Color, fraction: Float): Color {
|
|
28
|
+
return Color(
|
|
29
|
+
red = start.red + fraction * (stop.red - start.red),
|
|
30
|
+
green = start.green + fraction * (stop.green - start.green),
|
|
31
|
+
blue = start.blue + fraction * (stop.blue - start.blue),
|
|
32
|
+
alpha = start.alpha + fraction * (stop.alpha - start.alpha)
|
|
33
|
+
)
|
|
34
|
+
}
|
|
18
35
|
|
|
19
36
|
@Composable
|
|
20
37
|
fun HeaderBackground(
|
|
@@ -26,41 +43,38 @@ fun HeaderBackground(
|
|
|
26
43
|
useAnimationSearch: Boolean = false
|
|
27
44
|
) {
|
|
28
45
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
29
|
-
val screenWidth = getScreenDimensions().width
|
|
30
|
-
val leftPosition = if (isBack) (BACK_WIDTH + 20).dp else 20.dp
|
|
31
|
-
val searchWidth = screenWidth - (SCREEN_PADDING * 2)
|
|
32
46
|
|
|
33
|
-
val
|
|
34
|
-
|
|
35
|
-
statusBarHeight = statusBarHeight,
|
|
36
|
-
leftPosition = leftPosition,
|
|
37
|
-
searchWidth = searchWidth,
|
|
38
|
-
headerRightWidth = headerRightWidth
|
|
47
|
+
val opacityAni by animateFloatAsState(
|
|
48
|
+
targetValue = (1 - (scrollState / 52f)).coerceIn(0f, 1f),
|
|
39
49
|
)
|
|
40
50
|
|
|
41
|
-
val backgroundColor
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
val backgroundColor by animateColorAsState(
|
|
52
|
+
targetValue = animateColor(
|
|
53
|
+
Color.Transparent,
|
|
54
|
+
AppTheme.current.colors.background.surface,
|
|
55
|
+
opacityAni
|
|
56
|
+
),
|
|
57
|
+
)
|
|
46
58
|
|
|
47
59
|
when (headerType) {
|
|
48
60
|
HeaderType.DEFAULT -> {
|
|
49
|
-
val height = statusBarHeight + 52.dp
|
|
50
61
|
HeaderDefault(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
backgroundColor = backgroundColor
|
|
62
|
+
opacityAni = opacityAni,
|
|
63
|
+
statusBarHeight = statusBarHeight,
|
|
54
64
|
)
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
HeaderType.EXTENDED -> {
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
HeaderExtended(
|
|
69
|
+
scrollState = scrollState,
|
|
60
70
|
inputSearchProps = inputSearchProps,
|
|
71
|
+
headerRightWidth = headerRightWidth,
|
|
61
72
|
useAnimationSearch = useAnimationSearch,
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
opacityAni = opacityAni,
|
|
74
|
+
isBack = isBack,
|
|
75
|
+
statusBarHeight = statusBarHeight,
|
|
76
|
+
backgroundColor = backgroundColor,
|
|
77
|
+
)
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
else -> {
|
|
@@ -21,13 +21,13 @@ import vn.momo.kits.utils.bottomBorder
|
|
|
21
21
|
|
|
22
22
|
@Composable
|
|
23
23
|
fun HeaderDefault(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
animations: HeaderAnimations
|
|
24
|
+
opacityAni: Float,
|
|
25
|
+
statusBarHeight: Dp,
|
|
27
26
|
) {
|
|
27
|
+
val height = statusBarHeight + 52.dp
|
|
28
28
|
Box(
|
|
29
29
|
modifier = Modifier.fillMaxWidth().height(height)
|
|
30
|
-
.background(
|
|
30
|
+
.background(AppTheme.current.colors.background.surface)
|
|
31
31
|
.bottomBorder(
|
|
32
32
|
strokeWidth = 1.dp,
|
|
33
33
|
color = AppTheme.current.colors.border.default
|
|
@@ -37,7 +37,7 @@ fun HeaderDefault(
|
|
|
37
37
|
modifier = Modifier
|
|
38
38
|
.height(height)
|
|
39
39
|
.fillMaxWidth()
|
|
40
|
-
.alpha(
|
|
40
|
+
.alpha(opacityAni)
|
|
41
41
|
.background(
|
|
42
42
|
Brush.linearGradient(
|
|
43
43
|
colors = listOf(
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package vn.momo.kits.application
|
|
2
2
|
|
|
3
|
+
import androidx.compose.animation.animateColorAsState
|
|
4
|
+
import androidx.compose.animation.core.animateFloatAsState
|
|
3
5
|
import androidx.compose.foundation.background
|
|
4
6
|
import androidx.compose.foundation.layout.Box
|
|
5
7
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
@@ -9,6 +11,7 @@ import androidx.compose.foundation.layout.padding
|
|
|
9
11
|
import androidx.compose.foundation.layout.width
|
|
10
12
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
11
13
|
import androidx.compose.runtime.Composable
|
|
14
|
+
import androidx.compose.runtime.getValue
|
|
12
15
|
import androidx.compose.ui.Alignment
|
|
13
16
|
import androidx.compose.ui.Modifier
|
|
14
17
|
import androidx.compose.ui.draw.alpha
|
|
@@ -17,30 +20,47 @@ import androidx.compose.ui.graphics.Brush
|
|
|
17
20
|
import androidx.compose.ui.graphics.Color
|
|
18
21
|
import androidx.compose.ui.layout.ContentScale
|
|
19
22
|
import androidx.compose.ui.platform.LocalDensity
|
|
23
|
+
import androidx.compose.ui.unit.Dp
|
|
20
24
|
import androidx.compose.ui.unit.dp
|
|
21
25
|
import vn.momo.kits.components.Image
|
|
22
26
|
import vn.momo.kits.components.InputSearch
|
|
23
27
|
import vn.momo.kits.components.InputSearchProps
|
|
24
28
|
import vn.momo.kits.components.Options
|
|
25
29
|
import vn.momo.kits.const.AppTheme
|
|
30
|
+
import vn.momo.kits.const.Colors
|
|
26
31
|
import vn.momo.kits.const.Radius
|
|
27
32
|
import vn.momo.kits.const.Spacing
|
|
33
|
+
import vn.momo.kits.platform.getScreenDimensions
|
|
34
|
+
import vn.momo.kits.utils.bottomBorder
|
|
28
35
|
|
|
29
36
|
@Composable
|
|
30
37
|
fun HeaderExtended(
|
|
31
|
-
|
|
32
|
-
inputSearchProps: InputSearchProps
|
|
33
|
-
useAnimationSearch: Boolean =
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
opacityAni: Float,
|
|
39
|
+
inputSearchProps: InputSearchProps?,
|
|
40
|
+
useAnimationSearch: Boolean = true,
|
|
41
|
+
scrollState: Int,
|
|
42
|
+
headerRightWidth: Dp,
|
|
43
|
+
isBack: Boolean,
|
|
44
|
+
statusBarHeight: Dp,
|
|
45
|
+
backgroundColor: Color
|
|
46
|
+
) {
|
|
47
|
+
val animations = useHeaderSearchAnimation(
|
|
48
|
+
opacityAni = opacityAni,
|
|
49
|
+
scrollState = scrollState,
|
|
50
|
+
headerRightWidth = headerRightWidth,
|
|
51
|
+
statusBarHeight = statusBarHeight,
|
|
52
|
+
isBack = isBack
|
|
53
|
+
)
|
|
54
|
+
|
|
36
55
|
Box(
|
|
37
|
-
modifier = Modifier.fillMaxWidth()
|
|
56
|
+
modifier = Modifier.fillMaxWidth()
|
|
57
|
+
.height(animations.height.dp)
|
|
38
58
|
) {
|
|
39
59
|
Box(
|
|
40
60
|
modifier = Modifier
|
|
41
61
|
.fillMaxWidth()
|
|
42
62
|
.height(154.dp)
|
|
43
|
-
.alpha(
|
|
63
|
+
.alpha(opacityAni)
|
|
44
64
|
.background(
|
|
45
65
|
Brush.linearGradient(
|
|
46
66
|
colors = listOf(
|
|
@@ -70,6 +90,19 @@ fun HeaderExtended(
|
|
|
70
90
|
}
|
|
71
91
|
}
|
|
72
92
|
|
|
93
|
+
Box(
|
|
94
|
+
modifier = Modifier
|
|
95
|
+
.fillMaxWidth()
|
|
96
|
+
.alpha(1f - opacityAni)
|
|
97
|
+
.height(statusBarHeight + 52.dp)
|
|
98
|
+
.background(
|
|
99
|
+
AppTheme.current.colors.background.surface
|
|
100
|
+
)
|
|
101
|
+
.bottomBorder(
|
|
102
|
+
strokeWidth = 1.dp,
|
|
103
|
+
color = AppTheme.current.colors.border.default
|
|
104
|
+
)
|
|
105
|
+
)
|
|
73
106
|
if (inputSearchProps != null && useAnimationSearch) {
|
|
74
107
|
Box(
|
|
75
108
|
modifier = Modifier
|
|
@@ -98,5 +131,4 @@ fun HeaderExtended(
|
|
|
98
131
|
}
|
|
99
132
|
}
|
|
100
133
|
}
|
|
101
|
-
}
|
|
102
|
-
|
|
134
|
+
}
|
|
@@ -79,12 +79,12 @@ object Spacing {
|
|
|
79
79
|
|
|
80
80
|
@Composable
|
|
81
81
|
fun HeaderRight(
|
|
82
|
-
|
|
82
|
+
headerRight: HeaderRightData? = null,
|
|
83
83
|
) {
|
|
84
84
|
Row(
|
|
85
85
|
verticalAlignment = Alignment.CenterVertically,
|
|
86
86
|
) {
|
|
87
|
-
ToolkitHeaderRight(headerRight =
|
|
87
|
+
ToolkitHeaderRight(headerRight = headerRight)
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -180,8 +180,6 @@ fun ToolkitHeaderRight(headerRight: HeaderRightData? = null) {
|
|
|
180
180
|
group.items.any { it.showBadge }
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
if (context === null) return
|
|
184
|
-
|
|
185
183
|
Row(
|
|
186
184
|
verticalAlignment = Alignment.CenterVertically
|
|
187
185
|
) {
|
|
@@ -68,6 +68,7 @@ fun Screen(
|
|
|
68
68
|
layoutOffset: Dp = 56.dp,
|
|
69
69
|
inputSearchProps: InputSearchProps? = null,
|
|
70
70
|
useAnimationSearch: Boolean = false,
|
|
71
|
+
headerRightWidth: Dp = 0.dp,
|
|
71
72
|
content: @Composable () -> Unit,
|
|
72
73
|
) {
|
|
73
74
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
@@ -84,7 +85,7 @@ fun Screen(
|
|
|
84
85
|
val bottomPadding = min(indicator, 21.dp)
|
|
85
86
|
|
|
86
87
|
val opacity by animateFloatAsState(
|
|
87
|
-
targetValue = ((scrollState.value /
|
|
88
|
+
targetValue = ((scrollState.value / 52f)).coerceIn(0f, 1f),
|
|
88
89
|
)
|
|
89
90
|
|
|
90
91
|
val headerAnimated =
|
|
@@ -94,15 +95,16 @@ fun Screen(
|
|
|
94
95
|
|
|
95
96
|
Box(
|
|
96
97
|
Modifier.fillMaxSize()
|
|
97
|
-
.background(AppTheme.current.colors.background.
|
|
98
|
+
.background(backgroundColor ?: AppTheme.current.colors.background.default)
|
|
98
99
|
) {
|
|
99
100
|
|
|
100
101
|
if (animatedHeader === null) {
|
|
101
102
|
HeaderBackground(
|
|
102
103
|
headerType = headerType,
|
|
103
104
|
scrollState = scrollState.value,
|
|
104
|
-
inputSearchProps
|
|
105
|
-
useAnimationSearch = useAnimationSearch
|
|
105
|
+
inputSearchProps= inputSearchProps,
|
|
106
|
+
useAnimationSearch = useAnimationSearch,
|
|
107
|
+
headerRightWidth = headerRightWidth
|
|
106
108
|
)
|
|
107
109
|
} else {
|
|
108
110
|
Box(
|
|
@@ -114,8 +116,9 @@ fun Screen(
|
|
|
114
116
|
isBack = isBack,
|
|
115
117
|
headerType = headerType,
|
|
116
118
|
scrollState = scrollState.value,
|
|
117
|
-
inputSearchProps
|
|
118
|
-
useAnimationSearch = useAnimationSearch
|
|
119
|
+
inputSearchProps= inputSearchProps,
|
|
120
|
+
useAnimationSearch = useAnimationSearch,
|
|
121
|
+
headerRightWidth = headerRightWidth
|
|
119
122
|
)
|
|
120
123
|
}
|
|
121
124
|
}
|
|
@@ -130,7 +133,7 @@ fun Screen(
|
|
|
130
133
|
animatedHeader = animatedHeader,
|
|
131
134
|
inputSearchProps = inputSearchProps,
|
|
132
135
|
scrollState = scrollState.value,
|
|
133
|
-
useAnimationSearch = useAnimationSearch
|
|
136
|
+
useAnimationSearch = useAnimationSearch,
|
|
134
137
|
)
|
|
135
138
|
|
|
136
139
|
Column(
|
|
@@ -155,18 +158,14 @@ fun Screen(
|
|
|
155
158
|
verticalArrangement = verticalArrangement,
|
|
156
159
|
horizontalAlignment = horizontalAlignment
|
|
157
160
|
) {
|
|
158
|
-
Box
|
|
159
|
-
modifier = Modifier.background(
|
|
160
|
-
backgroundColor ?: AppTheme.current.colors.background.default
|
|
161
|
-
)
|
|
162
|
-
) {
|
|
161
|
+
Box {
|
|
163
162
|
headerAnimated()
|
|
164
163
|
Column {
|
|
165
164
|
if (animatedHeader !== null) {
|
|
166
165
|
Spacer(modifier = Modifier.padding(top = statusBarHeight + 52.dp + layoutOffset))
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
if (useAnimationSearch && inputSearchProps != null) {
|
|
168
|
+
if (useAnimationSearch && inputSearchProps != null && headerType == HeaderType.EXTENDED) {
|
|
170
169
|
Spacer(modifier = Modifier.padding(top = statusBarHeight))
|
|
171
170
|
}
|
|
172
171
|
content()
|
|
@@ -3,11 +3,13 @@ package vn.momo.kits.application
|
|
|
3
3
|
import androidx.compose.animation.animateColorAsState
|
|
4
4
|
import androidx.compose.animation.core.animateFloatAsState
|
|
5
5
|
import androidx.compose.runtime.Composable
|
|
6
|
+
import androidx.compose.runtime.getValue
|
|
6
7
|
import androidx.compose.ui.graphics.Color
|
|
7
8
|
import androidx.compose.ui.unit.Dp
|
|
9
|
+
import androidx.compose.ui.unit.dp
|
|
8
10
|
import vn.momo.kits.const.AppTheme
|
|
9
11
|
import vn.momo.kits.const.Colors
|
|
10
|
-
import
|
|
12
|
+
import vn.momo.kits.platform.getScreenDimensions
|
|
11
13
|
|
|
12
14
|
data class HeaderAnimations(
|
|
13
15
|
val opacity: Float,
|
|
@@ -17,40 +19,46 @@ data class HeaderAnimations(
|
|
|
17
19
|
val height: Float
|
|
18
20
|
)
|
|
19
21
|
|
|
22
|
+
private const val SCREEN_PADDING = 12
|
|
23
|
+
private const val BACK_WIDTH = 28
|
|
24
|
+
|
|
20
25
|
@Composable
|
|
21
26
|
fun useHeaderSearchAnimation(
|
|
27
|
+
opacityAni: Float,
|
|
22
28
|
scrollState: Int,
|
|
29
|
+
headerRightWidth: Dp,
|
|
23
30
|
statusBarHeight: Dp,
|
|
24
|
-
|
|
25
|
-
searchWidth: Int,
|
|
26
|
-
headerRightWidth: Dp
|
|
31
|
+
isBack: Boolean
|
|
27
32
|
): HeaderAnimations {
|
|
28
|
-
val
|
|
29
|
-
|
|
30
|
-
)
|
|
33
|
+
val screenWidth = getScreenDimensions().width
|
|
34
|
+
val leftPosition = if (isBack) (BACK_WIDTH + 20).dp else 20.dp
|
|
35
|
+
val searchWidth = screenWidth - (SCREEN_PADDING * 2)
|
|
31
36
|
|
|
32
37
|
val backgroundSearch by animateColorAsState(
|
|
33
38
|
targetValue = animateColor(
|
|
34
39
|
AppTheme.current.colors.background.default,
|
|
35
40
|
Colors.black_01,
|
|
36
41
|
opacityAni
|
|
37
|
-
)
|
|
42
|
+
),
|
|
38
43
|
)
|
|
39
44
|
|
|
40
45
|
val animatedTranslateX by animateFloatAsState(
|
|
41
|
-
targetValue = (scrollState / 52f).coerceIn(0f, 1f) * (leftPosition.value - 12) + 12
|
|
46
|
+
targetValue = (scrollState / 52f).coerceIn(0f, 1f) * (leftPosition.value - 12) + 12,
|
|
42
47
|
)
|
|
43
48
|
|
|
44
49
|
val animatedWidth by animateFloatAsState(
|
|
45
|
-
targetValue = (scrollState / 52f).coerceIn(
|
|
46
|
-
|
|
50
|
+
targetValue = (scrollState / 52f).coerceIn(
|
|
51
|
+
0f,
|
|
52
|
+
1f
|
|
53
|
+
) * ((searchWidth - leftPosition.value - headerRightWidth.value + 12) - searchWidth) + searchWidth,
|
|
47
54
|
)
|
|
48
55
|
|
|
49
56
|
val animatedHeight by animateFloatAsState(
|
|
50
|
-
targetValue = (1 - (scrollState / 52f).coerceIn(
|
|
51
|
-
|
|
57
|
+
targetValue = (1 - (scrollState / 52f).coerceIn(
|
|
58
|
+
0f,
|
|
59
|
+
1f
|
|
60
|
+
)) * (statusBarHeight.value + 94 - (statusBarHeight.value + 52)) + (statusBarHeight.value + 52),
|
|
52
61
|
)
|
|
53
|
-
|
|
54
62
|
return HeaderAnimations(
|
|
55
63
|
opacity = opacityAni,
|
|
56
64
|
backgroundSearch = backgroundSearch,
|
|
@@ -35,6 +35,7 @@ import vn.momo.kits.const.AppTheme
|
|
|
35
35
|
import vn.momo.kits.const.Radius
|
|
36
36
|
import vn.momo.kits.const.Spacing
|
|
37
37
|
import vn.momo.kits.const.Typography
|
|
38
|
+
import vn.momo.kits.modifier.setAutomationId
|
|
38
39
|
import vn.momo.kits.utils.ifNotNull
|
|
39
40
|
|
|
40
41
|
data class PopupAction(
|
|
@@ -95,12 +96,12 @@ fun PopupNotify(
|
|
|
95
96
|
callback?.invoke()
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
Box(Modifier.
|
|
99
|
-
|
|
100
|
-
}, contentAlignment = Alignment.TopEnd) {
|
|
99
|
+
Box(Modifier.setAutomationId("popup_notify")
|
|
100
|
+
, contentAlignment = Alignment.TopEnd) {
|
|
101
101
|
Column(
|
|
102
102
|
modifier = Modifier
|
|
103
103
|
.fillMaxWidth()
|
|
104
|
+
.padding(horizontal = 12.dp)
|
|
104
105
|
.clip(RoundedCornerShape(Radius.L))
|
|
105
106
|
.background(
|
|
106
107
|
AppTheme.current.colors.background.surface,
|
|
@@ -115,7 +116,7 @@ fun PopupNotify(
|
|
|
115
116
|
)
|
|
116
117
|
|
|
117
118
|
Column(modifier = Modifier.padding(Spacing.XL)) {
|
|
118
|
-
Text(style = Typography.titleXs, maxLines = 2, text = title)
|
|
119
|
+
Text(style = Typography.titleXs, maxLines = 2, text = title, modifier = Modifier.setAutomationId("title_popup_permission"))
|
|
119
120
|
content(Modifier.padding(top = Spacing.S))
|
|
120
121
|
if (error.isNotEmpty()) {
|
|
121
122
|
Text(
|
|
@@ -142,7 +143,7 @@ fun PopupNotify(
|
|
|
142
143
|
Modifier
|
|
143
144
|
.width(22.dp)
|
|
144
145
|
.height(22.dp)
|
|
145
|
-
.offset(x = Spacing.
|
|
146
|
+
.offset(x = Spacing.M / 2, y = -Spacing.M)
|
|
146
147
|
.background(
|
|
147
148
|
color = AppTheme.current.colors.text.default,
|
|
148
149
|
shape = RoundedCornerShape(Radius.M)
|
|
@@ -164,9 +165,7 @@ fun PopupNotify(
|
|
|
164
165
|
source = "navigation_close",
|
|
165
166
|
color = AppTheme.current.colors.background.surface,
|
|
166
167
|
size = 16.dp,
|
|
167
|
-
modifier = Modifier.
|
|
168
|
-
testTag = "ic_popup_close"
|
|
169
|
-
}
|
|
168
|
+
modifier = Modifier.setAutomationId("ic_popup_close")
|
|
170
169
|
)
|
|
171
170
|
}
|
|
172
171
|
}
|
|
@@ -233,9 +232,7 @@ fun renderRow(
|
|
|
233
232
|
},
|
|
234
233
|
title = it.title,
|
|
235
234
|
type = ButtonType.TEXT,
|
|
236
|
-
modifier = Modifier.
|
|
237
|
-
testTag = "btn_popup_cancel"
|
|
238
|
-
}
|
|
235
|
+
modifier = Modifier.setAutomationId("btn_popup_cancel")
|
|
239
236
|
)
|
|
240
237
|
}
|
|
241
238
|
Spacer(modifier = Modifier.width(Spacing.S))
|
|
@@ -248,9 +245,7 @@ fun renderRow(
|
|
|
248
245
|
onAction(primary?.onPress)
|
|
249
246
|
},
|
|
250
247
|
title = primary?.title ?: "",
|
|
251
|
-
modifier = Modifier.
|
|
252
|
-
testTag = "btn_popup_allow"
|
|
253
|
-
}
|
|
248
|
+
modifier = Modifier.setAutomationId("btn_popup_allow")
|
|
254
249
|
)
|
|
255
250
|
}
|
|
256
251
|
}
|
|
@@ -271,9 +266,7 @@ fun renderColumn(
|
|
|
271
266
|
onAction(primary?.onPress)
|
|
272
267
|
},
|
|
273
268
|
title = primary?.title ?: "",
|
|
274
|
-
modifier = Modifier.
|
|
275
|
-
testTag = "btn_popup_allow"
|
|
276
|
-
}
|
|
269
|
+
modifier = Modifier.setAutomationId("btn_popup_allow")
|
|
277
270
|
)
|
|
278
271
|
secondary?.let {
|
|
279
272
|
Spacer(modifier = Modifier.height(Spacing.S))
|
|
@@ -286,9 +279,7 @@ fun renderColumn(
|
|
|
286
279
|
},
|
|
287
280
|
title = it.title,
|
|
288
281
|
type = ButtonType.TEXT,
|
|
289
|
-
modifier = Modifier.
|
|
290
|
-
testTag = "btn_popup_cancel"
|
|
291
|
-
}
|
|
282
|
+
modifier = Modifier.setAutomationId("btn_popup_cancel")
|
|
292
283
|
)
|
|
293
284
|
}
|
|
294
285
|
}
|
|
@@ -49,6 +49,7 @@ public struct PopupDisplay: View {
|
|
|
49
49
|
.padding(.trailing, -Spacing.M )
|
|
50
50
|
.padding(.top, -Spacing.M)
|
|
51
51
|
.zIndex(1)
|
|
52
|
+
.accessibility(identifier: "ic_popup_close")
|
|
52
53
|
|
|
53
54
|
VStack {
|
|
54
55
|
if(!url.isEmpty) {
|
|
@@ -71,6 +72,7 @@ public struct PopupDisplay: View {
|
|
|
71
72
|
.padding(.top, 16)
|
|
72
73
|
.padding(.bottom, 8)
|
|
73
74
|
.lineLimit(2)
|
|
75
|
+
.accessibility(identifier: "title_popup_permission")
|
|
74
76
|
|
|
75
77
|
Text(description)
|
|
76
78
|
.foregroundColor(.black)
|
|
@@ -79,7 +81,7 @@ public struct PopupDisplay: View {
|
|
|
79
81
|
.multilineTextAlignment(.leading)
|
|
80
82
|
.padding(.bottom, 20)
|
|
81
83
|
}
|
|
82
|
-
.frame(maxWidth: .infinity, alignment: .leading)
|
|
84
|
+
.frame(maxWidth: .infinity, alignment: .leading)
|
|
83
85
|
.padding(.horizontal, 24)
|
|
84
86
|
|
|
85
87
|
if buttonDirection == .row {
|
|
@@ -100,7 +102,7 @@ public struct PopupDisplay: View {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
.background(Color.white.cornerRadius(15))
|
|
103
|
-
.padding(.horizontal,
|
|
105
|
+
.padding(.horizontal, 12)
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
// MARK: Internal
|
|
@@ -153,8 +155,9 @@ public struct PopupDisplay: View {
|
|
|
153
155
|
|
|
154
156
|
var RowButtons: some View {
|
|
155
157
|
HStack {
|
|
156
|
-
Button(title: closeButtonTitle, action: onPressCloseButton, type: .secondary, size: .medium)
|
|
158
|
+
Button(title: closeButtonTitle, action: onPressCloseButton, type: .secondary, size: .medium).accessibility(identifier: "btn_popup_cancel")
|
|
157
159
|
Button(title: actionButtonTitle, action: onPressAction, size: .medium)
|
|
160
|
+
.accessibility(identifier: "btn_popup_allow")
|
|
158
161
|
}
|
|
159
162
|
.frame(maxWidth: .infinity, alignment: .center)
|
|
160
163
|
.padding(.horizontal, 24)
|
|
@@ -167,8 +170,9 @@ public struct PopupDisplay: View {
|
|
|
167
170
|
title: actionButtonTitle,
|
|
168
171
|
action: onPressAction,
|
|
169
172
|
size: .medium
|
|
170
|
-
)
|
|
171
|
-
Button(title: closeButtonTitle, action: onPressCloseButton, type: .secondary, size: .medium)
|
|
173
|
+
).accessibility(identifier: "btn_popup_allow")
|
|
174
|
+
Button(title: closeButtonTitle, action: onPressCloseButton, type: .secondary, size: .medium).accessibility(identifier: "btn_popup_cancel")
|
|
175
|
+
|
|
172
176
|
}
|
|
173
177
|
.frame(maxWidth: .infinity, alignment: .trailing)
|
|
174
178
|
.padding(.horizontal, 24)
|