@momo-kits/native-kits 0.120.0-navigation.3 → 0.120.0-navigation.4
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/const/Theme.kt +3 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +5 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +12 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +21 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +17 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +38 -14
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +27 -23
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +4 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/header/Header.kt +6 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/header/HeaderRight.kt +12 -2
- package/package.json +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/MeasureRenderTime.kt +0 -27
|
@@ -170,4 +170,6 @@ val darkTheme = Theme(
|
|
|
170
170
|
|
|
171
171
|
val AppTheme = staticCompositionLocalOf { defaultTheme }
|
|
172
172
|
|
|
173
|
-
val AppStatusBar = staticCompositionLocalOf { 0.dp }
|
|
173
|
+
val AppStatusBar = staticCompositionLocalOf { 0.dp }
|
|
174
|
+
|
|
175
|
+
val AppNavigationBar = staticCompositionLocalOf { 0.dp }
|
|
@@ -30,6 +30,8 @@ import androidx.compose.ui.unit.dp
|
|
|
30
30
|
import kotlinx.coroutines.launch
|
|
31
31
|
import vn.momo.kits.application.HEADER_HEIGHT
|
|
32
32
|
import vn.momo.kits.components.Divider
|
|
33
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
34
|
+
import vn.momo.kits.const.AppStatusBar
|
|
33
35
|
import vn.momo.kits.const.AppTheme
|
|
34
36
|
import vn.momo.kits.const.Radius
|
|
35
37
|
import vn.momo.kits.modifier.noFeedbackClickable
|
|
@@ -44,9 +46,9 @@ fun BottomSheet(
|
|
|
44
46
|
) {
|
|
45
47
|
val navigator = LocalNavigator.current
|
|
46
48
|
|
|
47
|
-
val
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
val height = if(getPlatformName() == "iOS")
|
|
50
|
+
getScreenDimensions().height.dp
|
|
51
|
+
else getScreenDimensions().height.dp + AppStatusBar.current + AppNavigationBar.current
|
|
50
52
|
val screenHeight = with(LocalDensity.current) { height.toPx() }
|
|
51
53
|
val sheetOffset = remember { Animatable(screenHeight) }
|
|
52
54
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package vn.momo.kits.navigation
|
|
2
2
|
|
|
3
|
+
import androidx.compose.foundation.ScrollState
|
|
3
4
|
import androidx.compose.runtime.Composable
|
|
4
5
|
import androidx.compose.runtime.State
|
|
5
6
|
import androidx.compose.runtime.mutableStateOf
|
|
@@ -12,9 +13,10 @@ import vn.momo.kits.navigation.header.HeaderType
|
|
|
12
13
|
|
|
13
14
|
class Navigation(
|
|
14
15
|
val id: Int = -1,
|
|
15
|
-
val bottomTabIndex: Int = -1
|
|
16
|
+
val bottomTabIndex: Int = -1,
|
|
17
|
+
val initOptions: NavigationOptions? = null
|
|
16
18
|
) {
|
|
17
|
-
private val _options = mutableStateOf(NavigationOptions())
|
|
19
|
+
private val _options = mutableStateOf(initOptions ?: NavigationOptions())
|
|
18
20
|
val currentOptions: State<NavigationOptions> get() = _options
|
|
19
21
|
val options: NavigationOptions get() = _options.value
|
|
20
22
|
|
|
@@ -24,7 +26,7 @@ class Navigation(
|
|
|
24
26
|
headerTitle: HeaderTitle? = null,
|
|
25
27
|
headerRight: HeaderRight? = null,
|
|
26
28
|
headerType: HeaderType? = null,
|
|
27
|
-
|
|
29
|
+
scrollData: ScrollData? = null,
|
|
28
30
|
backgroundColor: Color? = null,
|
|
29
31
|
tintColor: Color? = null,
|
|
30
32
|
footerComponent: (@Composable () -> Unit)? = null,
|
|
@@ -36,7 +38,7 @@ class Navigation(
|
|
|
36
38
|
headerTitle = headerTitle ?: options.headerTitle,
|
|
37
39
|
headerRight = headerRight ?: options.headerRight,
|
|
38
40
|
headerType = headerType ?: options.headerType,
|
|
39
|
-
|
|
41
|
+
scrollData = scrollData ?: options.scrollData,
|
|
40
42
|
backgroundColor = backgroundColor ?: options.backgroundColor,
|
|
41
43
|
tintColor = tintColor ?: options.tintColor,
|
|
42
44
|
footerComponent = footerComponent ?: options.footerComponent,
|
|
@@ -65,8 +67,13 @@ data class NavigationOptions(
|
|
|
65
67
|
val headerTitle: HeaderTitle = HeaderTitle.Default("Stack"),
|
|
66
68
|
val headerRight: HeaderRight = HeaderRight.Toolkit(),
|
|
67
69
|
val headerType: HeaderType = HeaderType.Default(),
|
|
68
|
-
val
|
|
70
|
+
val scrollData: ScrollData = ScrollData(),
|
|
69
71
|
val backgroundColor: Color? = null,
|
|
70
72
|
val tintColor: Color? = null,
|
|
71
73
|
val footerComponent: @Composable (() -> Unit)? = null,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
data class ScrollData(
|
|
77
|
+
val scrollable: Boolean = true,
|
|
78
|
+
val scrollState: ScrollState? = null,
|
|
72
79
|
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package vn.momo.kits.navigation
|
|
2
2
|
|
|
3
|
-
import MeasureRenderTime
|
|
4
3
|
import androidx.compose.animation.core.tween
|
|
5
4
|
import androidx.compose.animation.slideInHorizontally
|
|
6
5
|
import androidx.compose.animation.slideInVertically
|
|
@@ -19,9 +18,9 @@ import androidx.navigation.compose.composable
|
|
|
19
18
|
import androidx.navigation.compose.dialog
|
|
20
19
|
import androidx.navigation.compose.rememberNavController
|
|
21
20
|
import androidx.navigation.toRoute
|
|
21
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
22
22
|
import vn.momo.kits.const.AppStatusBar
|
|
23
23
|
import vn.momo.kits.platform.ConfigureDialog
|
|
24
|
-
import vn.momo.kits.platform.getStatusBarHeight
|
|
25
24
|
|
|
26
25
|
@Composable
|
|
27
26
|
fun NavigationContainer(initialScreen: @Composable () -> Unit, initialScreenTitle: String?, options: NavigationOptions? = null){
|
|
@@ -32,12 +31,18 @@ fun NavigationContainer(initialScreen: @Composable () -> Unit, initialScreenTitl
|
|
|
32
31
|
} else {
|
|
33
32
|
AppStatusBar.current
|
|
34
33
|
}
|
|
34
|
+
val navigationBarHeight = if (AppNavigationBar.current == 0.dp) {
|
|
35
|
+
WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
|
|
36
|
+
} else {
|
|
37
|
+
AppNavigationBar.current
|
|
38
|
+
}
|
|
35
39
|
|
|
36
40
|
val startDestination = DynamicScreenRegistry.register(initialScreen, initialScreenTitle, options)
|
|
37
41
|
|
|
38
42
|
CompositionLocalProvider(
|
|
39
43
|
LocalNavigator provides navigator,
|
|
40
44
|
AppStatusBar provides statusBarHeight,
|
|
45
|
+
AppNavigationBar provides navigationBarHeight,
|
|
41
46
|
) {
|
|
42
47
|
NavHost(navController, startDestination = startDestination) {
|
|
43
48
|
composable<DynamicScreenRoute>(
|
|
@@ -60,13 +65,12 @@ fun NavigationContainer(initialScreen: @Composable () -> Unit, initialScreenTitl
|
|
|
60
65
|
val screen = DynamicScreenRegistry.getScreen(route.id)
|
|
61
66
|
|
|
62
67
|
if (screen != null){
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
68
|
+
StackScreen(
|
|
69
|
+
id = route.id,
|
|
70
|
+
title = route.title,
|
|
71
|
+
content = screen.content,
|
|
72
|
+
navigationOptions = screen.options
|
|
73
|
+
)
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -90,13 +94,12 @@ fun NavigationContainer(initialScreen: @Composable () -> Unit, initialScreenTitl
|
|
|
90
94
|
val screen = DynamicScreenRegistry.getScreen(route.id)
|
|
91
95
|
|
|
92
96
|
if (screen != null){
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
97
|
+
StackScreen(
|
|
98
|
+
id = route.id,
|
|
99
|
+
title = route.title,
|
|
100
|
+
content = screen.content,
|
|
101
|
+
navigationOptions = screen.options
|
|
102
|
+
)
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -111,13 +114,9 @@ fun NavigationContainer(initialScreen: @Composable () -> Unit, initialScreenTitl
|
|
|
111
114
|
if (screen != null){
|
|
112
115
|
ConfigureDialog()
|
|
113
116
|
if (route.isBottomSheet){
|
|
114
|
-
|
|
115
|
-
BottomSheet(screen.content, screen.onDismiss)
|
|
116
|
-
}
|
|
117
|
+
BottomSheet(screen.content, screen.onDismiss)
|
|
117
118
|
} else {
|
|
118
|
-
|
|
119
|
-
ModalScreen(screen.content, screen.onDismiss)
|
|
120
|
-
}
|
|
119
|
+
ModalScreen(screen.content, screen.onDismiss)
|
|
121
120
|
}
|
|
122
121
|
}
|
|
123
122
|
}
|
|
@@ -48,7 +48,7 @@ class Navigator(
|
|
|
48
48
|
|
|
49
49
|
fun showBottomSheet(content: @Composable () -> Unit, title : String? = null, onDismiss: (() -> Unit)? = null){
|
|
50
50
|
val route = DynamicScreenRegistry.registerModal(content, title, onDismiss)
|
|
51
|
-
navController.navigate(DynamicModalRoute(route.id, title, isBottomSheet = true))
|
|
51
|
+
navController.navigate(DynamicModalRoute(route.id, route.title, isBottomSheet = true))
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -57,16 +57,17 @@ val LocalNavigator = staticCompositionLocalOf<Navigator> {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
@Serializable
|
|
60
|
-
data class DynamicScreenRoute(val id: Int, val title: String
|
|
60
|
+
data class DynamicScreenRoute(val id: Int, val title: String)
|
|
61
61
|
|
|
62
62
|
@Serializable
|
|
63
|
-
data class DynamicDialogRoute(val id: Int, val title: String
|
|
63
|
+
data class DynamicDialogRoute(val id: Int, val title: String)
|
|
64
64
|
|
|
65
65
|
@Serializable
|
|
66
|
-
data class DynamicModalRoute(val id: Int, val title: String
|
|
66
|
+
data class DynamicModalRoute(val id: Int, val title: String, val isBottomSheet: Boolean = false)
|
|
67
67
|
|
|
68
68
|
data class DynamicScreen(
|
|
69
69
|
val id: Int,
|
|
70
|
+
val title: String,
|
|
70
71
|
val content: @Composable () -> Unit,
|
|
71
72
|
val onDismiss: (() -> Unit)? = null,
|
|
72
73
|
var options: NavigationOptions? = null
|
|
@@ -79,14 +80,17 @@ object DynamicScreenRegistry {
|
|
|
79
80
|
|
|
80
81
|
fun register(content: @Composable () -> Unit, title: String?, options: NavigationOptions?): DynamicScreenRoute {
|
|
81
82
|
val id = idCounter++
|
|
83
|
+
val screenTitle = title ?: "StackScreen$id"
|
|
82
84
|
screens.add(
|
|
83
85
|
DynamicScreen(
|
|
84
86
|
id = id,
|
|
87
|
+
title = screenTitle,
|
|
85
88
|
content = content,
|
|
86
89
|
options = options
|
|
87
90
|
)
|
|
88
91
|
)
|
|
89
|
-
|
|
92
|
+
|
|
93
|
+
return DynamicScreenRoute(id, screenTitle)
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
fun registerModal(
|
|
@@ -95,8 +99,14 @@ object DynamicScreenRegistry {
|
|
|
95
99
|
onDismiss: (() -> Unit)?
|
|
96
100
|
): DynamicModalRoute {
|
|
97
101
|
val id = idCounter++
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
val modalTitle = title ?: "ModalScreen$id"
|
|
103
|
+
screens.add(DynamicScreen(
|
|
104
|
+
id = id,
|
|
105
|
+
title = modalTitle,
|
|
106
|
+
content = content,
|
|
107
|
+
onDismiss = onDismiss
|
|
108
|
+
))
|
|
109
|
+
return DynamicModalRoute(id, modalTitle)
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
fun unregister() {
|
|
@@ -8,19 +8,17 @@ import androidx.compose.foundation.background
|
|
|
8
8
|
import androidx.compose.foundation.layout.Box
|
|
9
9
|
import androidx.compose.foundation.layout.Column
|
|
10
10
|
import androidx.compose.foundation.layout.Spacer
|
|
11
|
-
import androidx.compose.foundation.layout.WindowInsets
|
|
12
|
-
import androidx.compose.foundation.layout.asPaddingValues
|
|
13
11
|
import androidx.compose.foundation.layout.aspectRatio
|
|
14
12
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
15
13
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
16
14
|
import androidx.compose.foundation.layout.height
|
|
17
15
|
import androidx.compose.foundation.layout.offset
|
|
18
16
|
import androidx.compose.foundation.layout.padding
|
|
19
|
-
import androidx.compose.foundation.layout.systemBars
|
|
20
17
|
import androidx.compose.foundation.rememberScrollState
|
|
21
18
|
import androidx.compose.foundation.verticalScroll
|
|
22
19
|
import androidx.compose.runtime.Composable
|
|
23
20
|
import androidx.compose.runtime.CompositionLocalProvider
|
|
21
|
+
import androidx.compose.runtime.DisposableEffect
|
|
24
22
|
import androidx.compose.runtime.LaunchedEffect
|
|
25
23
|
import androidx.compose.runtime.getValue
|
|
26
24
|
import androidx.compose.runtime.remember
|
|
@@ -32,13 +30,16 @@ import androidx.compose.ui.graphics.lerp
|
|
|
32
30
|
import androidx.compose.ui.platform.LocalDensity
|
|
33
31
|
import androidx.compose.ui.unit.Dp
|
|
34
32
|
import androidx.compose.ui.unit.dp
|
|
33
|
+
import androidx.compose.ui.unit.min
|
|
35
34
|
import androidx.compose.ui.zIndex
|
|
36
35
|
import kotlinx.coroutines.delay
|
|
37
36
|
import vn.momo.kits.components.InputSearch
|
|
37
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
38
38
|
import vn.momo.kits.const.AppStatusBar
|
|
39
39
|
import vn.momo.kits.const.AppTheme
|
|
40
40
|
import vn.momo.kits.const.Colors
|
|
41
41
|
import vn.momo.kits.const.Spacing
|
|
42
|
+
import vn.momo.kits.modifier.conditional
|
|
42
43
|
import vn.momo.kits.navigation.header.Header
|
|
43
44
|
import vn.momo.kits.navigation.header.HeaderBackground
|
|
44
45
|
import vn.momo.kits.navigation.header.HeaderRight
|
|
@@ -55,15 +56,16 @@ fun StackScreen(
|
|
|
55
56
|
content: @Composable () -> Unit,
|
|
56
57
|
navigationOptions: NavigationOptions? = null,
|
|
57
58
|
id: Int = -1,
|
|
59
|
+
title: String = "",
|
|
58
60
|
bottomTabIndex: Int = -1,
|
|
59
61
|
) {
|
|
60
62
|
val navigator = LocalNavigator.current
|
|
61
|
-
val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex) }
|
|
62
|
-
val scrollState = rememberScrollState()
|
|
63
|
+
val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions) }
|
|
63
64
|
|
|
64
|
-
navigationOptions?.let { LaunchedEffect(Unit){ navigation.setOptions(navigationOptions) } }
|
|
65
65
|
val options by navigation.currentOptions
|
|
66
66
|
|
|
67
|
+
val scrollState = options.scrollData.scrollState ?: rememberScrollState()
|
|
68
|
+
|
|
67
69
|
val backgroundColor = options.backgroundColor ?: AppTheme.current.colors.background.default
|
|
68
70
|
val inputSearchType = when (val headerType = options.headerType) {
|
|
69
71
|
is HeaderType.DefaultOrExtended -> when {
|
|
@@ -120,7 +122,13 @@ fun StackScreen(
|
|
|
120
122
|
|
|
121
123
|
Column(Modifier.zIndex(2f).fillMaxSize()) {
|
|
122
124
|
Spacer(Modifier.height(if (options.headerType is HeaderType.DefaultOrExtended) AppStatusBar.current + HEADER_HEIGHT.dp else 0.dp))
|
|
123
|
-
Column(Modifier
|
|
125
|
+
Column (Modifier
|
|
126
|
+
.fillMaxWidth()
|
|
127
|
+
.weight(1f)
|
|
128
|
+
.conditional(options.scrollData.scrollable) {
|
|
129
|
+
verticalScroll(scrollState)
|
|
130
|
+
}
|
|
131
|
+
){
|
|
124
132
|
if (inputSearchType == InputSearchType.Animated) Spacer(Modifier.height(HEADER_HEIGHT.dp))
|
|
125
133
|
renderContent(
|
|
126
134
|
content = content,
|
|
@@ -130,7 +138,6 @@ fun StackScreen(
|
|
|
130
138
|
}
|
|
131
139
|
Footer(options.footerComponent)
|
|
132
140
|
}
|
|
133
|
-
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
}
|
|
@@ -138,7 +145,7 @@ fun StackScreen(
|
|
|
138
145
|
@Composable
|
|
139
146
|
fun renderContent(content: @Composable () -> Unit, scrollState: ScrollState, options: NavigationOptions){
|
|
140
147
|
if (options.headerType is HeaderType.Animated){
|
|
141
|
-
val animatedHeader = options.headerType
|
|
148
|
+
val animatedHeader = options.headerType
|
|
142
149
|
Box {
|
|
143
150
|
Box(Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)){
|
|
144
151
|
animatedHeader.composable.invoke(scrollState.value)
|
|
@@ -155,13 +162,12 @@ fun renderContent(content: @Composable () -> Unit, scrollState: ScrollState, opt
|
|
|
155
162
|
@Composable
|
|
156
163
|
fun Footer(footerComponent: @Composable (() -> Unit)?) {
|
|
157
164
|
if (footerComponent == null) return
|
|
158
|
-
val navigationBarHeight = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
|
|
159
165
|
|
|
160
166
|
Box {
|
|
161
167
|
Box(Modifier
|
|
162
168
|
.fillMaxWidth()
|
|
163
169
|
.background(AppTheme.current.colors.background.surface)
|
|
164
|
-
.padding(top = Spacing.S, start = Spacing.
|
|
170
|
+
.padding(top = Spacing.S, start = Spacing.M, end = Spacing.M, bottom = min(AppNavigationBar.current, 21.dp) + Spacing.S)
|
|
165
171
|
){
|
|
166
172
|
footerComponent.invoke()
|
|
167
173
|
}
|
|
@@ -197,7 +203,7 @@ fun renderSearchAnimated(scrollState: ScrollState, inputSearchType: InputSearchT
|
|
|
197
203
|
val minEndPadding = Spacing.M
|
|
198
204
|
val maxEndPadding = when (val headerRight = options.headerRight) {
|
|
199
205
|
is HeaderRight.Toolkit -> if (headerRight.useShortcut) 114.dp else 78.dp
|
|
200
|
-
|
|
206
|
+
is HeaderRight.Custom -> headerRight.width + Spacing.M * 2
|
|
201
207
|
else -> Spacing.M
|
|
202
208
|
}
|
|
203
209
|
|
|
@@ -210,13 +216,14 @@ fun renderSearchAnimated(scrollState: ScrollState, inputSearchType: InputSearchT
|
|
|
210
216
|
InputSearchLayoutParams(
|
|
211
217
|
topPadding = minTopPadding,
|
|
212
218
|
startPadding = maxStartPadding,
|
|
213
|
-
endPadding =
|
|
219
|
+
endPadding = maxEndPadding,
|
|
214
220
|
backgroundColor = bgColor
|
|
215
221
|
)
|
|
216
222
|
}
|
|
217
223
|
|
|
218
224
|
InputSearchType.Animated -> {
|
|
219
|
-
val
|
|
225
|
+
val density = LocalDensity.current
|
|
226
|
+
val scrollDp = with(density) { scrollState.value.toDp() }
|
|
220
227
|
|
|
221
228
|
val animatedTopPadding by animateDpAsState(
|
|
222
229
|
targetValue = (maxTopPadding - scrollDp).coerceIn(minTopPadding, maxTopPadding),
|
|
@@ -240,6 +247,23 @@ fun renderSearchAnimated(scrollState: ScrollState, inputSearchType: InputSearchT
|
|
|
240
247
|
)
|
|
241
248
|
val animatedColor by animateColorAsState(targetValue = targetColor, label = "BackgroundColor")
|
|
242
249
|
|
|
250
|
+
val maxPadding = maxOf(maxEndPadding, maxStartPadding, maxTopPadding)
|
|
251
|
+
LaunchedEffect(scrollState.isScrollInProgress) {
|
|
252
|
+
if (scrollDp < maxPadding) {
|
|
253
|
+
if (!scrollState.isScrollInProgress) {
|
|
254
|
+
val midpoint = (maxTopPadding - minTopPadding) / 2
|
|
255
|
+
val currentScrollDp = with(density) { scrollState.value.toDp() }
|
|
256
|
+
|
|
257
|
+
if (currentScrollDp < midpoint) {
|
|
258
|
+
scrollState.animateScrollTo(0)
|
|
259
|
+
} else {
|
|
260
|
+
val snapScrollValue = with(density) { maxPadding.toPx().toInt() }
|
|
261
|
+
scrollState.animateScrollTo(snapScrollValue)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
243
267
|
InputSearchLayoutParams(
|
|
244
268
|
topPadding = animatedTopPadding,
|
|
245
269
|
startPadding = animatedStartPadding,
|
|
@@ -9,19 +9,23 @@ import androidx.compose.foundation.background
|
|
|
9
9
|
import androidx.compose.foundation.layout.Box
|
|
10
10
|
import androidx.compose.foundation.layout.Column
|
|
11
11
|
import androidx.compose.foundation.layout.Spacer
|
|
12
|
-
import androidx.compose.foundation.layout.
|
|
13
|
-
import androidx.compose.foundation.layout.asPaddingValues
|
|
12
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
14
13
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
15
14
|
import androidx.compose.foundation.layout.height
|
|
16
|
-
import androidx.compose.foundation.layout.
|
|
15
|
+
import androidx.compose.foundation.layout.padding
|
|
17
16
|
import androidx.compose.runtime.Composable
|
|
18
17
|
import androidx.compose.runtime.LaunchedEffect
|
|
18
|
+
import androidx.compose.ui.Alignment
|
|
19
19
|
import androidx.compose.ui.Modifier
|
|
20
20
|
import androidx.compose.ui.unit.dp
|
|
21
|
+
import androidx.compose.ui.unit.min
|
|
21
22
|
import androidx.navigation.compose.NavHost
|
|
22
23
|
import androidx.navigation.compose.composable
|
|
23
24
|
import androidx.navigation.compose.rememberNavController
|
|
25
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
26
|
+
import vn.momo.kits.const.AppStatusBar
|
|
24
27
|
import vn.momo.kits.const.AppTheme
|
|
28
|
+
import vn.momo.kits.const.Spacing
|
|
25
29
|
import vn.momo.kits.navigation.LocalNavigation
|
|
26
30
|
import vn.momo.kits.navigation.NavigationOptions
|
|
27
31
|
import vn.momo.kits.navigation.StackScreen
|
|
@@ -49,9 +53,6 @@ fun BottomTab(
|
|
|
49
53
|
val navigation = LocalNavigation.current
|
|
50
54
|
val navController = rememberNavController()
|
|
51
55
|
|
|
52
|
-
val navigationBarHeight = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
|
|
53
|
-
val statusBarHeight = WindowInsets.systemBars.asPaddingValues().calculateTopPadding()
|
|
54
|
-
|
|
55
56
|
bottomTabOptionItems = items.map { it.options }.toMutableList()
|
|
56
57
|
|
|
57
58
|
LaunchedEffect(Unit){
|
|
@@ -61,12 +62,12 @@ fun BottomTab(
|
|
|
61
62
|
}
|
|
62
63
|
val height = if(getPlatformName() == "iOS")
|
|
63
64
|
getScreenDimensions().height.dp
|
|
64
|
-
else getScreenDimensions().height.dp +
|
|
65
|
+
else getScreenDimensions().height.dp + AppStatusBar.current + AppNavigationBar.current
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
Box(modifier = Modifier.fillMaxWidth().height(height), contentAlignment = Alignment.BottomCenter) {
|
|
67
68
|
Box(modifier = Modifier
|
|
68
|
-
.
|
|
69
|
-
.
|
|
69
|
+
.fillMaxSize()
|
|
70
|
+
.padding(bottom = BOTTOM_TAB_BAR_HEIGHT.dp + AppNavigationBar.current)
|
|
70
71
|
) {
|
|
71
72
|
NavHost(
|
|
72
73
|
navController = navController,
|
|
@@ -115,25 +116,28 @@ fun BottomTab(
|
|
|
115
116
|
StackScreen(
|
|
116
117
|
content = item.screen,
|
|
117
118
|
navigationOptions = option,
|
|
118
|
-
bottomTabIndex = index
|
|
119
|
+
bottomTabIndex = index,
|
|
120
|
+
title = "BottomTabItem$index"
|
|
119
121
|
)
|
|
120
122
|
}
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
126
|
+
Column {
|
|
127
|
+
BottomTabBar(
|
|
128
|
+
items = items,
|
|
129
|
+
floatingButton = floatingButton,
|
|
130
|
+
navController = navController,
|
|
131
|
+
onTabSelected = {
|
|
132
|
+
val currentRoute = navController.currentBackStackEntry?.destination?.route
|
|
133
|
+
val targetRoute = "option$it"
|
|
134
|
+
if (currentRoute != targetRoute){
|
|
135
|
+
navController.navigate(targetRoute)
|
|
136
|
+
}
|
|
133
137
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
)
|
|
139
|
+
Spacer(modifier = Modifier.fillMaxWidth().height(min(AppNavigationBar.current, 21.dp) + Spacing.S).background(AppTheme.current.colors.background.surface))
|
|
140
|
+
}
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
143
|
|
|
@@ -43,6 +43,7 @@ import vn.momo.kits.modifier.noFeedbackClickable
|
|
|
43
43
|
import vn.momo.kits.platform.getScreenDimensions
|
|
44
44
|
|
|
45
45
|
val floatingButtonWidth = 75.dp
|
|
46
|
+
const val BOTTOM_TAB_BAR_HEIGHT = 56
|
|
46
47
|
|
|
47
48
|
@Composable
|
|
48
49
|
fun BottomTabBar(
|
|
@@ -77,7 +78,7 @@ fun BottomTabBar(
|
|
|
77
78
|
Row(
|
|
78
79
|
modifier = Modifier
|
|
79
80
|
.fillMaxWidth()
|
|
80
|
-
.height(
|
|
81
|
+
.height(BOTTOM_TAB_BAR_HEIGHT.dp)
|
|
81
82
|
.background(AppTheme.current.colors.background.surface),
|
|
82
83
|
horizontalArrangement = Arrangement.SpaceAround,
|
|
83
84
|
) {
|
|
@@ -91,7 +92,7 @@ fun BottomTabBar(
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
Box(modifier = Modifier
|
|
94
|
-
.offset(x = indicatorOffsetX, y = (-
|
|
95
|
+
.offset(x = indicatorOffsetX, y = (-BOTTOM_TAB_BAR_HEIGHT + 2).dp)
|
|
95
96
|
.height(2.dp)
|
|
96
97
|
.width(44.dp)
|
|
97
98
|
.background(
|
|
@@ -103,7 +104,7 @@ fun BottomTabBar(
|
|
|
103
104
|
Box(modifier = Modifier
|
|
104
105
|
.fillMaxWidth()
|
|
105
106
|
.height(6.dp)
|
|
106
|
-
.offset(x = 0.dp, y = (-
|
|
107
|
+
.offset(x = 0.dp, y = (-BOTTOM_TAB_BAR_HEIGHT).dp)
|
|
107
108
|
.background(
|
|
108
109
|
brush = Brush.verticalGradient(
|
|
109
110
|
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.05f))
|
|
@@ -72,10 +72,12 @@ fun Header(
|
|
|
72
72
|
)
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
renderHeaderContent(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
renderHeaderContent(
|
|
76
|
+
options.headerTitle,
|
|
77
|
+
headerColor.tintIconColor
|
|
78
|
+
.copy(alpha = if (inputSearchType == InputSearchType.Animated) 1f - animatedAlpha else 1f)
|
|
79
|
+
)
|
|
80
|
+
HeaderRight(options.headerRight, options.tintColor, headerColor)
|
|
79
81
|
}
|
|
80
82
|
renderVerticalShadow(opacity)
|
|
81
83
|
}
|
|
@@ -5,6 +5,8 @@ import androidx.compose.foundation.border
|
|
|
5
5
|
import androidx.compose.foundation.layout.Arrangement
|
|
6
6
|
import androidx.compose.foundation.layout.Box
|
|
7
7
|
import androidx.compose.foundation.layout.Row
|
|
8
|
+
import androidx.compose.foundation.layout.fillMaxHeight
|
|
9
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
10
|
import androidx.compose.foundation.layout.height
|
|
9
11
|
import androidx.compose.foundation.layout.offset
|
|
10
12
|
import androidx.compose.foundation.layout.padding
|
|
@@ -17,6 +19,7 @@ import androidx.compose.ui.Alignment
|
|
|
17
19
|
import androidx.compose.ui.Modifier
|
|
18
20
|
import androidx.compose.ui.draw.clip
|
|
19
21
|
import androidx.compose.ui.graphics.Color
|
|
22
|
+
import androidx.compose.ui.unit.Dp
|
|
20
23
|
import androidx.compose.ui.unit.dp
|
|
21
24
|
import vn.momo.kits.application.DesignSystemWhiteList
|
|
22
25
|
import vn.momo.kits.application.Spacing
|
|
@@ -35,7 +38,11 @@ fun HeaderRight(
|
|
|
35
38
|
) {
|
|
36
39
|
when (headerRight) {
|
|
37
40
|
is HeaderRight.None -> {}
|
|
38
|
-
is HeaderRight.Custom ->
|
|
41
|
+
is HeaderRight.Custom -> {
|
|
42
|
+
Box(Modifier.fillMaxHeight().width(headerRight.width)){
|
|
43
|
+
headerRight.content()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
39
46
|
is HeaderRight.OnBoarding -> {}
|
|
40
47
|
is HeaderRight.Toolkit -> {
|
|
41
48
|
Toolkit(
|
|
@@ -148,7 +155,10 @@ fun NavigationButton(
|
|
|
148
155
|
|
|
149
156
|
sealed interface HeaderRight {
|
|
150
157
|
data object None : HeaderRight
|
|
151
|
-
data class Custom(
|
|
158
|
+
data class Custom(
|
|
159
|
+
val width: Dp,
|
|
160
|
+
val content: @Composable () -> Unit
|
|
161
|
+
) : HeaderRight
|
|
152
162
|
data object OnBoarding : HeaderRight
|
|
153
163
|
data class Toolkit(
|
|
154
164
|
val useShortcut: Boolean = false,
|
package/package.json
CHANGED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import androidx.compose.foundation.layout.Box
|
|
2
|
-
import androidx.compose.runtime.Composable
|
|
3
|
-
import androidx.compose.runtime.remember
|
|
4
|
-
import androidx.compose.ui.Modifier
|
|
5
|
-
import androidx.compose.ui.layout.onGloballyPositioned
|
|
6
|
-
import kotlinx.datetime.Clock
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@Composable
|
|
10
|
-
fun MeasureRenderTime(
|
|
11
|
-
tag: String = "",
|
|
12
|
-
content: @Composable () -> Unit
|
|
13
|
-
) {
|
|
14
|
-
val startTime = remember { Clock.System.now() }
|
|
15
|
-
|
|
16
|
-
Box(
|
|
17
|
-
modifier = Modifier.onGloballyPositioned {
|
|
18
|
-
val endTime = Clock.System.now()
|
|
19
|
-
val duration = (endTime - startTime).inWholeMilliseconds
|
|
20
|
-
println("TEST112 [$tag] rendered in $duration ms")
|
|
21
|
-
}
|
|
22
|
-
) {
|
|
23
|
-
content()
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|