@momo-kits/native-kits 0.113.1-beta.6 → 0.113.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.
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +189 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +70 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +63 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +102 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +27 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +61 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +1 -1
- package/ios/Button/Button.swift +2 -1
- package/ios/Popup/PopupDisplay.swift +10 -14
- package/local.properties +2 -2
- package/package.json +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Components.kt +0 -379
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
package vn.momo.kits.application
|
|
2
|
+
|
|
3
|
+
import androidx.compose.animation.animateColorAsState
|
|
4
|
+
import androidx.compose.foundation.background
|
|
5
|
+
import androidx.compose.foundation.border
|
|
6
|
+
import androidx.compose.foundation.clickable
|
|
7
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
8
|
+
import androidx.compose.foundation.layout.Box
|
|
9
|
+
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
10
|
+
import androidx.compose.foundation.layout.Row
|
|
11
|
+
import androidx.compose.foundation.layout.Spacer
|
|
12
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
13
|
+
import androidx.compose.foundation.layout.height
|
|
14
|
+
import androidx.compose.foundation.layout.padding
|
|
15
|
+
import androidx.compose.foundation.layout.size
|
|
16
|
+
import androidx.compose.foundation.layout.width
|
|
17
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
18
|
+
import androidx.compose.runtime.Composable
|
|
19
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
20
|
+
import androidx.compose.runtime.getValue
|
|
21
|
+
import androidx.compose.runtime.mutableStateOf
|
|
22
|
+
import androidx.compose.runtime.remember
|
|
23
|
+
import androidx.compose.runtime.setValue
|
|
24
|
+
import androidx.compose.runtime.snapshotFlow
|
|
25
|
+
import androidx.compose.ui.Alignment
|
|
26
|
+
import androidx.compose.ui.Modifier
|
|
27
|
+
import androidx.compose.ui.graphics.Color
|
|
28
|
+
import androidx.compose.ui.graphics.graphicsLayer
|
|
29
|
+
import androidx.compose.ui.semantics.semantics
|
|
30
|
+
import androidx.compose.ui.semantics.testTag
|
|
31
|
+
import androidx.compose.ui.unit.dp
|
|
32
|
+
import androidx.compose.ui.zIndex
|
|
33
|
+
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
34
|
+
import kotlinx.coroutines.flow.map
|
|
35
|
+
import vn.momo.kits.components.Icon
|
|
36
|
+
import vn.momo.kits.components.InputSearch
|
|
37
|
+
import vn.momo.kits.components.InputSearchProps
|
|
38
|
+
import vn.momo.kits.const.AppStatusBar
|
|
39
|
+
import vn.momo.kits.const.AppTheme
|
|
40
|
+
import vn.momo.kits.const.Colors
|
|
41
|
+
import vn.momo.kits.const.Spacing
|
|
42
|
+
import vn.momo.kits.modifier.setAutomationId
|
|
43
|
+
import vn.momo.kits.platform.getStatusBarHeight
|
|
44
|
+
|
|
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
|
+
@Composable
|
|
55
|
+
fun Header(
|
|
56
|
+
headerType: HeaderType = HeaderType.DEFAULT,
|
|
57
|
+
titlePosition: TitlePosition,
|
|
58
|
+
title: String,
|
|
59
|
+
headerRight: @Composable (() -> Unit)? = null,
|
|
60
|
+
goBack: (() -> Unit)? = null,
|
|
61
|
+
opacity: Float? = null,
|
|
62
|
+
animatedHeader: AnimatedHeader? = null,
|
|
63
|
+
scrollState: Int = 0,
|
|
64
|
+
inputSearchProps: InputSearchProps? = null,
|
|
65
|
+
useAnimationSearch: Boolean = false
|
|
66
|
+
) {
|
|
67
|
+
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
68
|
+
val tintIconColor = AppTheme.current.colors.text.default
|
|
69
|
+
val backgroundButton = Colors.black_01.copy(alpha = 0.6f)
|
|
70
|
+
val miniAppContext = ApplicationContext.current
|
|
71
|
+
|
|
72
|
+
var colorFraction by remember { mutableStateOf(0f) }
|
|
73
|
+
|
|
74
|
+
LaunchedEffect(scrollState) {
|
|
75
|
+
snapshotFlow { scrollState }
|
|
76
|
+
.map { (it / 50f).coerceIn(0f, 1f) }
|
|
77
|
+
.distinctUntilChanged()
|
|
78
|
+
.collect { fraction -> colorFraction = fraction }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
val backgroundSearch by animateColorAsState(
|
|
82
|
+
targetValue = animateColor(
|
|
83
|
+
Colors.black_01,
|
|
84
|
+
AppTheme.current.colors.background.default,
|
|
85
|
+
colorFraction
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if (headerType != HeaderType.NONE) {
|
|
90
|
+
BoxWithConstraints(
|
|
91
|
+
Modifier.height(statusBarHeight + 52.dp)
|
|
92
|
+
.fillMaxWidth()
|
|
93
|
+
.zIndex(10f),
|
|
94
|
+
contentAlignment = Alignment.BottomCenter
|
|
95
|
+
) {
|
|
96
|
+
Row(
|
|
97
|
+
modifier = Modifier.height(52.dp)
|
|
98
|
+
.fillMaxWidth()
|
|
99
|
+
.padding(horizontal = Spacing.M),
|
|
100
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
101
|
+
horizontalArrangement = Arrangement.SpaceBetween
|
|
102
|
+
) {
|
|
103
|
+
Box {
|
|
104
|
+
if (goBack != null) {
|
|
105
|
+
Box(
|
|
106
|
+
modifier = Modifier
|
|
107
|
+
.size(28.dp)
|
|
108
|
+
.then(
|
|
109
|
+
Modifier.border(
|
|
110
|
+
0.2.dp,
|
|
111
|
+
Colors.black_20.copy(alpha = 0.2f),
|
|
112
|
+
RoundedCornerShape(100)
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
.background(
|
|
116
|
+
backgroundButton,
|
|
117
|
+
RoundedCornerShape(100)
|
|
118
|
+
)
|
|
119
|
+
.clickable(
|
|
120
|
+
onClick = goBack
|
|
121
|
+
)
|
|
122
|
+
.padding(Spacing.XS)
|
|
123
|
+
.setAutomationId("btn_navigation_back"),
|
|
124
|
+
contentAlignment = Alignment.Center
|
|
125
|
+
) {
|
|
126
|
+
Icon(
|
|
127
|
+
source = "arrow-back",
|
|
128
|
+
color = Colors.black_20,
|
|
129
|
+
size = 20.dp,
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (inputSearchProps == null && miniAppContext != null) {
|
|
136
|
+
Box(Modifier.graphicsLayer {
|
|
137
|
+
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
138
|
+
}) {
|
|
139
|
+
headerRight?.invoke()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Title
|
|
145
|
+
Row(
|
|
146
|
+
modifier = Modifier.height(52.dp)
|
|
147
|
+
.fillMaxWidth()
|
|
148
|
+
.padding(horizontal = Spacing.M),
|
|
149
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
150
|
+
) {
|
|
151
|
+
if (goBack != null && titlePosition == TitlePosition.LEFT) {
|
|
152
|
+
Spacer(Modifier.width(40.dp))
|
|
153
|
+
}
|
|
154
|
+
if (inputSearchProps != null && !useAnimationSearch) {
|
|
155
|
+
InputSearch(inputSearchProps = inputSearchProps.copy(backgroundColor = backgroundSearch))
|
|
156
|
+
} else {
|
|
157
|
+
Box(
|
|
158
|
+
Modifier.weight(1f).graphicsLayer {
|
|
159
|
+
alpha = if (useAnimationSearch && inputSearchProps != null) {
|
|
160
|
+
1f - (opacity ?: 1f)
|
|
161
|
+
} else {
|
|
162
|
+
if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
|
|
166
|
+
) {
|
|
167
|
+
HeaderTitle(
|
|
168
|
+
title = title,
|
|
169
|
+
color = tintIconColor,
|
|
170
|
+
modifier = Modifier.semantics {
|
|
171
|
+
testTag = "title_navigation_header"
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
fun animateColor(start: Color, stop: Color, fraction: Float): Color {
|
|
183
|
+
return Color(
|
|
184
|
+
red = start.red + fraction * (stop.red - start.red),
|
|
185
|
+
green = start.green + fraction * (stop.green - start.green),
|
|
186
|
+
blue = start.blue + fraction * (stop.blue - start.blue),
|
|
187
|
+
alpha = start.alpha + fraction * (stop.alpha - start.alpha)
|
|
188
|
+
)
|
|
189
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
package vn.momo.kits.application
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Box
|
|
4
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import androidx.compose.ui.Modifier
|
|
7
|
+
import androidx.compose.ui.graphics.Color
|
|
8
|
+
import androidx.compose.ui.unit.Dp
|
|
9
|
+
import androidx.compose.ui.unit.dp
|
|
10
|
+
import vn.momo.kits.components.InputSearchProps
|
|
11
|
+
import vn.momo.kits.const.AppStatusBar
|
|
12
|
+
import vn.momo.kits.const.AppTheme
|
|
13
|
+
import vn.momo.kits.platform.getScreenDimensions
|
|
14
|
+
import vn.momo.kits.platform.getStatusBarHeight
|
|
15
|
+
|
|
16
|
+
private const val SCREEN_PADDING = 12
|
|
17
|
+
private const val BACK_WIDTH = 28
|
|
18
|
+
|
|
19
|
+
@Composable
|
|
20
|
+
fun HeaderBackground(
|
|
21
|
+
isBack: Boolean = true,
|
|
22
|
+
headerType: HeaderType = HeaderType.DEFAULT,
|
|
23
|
+
scrollState: Int,
|
|
24
|
+
inputSearchProps: InputSearchProps? = null,
|
|
25
|
+
headerRightWidth: Dp = 0.dp,
|
|
26
|
+
useAnimationSearch: Boolean = false
|
|
27
|
+
) {
|
|
28
|
+
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
|
+
|
|
33
|
+
val animations = useHeaderSearchAnimation(
|
|
34
|
+
scrollState = scrollState,
|
|
35
|
+
statusBarHeight = statusBarHeight,
|
|
36
|
+
leftPosition = leftPosition,
|
|
37
|
+
searchWidth = searchWidth,
|
|
38
|
+
headerRightWidth = headerRightWidth
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
val backgroundColor = if (scrollState == 0) {
|
|
42
|
+
Color.Transparent
|
|
43
|
+
} else {
|
|
44
|
+
AppTheme.current.colors.background.surface
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
when (headerType) {
|
|
48
|
+
HeaderType.DEFAULT -> {
|
|
49
|
+
val height = statusBarHeight + 52.dp
|
|
50
|
+
HeaderDefault(
|
|
51
|
+
height = height,
|
|
52
|
+
animations = animations,
|
|
53
|
+
backgroundColor = backgroundColor
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
HeaderType.EXTENDED -> {
|
|
58
|
+
HeaderExtended(
|
|
59
|
+
animations = animations,
|
|
60
|
+
inputSearchProps = inputSearchProps,
|
|
61
|
+
useAnimationSearch = useAnimationSearch,
|
|
62
|
+
backgroundColor = backgroundColor
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
else -> {
|
|
67
|
+
Box(modifier = Modifier.fillMaxWidth())
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -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
|
+
height: Dp,
|
|
25
|
+
backgroundColor: Color,
|
|
26
|
+
animations: HeaderAnimations
|
|
27
|
+
) {
|
|
28
|
+
Box(
|
|
29
|
+
modifier = Modifier.fillMaxWidth().height(height)
|
|
30
|
+
.background(backgroundColor)
|
|
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(animations.opacity)
|
|
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,102 @@
|
|
|
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.Alignment
|
|
13
|
+
import androidx.compose.ui.Modifier
|
|
14
|
+
import androidx.compose.ui.draw.alpha
|
|
15
|
+
import androidx.compose.ui.geometry.Offset
|
|
16
|
+
import androidx.compose.ui.graphics.Brush
|
|
17
|
+
import androidx.compose.ui.graphics.Color
|
|
18
|
+
import androidx.compose.ui.layout.ContentScale
|
|
19
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
20
|
+
import androidx.compose.ui.unit.dp
|
|
21
|
+
import vn.momo.kits.components.Image
|
|
22
|
+
import vn.momo.kits.components.InputSearch
|
|
23
|
+
import vn.momo.kits.components.InputSearchProps
|
|
24
|
+
import vn.momo.kits.components.Options
|
|
25
|
+
import vn.momo.kits.const.AppTheme
|
|
26
|
+
import vn.momo.kits.const.Radius
|
|
27
|
+
import vn.momo.kits.const.Spacing
|
|
28
|
+
|
|
29
|
+
@Composable
|
|
30
|
+
fun HeaderExtended(
|
|
31
|
+
animations: HeaderAnimations,
|
|
32
|
+
inputSearchProps: InputSearchProps? = null,
|
|
33
|
+
useAnimationSearch: Boolean = false,
|
|
34
|
+
backgroundColor: Color = Color.Transparent
|
|
35
|
+
){
|
|
36
|
+
Box(
|
|
37
|
+
modifier = Modifier.fillMaxWidth().height(animations.height.dp)
|
|
38
|
+
) {
|
|
39
|
+
Box(
|
|
40
|
+
modifier = Modifier
|
|
41
|
+
.fillMaxWidth()
|
|
42
|
+
.height(154.dp)
|
|
43
|
+
.alpha(animations.opacity)
|
|
44
|
+
.background(
|
|
45
|
+
Brush.linearGradient(
|
|
46
|
+
colors = listOf(
|
|
47
|
+
Color(0xFFFDCADE),
|
|
48
|
+
Color(0x00FDCADE)
|
|
49
|
+
),
|
|
50
|
+
start = Offset(0f, 0f),
|
|
51
|
+
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
) {
|
|
55
|
+
if (AppTheme.current.assets.headerBackground != null) {
|
|
56
|
+
Box(
|
|
57
|
+
modifier = Modifier
|
|
58
|
+
.fillMaxWidth()
|
|
59
|
+
.background(backgroundColor)
|
|
60
|
+
) {
|
|
61
|
+
Image(
|
|
62
|
+
loading = false,
|
|
63
|
+
source = AppTheme.current.assets.headerBackground!!,
|
|
64
|
+
modifier = Modifier.fillMaxWidth().height(154.dp),
|
|
65
|
+
options = Options(
|
|
66
|
+
contentScale = ContentScale.FillWidth
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (inputSearchProps != null && useAnimationSearch) {
|
|
74
|
+
Box(
|
|
75
|
+
modifier = Modifier
|
|
76
|
+
.height(52.dp)
|
|
77
|
+
.offset(
|
|
78
|
+
x = animations.translateX.dp
|
|
79
|
+
)
|
|
80
|
+
.padding(vertical = Spacing.S)
|
|
81
|
+
.align(Alignment.BottomStart)
|
|
82
|
+
) {
|
|
83
|
+
Box(
|
|
84
|
+
modifier = Modifier
|
|
85
|
+
.width(animations.width.dp)
|
|
86
|
+
.background(
|
|
87
|
+
color = animations.backgroundSearch,
|
|
88
|
+
shape = RoundedCornerShape(Radius.XL)
|
|
89
|
+
)
|
|
90
|
+
) {
|
|
91
|
+
InputSearch(
|
|
92
|
+
inputSearchProps = inputSearchProps.copy(
|
|
93
|
+
showButtonText = false,
|
|
94
|
+
backgroundColor = Color.Transparent
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package vn.momo.kits.application
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.ui.Modifier
|
|
5
|
+
import androidx.compose.ui.graphics.Color
|
|
6
|
+
import androidx.compose.ui.text.style.TextAlign
|
|
7
|
+
import androidx.compose.ui.zIndex
|
|
8
|
+
import vn.momo.kits.components.Text
|
|
9
|
+
import vn.momo.kits.const.Typography
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@Composable
|
|
13
|
+
fun HeaderTitle(
|
|
14
|
+
title: String = "",
|
|
15
|
+
modifier: Modifier = Modifier,
|
|
16
|
+
textAlign: TextAlign = TextAlign.Start,
|
|
17
|
+
color: Color? = null,
|
|
18
|
+
) {
|
|
19
|
+
Text(
|
|
20
|
+
modifier = Modifier.then(modifier).zIndex(1f),
|
|
21
|
+
text = title,
|
|
22
|
+
textAlign = textAlign,
|
|
23
|
+
style = Typography.actionS,
|
|
24
|
+
color = color,
|
|
25
|
+
maxLines = 1
|
|
26
|
+
)
|
|
27
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package vn.momo.kits.application
|
|
2
|
+
|
|
3
|
+
import androidx.compose.animation.animateColorAsState
|
|
4
|
+
import androidx.compose.animation.core.animateFloatAsState
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import androidx.compose.ui.graphics.Color
|
|
7
|
+
import androidx.compose.ui.unit.Dp
|
|
8
|
+
import vn.momo.kits.const.AppTheme
|
|
9
|
+
import vn.momo.kits.const.Colors
|
|
10
|
+
import androidx.compose.runtime.getValue
|
|
11
|
+
|
|
12
|
+
data class HeaderAnimations(
|
|
13
|
+
val opacity: Float,
|
|
14
|
+
val backgroundSearch: Color,
|
|
15
|
+
val translateX: Float,
|
|
16
|
+
val width: Float,
|
|
17
|
+
val height: Float
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
@Composable
|
|
21
|
+
fun useHeaderSearchAnimation(
|
|
22
|
+
scrollState: Int,
|
|
23
|
+
statusBarHeight: Dp,
|
|
24
|
+
leftPosition: Dp,
|
|
25
|
+
searchWidth: Int,
|
|
26
|
+
headerRightWidth: Dp
|
|
27
|
+
): HeaderAnimations {
|
|
28
|
+
val opacityAni by animateFloatAsState(
|
|
29
|
+
targetValue = (1 - (scrollState / 52f)).coerceIn(0f, 1f)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
val backgroundSearch by animateColorAsState(
|
|
33
|
+
targetValue = animateColor(
|
|
34
|
+
AppTheme.current.colors.background.default,
|
|
35
|
+
Colors.black_01,
|
|
36
|
+
opacityAni
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
val animatedTranslateX by animateFloatAsState(
|
|
41
|
+
targetValue = (scrollState / 52f).coerceIn(0f, 1f) * (leftPosition.value - 12) + 12
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
val animatedWidth by animateFloatAsState(
|
|
45
|
+
targetValue = (scrollState / 52f).coerceIn(0f, 1f) *
|
|
46
|
+
((searchWidth - leftPosition.value - headerRightWidth.value + 12) - searchWidth) + searchWidth
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
val animatedHeight by animateFloatAsState(
|
|
50
|
+
targetValue = (1 - (scrollState / 52f).coerceIn(0f, 1f)) *
|
|
51
|
+
(statusBarHeight.value + 94 - (statusBarHeight.value + 52)) + (statusBarHeight.value + 52)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return HeaderAnimations(
|
|
55
|
+
opacity = opacityAni,
|
|
56
|
+
backgroundSearch = backgroundSearch,
|
|
57
|
+
translateX = animatedTranslateX,
|
|
58
|
+
width = animatedWidth,
|
|
59
|
+
height = animatedHeight
|
|
60
|
+
)
|
|
61
|
+
}
|
|
@@ -115,7 +115,7 @@ fun PopupNotify(
|
|
|
115
115
|
)
|
|
116
116
|
|
|
117
117
|
Column(modifier = Modifier.padding(Spacing.XL)) {
|
|
118
|
-
Text(style = Typography.titleXs, maxLines =
|
|
118
|
+
Text(style = Typography.titleXs, maxLines = 1, text = title)
|
|
119
119
|
content(Modifier.padding(top = Spacing.S))
|
|
120
120
|
if (error.isNotEmpty()) {
|
|
121
121
|
Text(
|
package/ios/Button/Button.swift
CHANGED
|
@@ -98,8 +98,9 @@ private extension View {
|
|
|
98
98
|
case .secondary:
|
|
99
99
|
return AnyView(self
|
|
100
100
|
.background(Colors.card)
|
|
101
|
-
.foregroundColor(Colors.
|
|
101
|
+
.foregroundColor(Colors.text)
|
|
102
102
|
.cornerRadius(8)
|
|
103
|
+
.overlay(RoundedRectangle(cornerRadius: Radius.S).stroke(Colors.black06, lineWidth: 1))
|
|
103
104
|
.padding(2)
|
|
104
105
|
)
|
|
105
106
|
case .outline:
|
|
@@ -43,7 +43,6 @@ public struct PopupDisplay: View {
|
|
|
43
43
|
Image(systemName: "xmark.circle.fill")
|
|
44
44
|
.resizable()
|
|
45
45
|
.frame(width: 16, height: 16)
|
|
46
|
-
.overlay(RoundedRectangle(cornerRadius: Radius.S).stroke(Colors.black01, lineWidth: 1))
|
|
47
46
|
}.foregroundColor(Colors.black20)
|
|
48
47
|
.background(Colors.black01.cornerRadius(8))
|
|
49
48
|
.offset(x: 6, y: -6)
|
|
@@ -53,17 +52,15 @@ public struct PopupDisplay: View {
|
|
|
53
52
|
WebImage(url: URL(string: url), isAnimating: .constant(true))
|
|
54
53
|
.resizable()
|
|
55
54
|
.scaledToFill()
|
|
56
|
-
.frame(maxWidth: .infinity)
|
|
55
|
+
.frame(maxWidth: .infinity, maxHeight: 164)
|
|
57
56
|
.clipShape(RoundedCorner(radius: 8, corners: [.topLeft, .topRight]))
|
|
58
|
-
.aspectRatio(2, contentMode: .fit)
|
|
59
57
|
|
|
60
58
|
VStack(alignment: .leading) {
|
|
61
59
|
Text(title)
|
|
62
60
|
.foregroundColor(.black)
|
|
63
|
-
.font(.
|
|
64
|
-
.padding(.top,
|
|
65
|
-
.padding(.bottom,
|
|
66
|
-
.lineLimit(2)
|
|
61
|
+
.font(.headerText1)
|
|
62
|
+
.padding(.top, 12)
|
|
63
|
+
.padding(.bottom, 24)
|
|
67
64
|
|
|
68
65
|
Text(description)
|
|
69
66
|
.foregroundColor(.black)
|
|
@@ -90,8 +87,10 @@ public struct PopupDisplay: View {
|
|
|
90
87
|
}.clipped()
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
|
-
.background(Color.white.cornerRadius(
|
|
94
|
-
.
|
|
90
|
+
.background(Color.white.cornerRadius(8))
|
|
91
|
+
.shadow(color: .black.opacity(0.08), radius: 2, x: 0, y: 0)
|
|
92
|
+
.shadow(color: .black.opacity(0.16), radius: 24, x: 0, y: 0)
|
|
93
|
+
.padding(.horizontal, 40)
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
// MARK: Internal
|
|
@@ -107,7 +106,7 @@ public struct PopupDisplay: View {
|
|
|
107
106
|
var onClose: () -> Void
|
|
108
107
|
var actionButtonTitle: String
|
|
109
108
|
var closeButtonTitle: String
|
|
110
|
-
|
|
109
|
+
|
|
111
110
|
var RowTextButtons: some View {
|
|
112
111
|
HStack {
|
|
113
112
|
SwiftUI.Button(action: onPressCloseButton) {
|
|
@@ -154,10 +153,7 @@ public struct PopupDisplay: View {
|
|
|
154
153
|
|
|
155
154
|
var ColumnButtons: some View {
|
|
156
155
|
VStack(alignment: .trailing) {
|
|
157
|
-
Button(
|
|
158
|
-
title: actionButtonTitle,
|
|
159
|
-
action: onPressAction
|
|
160
|
-
)
|
|
156
|
+
Button(title: actionButtonTitle, action: onPressAction)
|
|
161
157
|
Button(title: closeButtonTitle, action: onPressCloseButton, type: .secondary)
|
|
162
158
|
}
|
|
163
159
|
.frame(maxWidth: .infinity, alignment: .trailing)
|
package/local.properties
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
# Location of the SDK. This is only used by Gradle.
|
|
5
5
|
# For customization when using a Version Control System, please read the
|
|
6
6
|
# header note.
|
|
7
|
-
#
|
|
8
|
-
sdk.dir=/Users/
|
|
7
|
+
#Sun Mar 02 11:30:14 ICT 2025
|
|
8
|
+
sdk.dir=/Users/nguyenhoangson/Library/Android/sdk
|
package/package.json
CHANGED
|
@@ -1,379 +0,0 @@
|
|
|
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.background
|
|
6
|
-
import androidx.compose.foundation.border
|
|
7
|
-
import androidx.compose.foundation.clickable
|
|
8
|
-
import androidx.compose.foundation.layout.Arrangement
|
|
9
|
-
import androidx.compose.foundation.layout.Box
|
|
10
|
-
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
11
|
-
import androidx.compose.foundation.layout.Row
|
|
12
|
-
import androidx.compose.foundation.layout.Spacer
|
|
13
|
-
import androidx.compose.foundation.layout.fillMaxWidth
|
|
14
|
-
import androidx.compose.foundation.layout.height
|
|
15
|
-
import androidx.compose.foundation.layout.offset
|
|
16
|
-
import androidx.compose.foundation.layout.padding
|
|
17
|
-
import androidx.compose.foundation.layout.size
|
|
18
|
-
import androidx.compose.foundation.layout.width
|
|
19
|
-
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
20
|
-
import androidx.compose.runtime.Composable
|
|
21
|
-
import androidx.compose.runtime.LaunchedEffect
|
|
22
|
-
import androidx.compose.runtime.getValue
|
|
23
|
-
import androidx.compose.runtime.mutableStateOf
|
|
24
|
-
import androidx.compose.runtime.remember
|
|
25
|
-
import androidx.compose.runtime.setValue
|
|
26
|
-
import androidx.compose.runtime.snapshotFlow
|
|
27
|
-
import androidx.compose.ui.Alignment
|
|
28
|
-
import androidx.compose.ui.Modifier
|
|
29
|
-
import androidx.compose.ui.draw.alpha
|
|
30
|
-
import androidx.compose.ui.geometry.Offset
|
|
31
|
-
import androidx.compose.ui.graphics.Brush
|
|
32
|
-
import androidx.compose.ui.graphics.Color
|
|
33
|
-
import androidx.compose.ui.graphics.graphicsLayer
|
|
34
|
-
import androidx.compose.ui.layout.ContentScale
|
|
35
|
-
import androidx.compose.ui.platform.LocalDensity
|
|
36
|
-
import androidx.compose.ui.semantics.semantics
|
|
37
|
-
import androidx.compose.ui.semantics.testTag
|
|
38
|
-
import androidx.compose.ui.text.style.TextAlign
|
|
39
|
-
import androidx.compose.ui.unit.Dp
|
|
40
|
-
import androidx.compose.ui.unit.dp
|
|
41
|
-
import androidx.compose.ui.zIndex
|
|
42
|
-
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
43
|
-
import kotlinx.coroutines.flow.map
|
|
44
|
-
import vn.momo.kits.components.Icon
|
|
45
|
-
import vn.momo.kits.components.Image
|
|
46
|
-
import vn.momo.kits.components.InputSearch
|
|
47
|
-
import vn.momo.kits.components.InputSearchProps
|
|
48
|
-
import vn.momo.kits.components.Options
|
|
49
|
-
import vn.momo.kits.components.Text
|
|
50
|
-
import vn.momo.kits.const.AppStatusBar
|
|
51
|
-
import vn.momo.kits.const.AppTheme
|
|
52
|
-
import vn.momo.kits.const.Colors
|
|
53
|
-
import vn.momo.kits.const.Radius
|
|
54
|
-
import vn.momo.kits.const.Spacing
|
|
55
|
-
import vn.momo.kits.const.Typography
|
|
56
|
-
import vn.momo.kits.modifier.setAutomationId
|
|
57
|
-
import vn.momo.kits.platform.getScreenDimensions
|
|
58
|
-
import vn.momo.kits.platform.getStatusBarHeight
|
|
59
|
-
import vn.momo.kits.utils.bottomBorder
|
|
60
|
-
|
|
61
|
-
enum class TitlePosition {
|
|
62
|
-
LEFT, CENTER,
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private const val SCREEN_PADDING = 12
|
|
66
|
-
private const val BACK_WIDTH = 28
|
|
67
|
-
|
|
68
|
-
data class AnimatedHeader(
|
|
69
|
-
val type: HeaderType = HeaderType.DEFAULT,
|
|
70
|
-
val composable: @Composable (scrollState: Int) -> Unit = {}
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
@Composable
|
|
74
|
-
fun HeaderBackground(
|
|
75
|
-
isBack: Boolean = true,
|
|
76
|
-
headerType: HeaderType = HeaderType.DEFAULT,
|
|
77
|
-
scrollState: Int,
|
|
78
|
-
inputSearchProps: InputSearchProps? = null,
|
|
79
|
-
headerRightWidth: Dp = 0.dp,
|
|
80
|
-
useAnimationSearch: Boolean = false
|
|
81
|
-
) {
|
|
82
|
-
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
83
|
-
val screenWidth = getScreenDimensions().width
|
|
84
|
-
val leftPosition = if (isBack) (BACK_WIDTH + 20).dp else 20.dp
|
|
85
|
-
val searchWidth = screenWidth - (SCREEN_PADDING * 2)
|
|
86
|
-
|
|
87
|
-
val opacityAni by animateFloatAsState(
|
|
88
|
-
targetValue = (1 - (scrollState / 52f)).coerceIn(0f, 1f),
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
val backgroundColor by animateColorAsState(
|
|
92
|
-
targetValue = animateColor(
|
|
93
|
-
Color.Transparent,
|
|
94
|
-
AppTheme.current.colors.background.surface,
|
|
95
|
-
opacityAni
|
|
96
|
-
),
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
val backgroundSearch by animateColorAsState(
|
|
100
|
-
targetValue = animateColor(
|
|
101
|
-
AppTheme.current.colors.background.default,
|
|
102
|
-
Colors.black_01,
|
|
103
|
-
opacityAni
|
|
104
|
-
),
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
val animatedTranslateX by animateFloatAsState(
|
|
108
|
-
targetValue = (scrollState / 52f).coerceIn(0f, 1f) * (leftPosition.value - 12) + 12,
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
val animatedWidth by animateFloatAsState(
|
|
112
|
-
targetValue = (scrollState / 52f).coerceIn(
|
|
113
|
-
0f,
|
|
114
|
-
1f
|
|
115
|
-
) * ((searchWidth - leftPosition.value - headerRightWidth.value + 12) - searchWidth) + searchWidth,
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
val animatedHeight by animateFloatAsState(
|
|
119
|
-
targetValue = (1 - (scrollState / 52f).coerceIn(
|
|
120
|
-
0f,
|
|
121
|
-
1f
|
|
122
|
-
)) * (statusBarHeight.value + 94 - (statusBarHeight.value + 52)) + (statusBarHeight.value + 52),
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
when (headerType) {
|
|
126
|
-
HeaderType.DEFAULT -> {
|
|
127
|
-
val height = statusBarHeight + 52.dp
|
|
128
|
-
Box(
|
|
129
|
-
modifier = Modifier.fillMaxWidth().height(height)
|
|
130
|
-
.background(backgroundColor)
|
|
131
|
-
.bottomBorder(
|
|
132
|
-
strokeWidth = 1.dp,
|
|
133
|
-
color = AppTheme.current.colors.border.default
|
|
134
|
-
)
|
|
135
|
-
) {
|
|
136
|
-
Box(
|
|
137
|
-
modifier = Modifier
|
|
138
|
-
.height(height)
|
|
139
|
-
.fillMaxWidth()
|
|
140
|
-
.alpha(opacityAni)
|
|
141
|
-
.background(
|
|
142
|
-
Brush.linearGradient(
|
|
143
|
-
colors = listOf(
|
|
144
|
-
Color(0xFFFDCADE),
|
|
145
|
-
Color(0x00FDCADE)
|
|
146
|
-
),
|
|
147
|
-
start = Offset(0f, 0f),
|
|
148
|
-
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
149
|
-
)
|
|
150
|
-
)
|
|
151
|
-
)
|
|
152
|
-
if (AppTheme.current.assets.headerBackground != null) {
|
|
153
|
-
Image(
|
|
154
|
-
loading = false,
|
|
155
|
-
source = AppTheme.current.assets.headerBackground!!,
|
|
156
|
-
modifier = Modifier.fillMaxWidth().height(height),
|
|
157
|
-
options = Options(
|
|
158
|
-
contentScale = ContentScale.FillWidth
|
|
159
|
-
)
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
HeaderType.EXTENDED -> {
|
|
166
|
-
Box(
|
|
167
|
-
modifier = Modifier.fillMaxWidth().height(animatedHeight.dp)
|
|
168
|
-
) {
|
|
169
|
-
Box(
|
|
170
|
-
modifier = Modifier
|
|
171
|
-
.fillMaxWidth()
|
|
172
|
-
.height(154.dp)
|
|
173
|
-
.alpha(opacityAni)
|
|
174
|
-
.background(
|
|
175
|
-
Brush.linearGradient(
|
|
176
|
-
colors = listOf(
|
|
177
|
-
Color(0xFFFDCADE),
|
|
178
|
-
Color(0x00FDCADE)
|
|
179
|
-
),
|
|
180
|
-
start = Offset(0f, 0f),
|
|
181
|
-
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
182
|
-
)
|
|
183
|
-
)
|
|
184
|
-
) {
|
|
185
|
-
if (AppTheme.current.assets.headerBackground != null) {
|
|
186
|
-
Box(
|
|
187
|
-
modifier = Modifier
|
|
188
|
-
.fillMaxWidth()
|
|
189
|
-
.background(backgroundColor)
|
|
190
|
-
) {
|
|
191
|
-
Image(
|
|
192
|
-
loading = false,
|
|
193
|
-
source = AppTheme.current.assets.headerBackground!!,
|
|
194
|
-
modifier = Modifier.fillMaxWidth().height(154.dp),
|
|
195
|
-
options = Options(
|
|
196
|
-
contentScale = ContentScale.FillWidth
|
|
197
|
-
)
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (inputSearchProps != null && useAnimationSearch) {
|
|
204
|
-
Box(
|
|
205
|
-
modifier = Modifier
|
|
206
|
-
.height(52.dp)
|
|
207
|
-
.offset(
|
|
208
|
-
x = animatedTranslateX.dp
|
|
209
|
-
)
|
|
210
|
-
.padding(vertical = Spacing.S)
|
|
211
|
-
.align(Alignment.BottomStart)
|
|
212
|
-
) {
|
|
213
|
-
Box(
|
|
214
|
-
modifier = Modifier
|
|
215
|
-
.width(animatedWidth.dp)
|
|
216
|
-
.background(
|
|
217
|
-
color = backgroundSearch,
|
|
218
|
-
shape = RoundedCornerShape(Radius.XL)
|
|
219
|
-
)
|
|
220
|
-
) {
|
|
221
|
-
InputSearch(
|
|
222
|
-
inputSearchProps = inputSearchProps.copy(
|
|
223
|
-
showButtonText = false,
|
|
224
|
-
backgroundColor = Color.Transparent
|
|
225
|
-
)
|
|
226
|
-
)
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
else -> {
|
|
234
|
-
Box(modifier = Modifier.fillMaxWidth())
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
@Composable
|
|
240
|
-
fun Header(
|
|
241
|
-
headerType: HeaderType = HeaderType.DEFAULT,
|
|
242
|
-
titlePosition: TitlePosition,
|
|
243
|
-
title: String,
|
|
244
|
-
headerRight: @Composable (() -> Unit)? = null,
|
|
245
|
-
goBack: (() -> Unit)? = null,
|
|
246
|
-
opacity: Float? = null,
|
|
247
|
-
animatedHeader: AnimatedHeader? = null,
|
|
248
|
-
scrollState: Int = 0,
|
|
249
|
-
inputSearchProps: InputSearchProps? = null,
|
|
250
|
-
useAnimationSearch: Boolean = false
|
|
251
|
-
) {
|
|
252
|
-
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
253
|
-
val tintIconColor = AppTheme.current.colors.text.default
|
|
254
|
-
val backgroundButton = Colors.black_01.copy(alpha = 0.6f)
|
|
255
|
-
val miniAppContext = ApplicationContext.current
|
|
256
|
-
|
|
257
|
-
var colorFraction by remember { mutableStateOf(0f) }
|
|
258
|
-
|
|
259
|
-
LaunchedEffect(scrollState) {
|
|
260
|
-
snapshotFlow { scrollState }
|
|
261
|
-
.map { (it / 50f).coerceIn(0f, 1f) }
|
|
262
|
-
.distinctUntilChanged()
|
|
263
|
-
.collect { fraction -> colorFraction = fraction }
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (headerType != HeaderType.NONE) {
|
|
267
|
-
BoxWithConstraints(
|
|
268
|
-
Modifier.height(statusBarHeight + 52.dp)
|
|
269
|
-
.fillMaxWidth()
|
|
270
|
-
.zIndex(10f),
|
|
271
|
-
contentAlignment = Alignment.BottomCenter
|
|
272
|
-
) {
|
|
273
|
-
Row(
|
|
274
|
-
modifier = Modifier.height(52.dp)
|
|
275
|
-
.fillMaxWidth()
|
|
276
|
-
.padding(horizontal = Spacing.M),
|
|
277
|
-
verticalAlignment = Alignment.CenterVertically,
|
|
278
|
-
horizontalArrangement = Arrangement.SpaceBetween
|
|
279
|
-
) {
|
|
280
|
-
Box {
|
|
281
|
-
if (goBack != null) {
|
|
282
|
-
Box(
|
|
283
|
-
modifier = Modifier
|
|
284
|
-
.size(28.dp)
|
|
285
|
-
.then(
|
|
286
|
-
Modifier.border(
|
|
287
|
-
0.2.dp,
|
|
288
|
-
Colors.black_20.copy(alpha = 0.2f),
|
|
289
|
-
RoundedCornerShape(100)
|
|
290
|
-
)
|
|
291
|
-
)
|
|
292
|
-
.background(
|
|
293
|
-
backgroundButton,
|
|
294
|
-
RoundedCornerShape(100)
|
|
295
|
-
)
|
|
296
|
-
.clickable(
|
|
297
|
-
onClick = goBack
|
|
298
|
-
)
|
|
299
|
-
.padding(Spacing.XS)
|
|
300
|
-
.setAutomationId("btn_navigation_back"),
|
|
301
|
-
contentAlignment = Alignment.Center
|
|
302
|
-
) {
|
|
303
|
-
Icon(
|
|
304
|
-
source = "arrow-back",
|
|
305
|
-
color = Colors.black_20,
|
|
306
|
-
size = 20.dp,
|
|
307
|
-
)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (inputSearchProps == null && miniAppContext != null) {
|
|
313
|
-
Box(Modifier.graphicsLayer {
|
|
314
|
-
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
315
|
-
}) {
|
|
316
|
-
headerRight?.invoke()
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Title
|
|
322
|
-
Row(
|
|
323
|
-
modifier = Modifier.height(52.dp)
|
|
324
|
-
.fillMaxWidth()
|
|
325
|
-
.padding(horizontal = Spacing.M),
|
|
326
|
-
verticalAlignment = Alignment.CenterVertically,
|
|
327
|
-
) {
|
|
328
|
-
if (goBack != null && titlePosition == TitlePosition.LEFT) {
|
|
329
|
-
Spacer(Modifier.width(40.dp))
|
|
330
|
-
} else {
|
|
331
|
-
Box(
|
|
332
|
-
Modifier.weight(1f).graphicsLayer {
|
|
333
|
-
alpha = if (useAnimationSearch && inputSearchProps != null) {
|
|
334
|
-
1f - (opacity ?: 1f)
|
|
335
|
-
} else {
|
|
336
|
-
if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
|
-
contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
|
|
340
|
-
) {
|
|
341
|
-
HeaderTitle(
|
|
342
|
-
title = title,
|
|
343
|
-
color = tintIconColor,
|
|
344
|
-
modifier = Modifier.semantics {
|
|
345
|
-
testTag = "title_navigation_header"
|
|
346
|
-
}
|
|
347
|
-
)
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
@Composable
|
|
356
|
-
fun HeaderTitle(
|
|
357
|
-
title: String = "",
|
|
358
|
-
modifier: Modifier = Modifier,
|
|
359
|
-
textAlign: TextAlign = TextAlign.Start,
|
|
360
|
-
color: Color? = null,
|
|
361
|
-
) {
|
|
362
|
-
Text(
|
|
363
|
-
modifier = Modifier.then(modifier).zIndex(1f),
|
|
364
|
-
text = title,
|
|
365
|
-
textAlign = textAlign,
|
|
366
|
-
style = Typography.actionS,
|
|
367
|
-
color = color,
|
|
368
|
-
maxLines = 1
|
|
369
|
-
)
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
fun animateColor(start: Color, stop: Color, fraction: Float): Color {
|
|
373
|
-
return Color(
|
|
374
|
-
red = start.red + fraction * (stop.red - start.red),
|
|
375
|
-
green = start.green + fraction * (stop.green - start.green),
|
|
376
|
-
blue = start.blue + fraction * (stop.blue - start.blue),
|
|
377
|
-
alpha = start.alpha + fraction * (stop.alpha - start.alpha)
|
|
378
|
-
)
|
|
379
|
-
}
|