@momo-kits/native-kits 0.113.3-beta.1 → 0.113.3-beta.3
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/AnimationSearchInput.kt +58 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +21 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +38 -84
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +6 -40
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +6 -10
- 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(52.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
|
+
}
|
|
@@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier
|
|
|
26
26
|
import androidx.compose.ui.graphics.graphicsLayer
|
|
27
27
|
import androidx.compose.ui.semantics.semantics
|
|
28
28
|
import androidx.compose.ui.semantics.testTag
|
|
29
|
+
import androidx.compose.ui.unit.Dp
|
|
29
30
|
import androidx.compose.ui.unit.dp
|
|
30
31
|
import androidx.compose.ui.zIndex
|
|
31
32
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
@@ -47,10 +48,11 @@ fun Header(
|
|
|
47
48
|
title: String,
|
|
48
49
|
headerRight: @Composable (() -> Unit)? = null,
|
|
49
50
|
goBack: (() -> Unit)? = null,
|
|
50
|
-
opacity: Float
|
|
51
|
+
opacity: Float = 1f,
|
|
51
52
|
animatedHeader: AnimatedHeader? = null,
|
|
52
53
|
scrollState: Int = 0,
|
|
53
54
|
inputSearchProps: InputSearchProps? = null,
|
|
55
|
+
headerRightWidth: Dp = 0.dp,
|
|
54
56
|
useAnimationSearch: Boolean = false
|
|
55
57
|
) {
|
|
56
58
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
@@ -65,6 +67,12 @@ fun Header(
|
|
|
65
67
|
.distinctUntilChanged()
|
|
66
68
|
.collect { fraction -> colorFraction = fraction }
|
|
67
69
|
}
|
|
70
|
+
val animations = useHeaderSearchAnimation(
|
|
71
|
+
opacityAni = opacity,
|
|
72
|
+
scrollState = scrollState,
|
|
73
|
+
headerRightWidth = headerRightWidth,
|
|
74
|
+
isBack = goBack != null
|
|
75
|
+
)
|
|
68
76
|
|
|
69
77
|
val backgroundSearch = animateColor(
|
|
70
78
|
Colors.black_01,
|
|
@@ -72,6 +80,9 @@ fun Header(
|
|
|
72
80
|
colorFraction
|
|
73
81
|
)
|
|
74
82
|
|
|
83
|
+
val searchAnimationEnable =
|
|
84
|
+
inputSearchProps != null && useAnimationSearch && headerType == HeaderType.EXTENDED
|
|
85
|
+
|
|
75
86
|
if (headerType != HeaderType.NONE) {
|
|
76
87
|
BoxWithConstraints(
|
|
77
88
|
Modifier.height(statusBarHeight + 52.dp)
|
|
@@ -120,7 +131,7 @@ fun Header(
|
|
|
120
131
|
|
|
121
132
|
if (useAnimationSearch || inputSearchProps == null) {
|
|
122
133
|
Box(Modifier.graphicsLayer {
|
|
123
|
-
alpha = if (animatedHeader !== null) opacity
|
|
134
|
+
alpha = if (animatedHeader !== null) opacity else 1f
|
|
124
135
|
}) {
|
|
125
136
|
headerRight?.invoke()
|
|
126
137
|
}
|
|
@@ -142,15 +153,10 @@ fun Header(
|
|
|
142
153
|
} else {
|
|
143
154
|
Box(
|
|
144
155
|
Modifier.weight(1f).graphicsLayer {
|
|
145
|
-
alpha = if (
|
|
146
|
-
1f - (opacity ?: 1f)
|
|
147
|
-
} else {
|
|
148
|
-
if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
149
|
-
}
|
|
156
|
+
alpha = if (searchAnimationEnable) 1f - (opacity) else 1f
|
|
150
157
|
},
|
|
151
158
|
contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
|
|
152
159
|
) {
|
|
153
|
-
|
|
154
160
|
HeaderTitle(
|
|
155
161
|
title = title,
|
|
156
162
|
color = tintIconColor,
|
|
@@ -161,6 +167,13 @@ fun Header(
|
|
|
161
167
|
}
|
|
162
168
|
}
|
|
163
169
|
}
|
|
170
|
+
|
|
171
|
+
if (searchAnimationEnable) {
|
|
172
|
+
AnimationSearchInput(
|
|
173
|
+
animations = animations,
|
|
174
|
+
inputSearchProps = inputSearchProps!!
|
|
175
|
+
)
|
|
176
|
+
}
|
|
164
177
|
}
|
|
165
178
|
}
|
|
166
179
|
}
|
|
@@ -8,9 +8,6 @@ import androidx.compose.runtime.Composable
|
|
|
8
8
|
import androidx.compose.runtime.getValue
|
|
9
9
|
import androidx.compose.ui.Modifier
|
|
10
10
|
import androidx.compose.ui.graphics.Color
|
|
11
|
-
import androidx.compose.ui.unit.Dp
|
|
12
|
-
import androidx.compose.ui.unit.dp
|
|
13
|
-
import vn.momo.kits.components.InputSearchProps
|
|
14
11
|
import vn.momo.kits.const.AppStatusBar
|
|
15
12
|
import vn.momo.kits.const.AppTheme
|
|
16
13
|
import vn.momo.kits.platform.getStatusBarHeight
|
|
@@ -35,12 +32,8 @@ fun animateColor(start: Color, stop: Color, fraction: Float): Color {
|
|
|
35
32
|
|
|
36
33
|
@Composable
|
|
37
34
|
fun HeaderBackground(
|
|
38
|
-
isBack: Boolean = true,
|
|
39
35
|
headerType: HeaderType = HeaderType.DEFAULT,
|
|
40
36
|
scrollState: Int,
|
|
41
|
-
inputSearchProps: InputSearchProps? = null,
|
|
42
|
-
headerRightWidth: Dp = 0.dp,
|
|
43
|
-
useAnimationSearch: Boolean = false
|
|
44
37
|
) {
|
|
45
38
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
46
39
|
|
|
@@ -66,12 +59,7 @@ fun HeaderBackground(
|
|
|
66
59
|
|
|
67
60
|
HeaderType.EXTENDED -> {
|
|
68
61
|
HeaderExtended(
|
|
69
|
-
scrollState = scrollState,
|
|
70
|
-
inputSearchProps = inputSearchProps,
|
|
71
|
-
headerRightWidth = headerRightWidth,
|
|
72
|
-
useAnimationSearch = useAnimationSearch,
|
|
73
62
|
opacityAni = opacityAni,
|
|
74
|
-
isBack = isBack,
|
|
75
63
|
statusBarHeight = statusBarHeight,
|
|
76
64
|
backgroundColor = backgroundColor,
|
|
77
65
|
)
|
|
@@ -37,100 +37,54 @@ import vn.momo.kits.utils.bottomBorder
|
|
|
37
37
|
@Composable
|
|
38
38
|
fun HeaderExtended(
|
|
39
39
|
opacityAni: Float,
|
|
40
|
-
inputSearchProps: InputSearchProps?,
|
|
41
|
-
useAnimationSearch: Boolean = true,
|
|
42
|
-
scrollState: Int,
|
|
43
|
-
headerRightWidth: Dp,
|
|
44
|
-
isBack: Boolean,
|
|
45
40
|
statusBarHeight: Dp,
|
|
46
41
|
backgroundColor: Color
|
|
47
42
|
) {
|
|
48
|
-
val animations = useHeaderSearchAnimation(
|
|
49
|
-
opacityAni = opacityAni,
|
|
50
|
-
scrollState = scrollState,
|
|
51
|
-
headerRightWidth = headerRightWidth,
|
|
52
|
-
statusBarHeight = statusBarHeight,
|
|
53
|
-
isBack = isBack
|
|
54
|
-
)
|
|
55
|
-
|
|
56
43
|
Box(
|
|
57
|
-
modifier = Modifier
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
Color(0x00FDCADE)
|
|
70
|
-
),
|
|
71
|
-
start = Offset(0f, 0f),
|
|
72
|
-
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
73
|
-
)
|
|
74
|
-
)
|
|
75
|
-
) {
|
|
76
|
-
if (AppTheme.current.assets.headerBackground != null) {
|
|
77
|
-
Box(
|
|
78
|
-
modifier = Modifier
|
|
79
|
-
.fillMaxWidth()
|
|
80
|
-
.background(backgroundColor)
|
|
81
|
-
) {
|
|
82
|
-
Image(
|
|
83
|
-
loading = false,
|
|
84
|
-
source = AppTheme.current.assets.headerBackground!!,
|
|
85
|
-
modifier = Modifier.fillMaxWidth().height(154.dp),
|
|
86
|
-
options = Options(
|
|
87
|
-
contentScale = ContentScale.FillWidth
|
|
88
|
-
)
|
|
89
|
-
)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
Box(
|
|
95
|
-
modifier = Modifier
|
|
96
|
-
.fillMaxWidth()
|
|
97
|
-
.alpha(1f - opacityAni)
|
|
98
|
-
.height(statusBarHeight + 52.dp)
|
|
99
|
-
.background(
|
|
100
|
-
AppTheme.current.colors.background.surface
|
|
101
|
-
)
|
|
102
|
-
.bottomBorder(
|
|
103
|
-
strokeWidth = 1.dp,
|
|
104
|
-
color = AppTheme.current.colors.border.default
|
|
44
|
+
modifier = Modifier
|
|
45
|
+
.fillMaxWidth()
|
|
46
|
+
.height(154.dp)
|
|
47
|
+
.alpha(opacityAni)
|
|
48
|
+
.background(
|
|
49
|
+
Brush.linearGradient(
|
|
50
|
+
colors = listOf(
|
|
51
|
+
Color(0xFFFDCADE),
|
|
52
|
+
Color(0x00FDCADE)
|
|
53
|
+
),
|
|
54
|
+
start = Offset(0f, 0f),
|
|
55
|
+
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
105
56
|
)
|
|
106
|
-
|
|
107
|
-
|
|
57
|
+
)
|
|
58
|
+
) {
|
|
59
|
+
if (AppTheme.current.assets.headerBackground != null) {
|
|
108
60
|
Box(
|
|
109
61
|
modifier = Modifier
|
|
110
|
-
.
|
|
111
|
-
.
|
|
112
|
-
x = animations.translateX.dp
|
|
113
|
-
)
|
|
114
|
-
.padding(vertical = Spacing.S)
|
|
115
|
-
.align(Alignment.BottomStart)
|
|
116
|
-
.zIndex(1f)
|
|
62
|
+
.fillMaxWidth()
|
|
63
|
+
.background(backgroundColor)
|
|
117
64
|
) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
125
|
-
) {
|
|
126
|
-
InputSearch(
|
|
127
|
-
inputSearchProps = inputSearchProps.copy(
|
|
128
|
-
showButtonText = false,
|
|
129
|
-
backgroundColor = Color.Transparent
|
|
130
|
-
)
|
|
65
|
+
Image(
|
|
66
|
+
loading = false,
|
|
67
|
+
source = AppTheme.current.assets.headerBackground!!,
|
|
68
|
+
modifier = Modifier.fillMaxWidth().height(154.dp),
|
|
69
|
+
options = Options(
|
|
70
|
+
contentScale = ContentScale.FillWidth
|
|
131
71
|
)
|
|
132
|
-
|
|
72
|
+
)
|
|
133
73
|
}
|
|
134
74
|
}
|
|
135
75
|
}
|
|
76
|
+
|
|
77
|
+
Box(
|
|
78
|
+
modifier = Modifier
|
|
79
|
+
.fillMaxWidth()
|
|
80
|
+
.alpha(1f - opacityAni)
|
|
81
|
+
.height(statusBarHeight + 52.dp)
|
|
82
|
+
.background(
|
|
83
|
+
AppTheme.current.colors.background.surface
|
|
84
|
+
)
|
|
85
|
+
.bottomBorder(
|
|
86
|
+
strokeWidth = 1.dp,
|
|
87
|
+
color = AppTheme.current.colors.border.default
|
|
88
|
+
)
|
|
89
|
+
)
|
|
136
90
|
}
|
|
@@ -64,8 +64,6 @@ fun Screen(
|
|
|
64
64
|
footer: @Composable (() -> Unit)? = null,
|
|
65
65
|
headerRight: @Composable (() -> Unit)? = { HeaderRight() },
|
|
66
66
|
fabProps: FabProps? = null,
|
|
67
|
-
animatedHeader: AnimatedHeader? = null,
|
|
68
|
-
layoutOffset: Dp = 56.dp,
|
|
69
67
|
inputSearchProps: InputSearchProps? = null,
|
|
70
68
|
useAnimationSearch: Boolean = false,
|
|
71
69
|
headerRightWidth: Dp = 0.dp,
|
|
@@ -88,49 +86,23 @@ fun Screen(
|
|
|
88
86
|
targetValue = ((scrollState.value / 52f)).coerceIn(0f, 1f),
|
|
89
87
|
)
|
|
90
88
|
|
|
91
|
-
val headerAnimated =
|
|
92
|
-
@Composable {
|
|
93
|
-
animatedHeader?.composable?.invoke(scrollState.value)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
89
|
Box(
|
|
97
90
|
Modifier.fillMaxSize()
|
|
98
91
|
.background(backgroundColor ?: AppTheme.current.colors.background.default)
|
|
99
92
|
) {
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
inputSearchProps= inputSearchProps,
|
|
106
|
-
useAnimationSearch = useAnimationSearch,
|
|
107
|
-
headerRightWidth = headerRightWidth
|
|
108
|
-
)
|
|
109
|
-
} else {
|
|
110
|
-
Box(
|
|
111
|
-
Modifier.zIndex(2f)
|
|
112
|
-
.background(Color.White.copy(alpha = opacity))
|
|
113
|
-
.graphicsLayer { alpha = opacity }
|
|
114
|
-
) {
|
|
115
|
-
HeaderBackground(
|
|
116
|
-
isBack = isBack,
|
|
117
|
-
headerType = headerType,
|
|
118
|
-
scrollState = scrollState.value,
|
|
119
|
-
inputSearchProps= inputSearchProps,
|
|
120
|
-
useAnimationSearch = useAnimationSearch,
|
|
121
|
-
headerRightWidth = headerRightWidth
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
94
|
+
HeaderBackground(
|
|
95
|
+
headerType = headerType,
|
|
96
|
+
scrollState = scrollState.value,
|
|
97
|
+
)
|
|
126
98
|
Header(
|
|
127
99
|
headerType = headerType,
|
|
128
100
|
title = title,
|
|
129
101
|
titlePosition = titlePosition,
|
|
130
102
|
headerRight = headerRight,
|
|
103
|
+
headerRightWidth = headerRightWidth,
|
|
131
104
|
goBack = goBack,
|
|
132
105
|
opacity = opacity,
|
|
133
|
-
animatedHeader = animatedHeader,
|
|
134
106
|
inputSearchProps = inputSearchProps,
|
|
135
107
|
scrollState = scrollState.value,
|
|
136
108
|
useAnimationSearch = useAnimationSearch,
|
|
@@ -138,7 +110,7 @@ fun Screen(
|
|
|
138
110
|
|
|
139
111
|
Column(
|
|
140
112
|
modifier = Modifier.fillMaxSize()
|
|
141
|
-
.padding(top = if (
|
|
113
|
+
.padding(top = if (headerType !== HeaderType.NONE) statusBarHeight + 52.dp else 0.dp)
|
|
142
114
|
.pointerInput(Unit) {
|
|
143
115
|
detectTapGestures(onTap = {
|
|
144
116
|
keyboardController?.hide()
|
|
@@ -146,7 +118,6 @@ fun Screen(
|
|
|
146
118
|
}
|
|
147
119
|
.zIndex(1f),
|
|
148
120
|
) {
|
|
149
|
-
|
|
150
121
|
Column(
|
|
151
122
|
modifier = Modifier
|
|
152
123
|
.conditional(scrollable) { weight(1f) }
|
|
@@ -159,12 +130,7 @@ fun Screen(
|
|
|
159
130
|
horizontalAlignment = horizontalAlignment
|
|
160
131
|
) {
|
|
161
132
|
Box {
|
|
162
|
-
headerAnimated()
|
|
163
133
|
Column {
|
|
164
|
-
if (animatedHeader !== null) {
|
|
165
|
-
Spacer(modifier = Modifier.padding(top = statusBarHeight + 52.dp + layoutOffset))
|
|
166
|
-
}
|
|
167
|
-
|
|
168
134
|
if (useAnimationSearch && inputSearchProps != null && headerType == HeaderType.EXTENDED) {
|
|
169
135
|
Spacer(modifier = Modifier.padding(top = statusBarHeight))
|
|
170
136
|
}
|
|
@@ -16,7 +16,7 @@ data class HeaderAnimations(
|
|
|
16
16
|
val backgroundSearch: Color,
|
|
17
17
|
val translateX: Float,
|
|
18
18
|
val width: Float,
|
|
19
|
-
val
|
|
19
|
+
val translateY: Float
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
private const val SCREEN_PADDING = 12
|
|
@@ -27,17 +27,16 @@ fun useHeaderSearchAnimation(
|
|
|
27
27
|
opacityAni: Float,
|
|
28
28
|
scrollState: Int,
|
|
29
29
|
headerRightWidth: Dp,
|
|
30
|
-
statusBarHeight: Dp,
|
|
31
30
|
isBack: Boolean
|
|
32
31
|
): HeaderAnimations {
|
|
33
32
|
val screenWidth = getScreenDimensions().width
|
|
34
|
-
val leftPosition = if (isBack) (BACK_WIDTH + 20).dp else
|
|
33
|
+
val leftPosition = if (isBack) (BACK_WIDTH + 20).dp else 12.dp
|
|
35
34
|
val searchWidth = screenWidth - (SCREEN_PADDING * 2)
|
|
36
35
|
|
|
37
36
|
val backgroundSearch by animateColorAsState(
|
|
38
37
|
targetValue = animateColor(
|
|
39
|
-
AppTheme.current.colors.background.default,
|
|
40
38
|
Colors.black_01,
|
|
39
|
+
AppTheme.current.colors.background.default,
|
|
41
40
|
opacityAni
|
|
42
41
|
),
|
|
43
42
|
)
|
|
@@ -53,17 +52,14 @@ fun useHeaderSearchAnimation(
|
|
|
53
52
|
) * ((searchWidth - leftPosition.value - headerRightWidth.value + 12) - searchWidth) + searchWidth,
|
|
54
53
|
)
|
|
55
54
|
|
|
56
|
-
val
|
|
57
|
-
targetValue = (1 - (scrollState / 52f).coerceIn(
|
|
58
|
-
0f,
|
|
59
|
-
1f
|
|
60
|
-
)) * (statusBarHeight.value + 94 - (statusBarHeight.value + 52)) + (statusBarHeight.value + 52),
|
|
55
|
+
val animatedTranslateY by animateFloatAsState(
|
|
56
|
+
targetValue = (1 - (scrollState / 52f).coerceIn(0f, 1f)) * 52
|
|
61
57
|
)
|
|
62
58
|
return HeaderAnimations(
|
|
63
59
|
opacity = opacityAni,
|
|
64
60
|
backgroundSearch = backgroundSearch,
|
|
65
61
|
translateX = animatedTranslateX,
|
|
66
62
|
width = animatedWidth,
|
|
67
|
-
|
|
63
|
+
translateY = animatedTranslateY
|
|
68
64
|
)
|
|
69
65
|
}
|