@momo-kits/native-kits 0.162.39-debug → 0.162.40-debug

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.
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.162.39-debug"
43
+ version = "0.162.40-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -4,6 +4,7 @@ import androidx.compose.foundation.background
4
4
  import androidx.compose.foundation.layout.Arrangement
5
5
  import androidx.compose.foundation.layout.Box
6
6
  import androidx.compose.foundation.layout.BoxWithConstraints
7
+ import androidx.compose.foundation.layout.ExperimentalLayoutApi
7
8
  import androidx.compose.foundation.layout.FlowRow
8
9
  import androidx.compose.foundation.layout.PaddingValues
9
10
  import androidx.compose.foundation.layout.fillMaxWidth
@@ -14,6 +15,7 @@ import androidx.compose.runtime.CompositionLocalProvider
14
15
  import androidx.compose.ui.Modifier
15
16
  import androidx.compose.ui.draw.clip
16
17
  import androidx.compose.ui.draw.shadow
18
+ import androidx.compose.ui.graphics.Color
17
19
  import androidx.compose.ui.unit.dp
18
20
  import vn.momo.kits.components.Image
19
21
  import vn.momo.kits.const.AppTheme
@@ -21,30 +23,30 @@ import vn.momo.kits.const.Radius
21
23
  import vn.momo.kits.const.Spacing
22
24
 
23
25
  @Composable
24
- internal fun Card(
26
+ @OptIn(ExperimentalLayoutApi::class)
27
+ fun Card(
25
28
  useShadow: Boolean = false,
26
29
  backgroundImage: String? = null,
30
+ backgroundColor: Color? = null,
27
31
  contentPadding: PaddingValues = PaddingValues(Spacing.M),
28
32
  modifier: Modifier = Modifier,
29
33
  content: @Composable () -> Unit,
30
34
  ) {
31
- val columns = 12
32
- val gutter = 8.dp
35
+ val columns = gridColumns()
36
+ val gap = Spacing.S
33
37
  val shape = RoundedCornerShape(Radius.M)
34
- var surface = modifier.fillMaxWidth().padding(horizontal = 12.dp)
35
- if (useShadow) surface = surface.shadow(4.dp, shape)
36
- surface = surface.clip(shape)
37
- if (backgroundImage == null) surface = surface.background(AppTheme.current.colors.background.surface)
38
+ var surface = modifier.fillMaxWidth().padding(horizontal = Spacing.M)
39
+ if (useShadow) surface = surface.shadow(6.dp, shape)
40
+ surface = surface.clip(shape).background(backgroundColor ?: AppTheme.current.colors.background.surface)
38
41
  Box(modifier = surface) {
39
42
  if (backgroundImage != null) {
40
43
  Image(source = backgroundImage, modifier = Modifier.matchParentSize())
41
44
  }
42
45
  BoxWithConstraints(modifier = Modifier.fillMaxWidth().padding(contentPadding)) {
43
- val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
44
- CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
46
+ CompositionLocalProvider(LocalGridContext provides gridContext(constraints.maxWidth, columns, gap)) {
45
47
  FlowRow(
46
- horizontalArrangement = Arrangement.spacedBy(gutter),
47
- verticalArrangement = Arrangement.spacedBy(gutter),
48
+ horizontalArrangement = Arrangement.spacedBy(gap),
49
+ verticalArrangement = Arrangement.spacedBy(gap),
48
50
  ) { content() }
49
51
  }
50
52
  }
@@ -6,33 +6,46 @@ import androidx.compose.foundation.layout.width
6
6
  import androidx.compose.runtime.Composable
7
7
  import androidx.compose.runtime.compositionLocalOf
8
8
  import androidx.compose.ui.Modifier
9
+ import androidx.compose.ui.platform.LocalDensity
9
10
  import androidx.compose.ui.unit.Dp
10
11
  import androidx.compose.ui.unit.dp
12
+ import vn.momo.kits.platform.getScreenDimensions
13
+ import kotlin.math.floor
11
14
 
12
15
  internal data class GridContext(
13
16
  val numberOfColumns: Int = 12,
14
- val gutter: Dp = 12.dp,
15
- val sizePerSpan: Dp = 0.dp,
17
+ val gutterPx: Int = 0,
18
+ val columnPx: Float = 0f,
19
+ val density: Float = 1f,
16
20
  ) {
17
- fun sizeForSpan(span: Int): Dp = sizePerSpan * span + gutter * (span - 1)
21
+ fun sizeForSpan(span: Int): Dp = (floor(columnPx * span + gutterPx * (span - 1)) / density).dp
18
22
  }
19
23
 
20
24
  internal val LocalGridContext = compositionLocalOf<GridContext?> { null }
21
25
 
22
26
  @Composable
23
- internal fun Item(
24
- widthSpan: Int = 12,
27
+ internal fun gridColumns(): Int = if (getScreenDimensions().width > 600) 24 else 12
28
+
29
+ @Composable
30
+ internal fun gridContext(maxWidthPx: Int, columns: Int, gap: Dp): GridContext {
31
+ val density = LocalDensity.current
32
+ val gutterPx = with(density) { gap.roundToPx() }
33
+ return GridContext(columns, gutterPx, (maxWidthPx - gutterPx * (columns - 1)).toFloat() / columns, density.density)
34
+ }
35
+
36
+ @Composable
37
+ fun Item(
38
+ widthSpan: Int? = null,
25
39
  heightSpan: Int = 0,
26
40
  modifier: Modifier = Modifier,
41
+ contentModifier: Modifier = Modifier,
27
42
  content: @Composable () -> Unit,
28
43
  ) {
29
44
  val grid = LocalGridContext.current
30
45
  var m = modifier
31
46
  if (grid != null) {
32
- m = m.width(grid.sizeForSpan(widthSpan))
47
+ m = m.width(grid.sizeForSpan(widthSpan ?: grid.numberOfColumns))
33
48
  if (heightSpan > 0) m = m.height(grid.sizeForSpan(heightSpan))
34
49
  }
35
- // A Column (not a Box) so multiple children flow VERTICALLY instead of stacking
36
- // on top of each other — matches the React Item's flex-column content.
37
- Column(modifier = m) { content() }
50
+ Column(modifier = m.then(contentModifier)) { content() }
38
51
  }
@@ -3,6 +3,7 @@ package vn.momo.kits.layout
3
3
  import androidx.compose.foundation.layout.Arrangement
4
4
  import androidx.compose.foundation.layout.Box
5
5
  import androidx.compose.foundation.layout.BoxWithConstraints
6
+ import androidx.compose.foundation.layout.ExperimentalLayoutApi
6
7
  import androidx.compose.foundation.layout.FlowRow
7
8
  import androidx.compose.foundation.layout.fillMaxWidth
8
9
  import androidx.compose.foundation.layout.padding
@@ -11,27 +12,28 @@ import androidx.compose.runtime.CompositionLocalProvider
11
12
  import androidx.compose.ui.Modifier
12
13
  import androidx.compose.ui.unit.dp
13
14
  import vn.momo.kits.components.Image
15
+ import vn.momo.kits.const.Spacing
14
16
 
15
17
  @Composable
16
- internal fun Section(
18
+ @OptIn(ExperimentalLayoutApi::class)
19
+ fun Section(
17
20
  useMargin: Boolean = true,
18
21
  backgroundImage: String? = null,
19
22
  modifier: Modifier = Modifier,
20
23
  content: @Composable () -> Unit,
21
24
  ) {
22
- val columns = 12
23
- val gutter = 12.dp
24
- val margin = if (useMargin) 12.dp else 0.dp
25
- Box(modifier = modifier.fillMaxWidth().padding(horizontal = margin)) {
25
+ val columns = gridColumns()
26
+ val gap = Spacing.M
27
+ val margin = if (useMargin) Spacing.M else 0.dp
28
+ Box(modifier = Modifier.fillMaxWidth().padding(horizontal = margin).then(modifier)) {
26
29
  if (backgroundImage != null) {
27
30
  Image(source = backgroundImage, modifier = Modifier.matchParentSize())
28
31
  }
29
32
  BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
30
- val sizePerSpan = (maxWidth - gutter * (columns - 1)) / columns - 1.dp / columns
31
- CompositionLocalProvider(LocalGridContext provides GridContext(columns, gutter, sizePerSpan)) {
33
+ CompositionLocalProvider(LocalGridContext provides gridContext(constraints.maxWidth, columns, gap)) {
32
34
  FlowRow(
33
- horizontalArrangement = Arrangement.spacedBy(gutter),
34
- verticalArrangement = Arrangement.spacedBy(gutter),
35
+ horizontalArrangement = Arrangement.spacedBy(gap),
36
+ verticalArrangement = Arrangement.spacedBy(gap),
35
37
  ) { content() }
36
38
  }
37
39
  }
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.*
10
10
  import androidx.compose.runtime.Composable
11
11
  import androidx.compose.runtime.DisposableEffect
12
12
  import androidx.compose.runtime.LaunchedEffect
13
+ import androidx.compose.runtime.remember
13
14
  import androidx.compose.ui.Alignment
14
15
  import androidx.compose.ui.Modifier
15
16
  import androidx.compose.ui.unit.dp
@@ -26,6 +27,7 @@ import vn.momo.kits.navigation.LocalNavigator
26
27
  import vn.momo.kits.navigation.NavigationOptions
27
28
  import vn.momo.kits.navigation.StackScreen
28
29
  import vn.momo.kits.navigation.component.HeaderType
30
+ import vn.momo.kits.platform.BackHandler
29
31
  import vn.momo.kits.platform.reportFloatingArrowBack
30
32
 
31
33
  private var bottomTabOptionItems : MutableList<NavigationOptions?> = mutableListOf()
@@ -43,11 +45,17 @@ internal fun getBottomTabOption(index: Int): NavigationOptions? {
43
45
  @Composable
44
46
  fun BottomTab(
45
47
  items: List<BottomTabItem>,
46
- floatingButton: BottomTabFloatingButton? = null
48
+ floatingButton: BottomTabFloatingButton? = null,
49
+ initialRouteName: String? = null,
50
+ onTabPress: ((index: Int, switchTab: () -> Unit) -> Unit)? = null,
51
+ backToInitialTab: Boolean = true,
47
52
  ) {
48
53
  val navigation = LocalNavigation.current
49
54
  val navigator = LocalNavigator.current
50
55
  val navController = rememberNavController()
56
+ val startRoute = remember {
57
+ "option${items.indexOfFirst { it.name == initialRouteName }.coerceAtLeast(0)}"
58
+ }
51
59
 
52
60
  bottomTabOptionItems = items.mapIndexed { index, item ->
53
61
  item.options ?: NavigationOptions()
@@ -62,15 +70,14 @@ fun BottomTab(
62
70
  )
63
71
  }
64
72
 
65
- // Tab 0 keeps the seeked transition; other tabs go to the host's floating arrow. Matches RN.
66
73
  val currentRoute = navController.currentBackStackEntryAsState().value?.destination?.route
67
- val isFirstTab = currentRoute == null || currentRoute == "option0"
74
+ val onStartTab = currentRoute == null || currentRoute == startRoute
75
+ val isFirstTab = onStartTab || !backToInitialTab
76
+ val backToStartTab = { navController.popBackStack(startRoute, inclusive = false) }
68
77
 
69
78
  DisposableEffect(isFirstTab) {
70
79
  reportFloatingArrowBack(!isFirstTab)
71
- navigator.tabBackHandler = if (isFirstTab) null else ({
72
- navController.popBackStack(navController.graph.startDestinationRoute!!, false)
73
- })
80
+ navigator.tabBackHandler = if (isFirstTab) null else ({ backToStartTab() })
74
81
  // both live outside this composition
75
82
  onDispose {
76
83
  reportFloatingArrowBack(false)
@@ -84,7 +91,7 @@ fun BottomTab(
84
91
  ) {
85
92
  NavHost(
86
93
  navController = navController,
87
- startDestination = "option0"
94
+ startDestination = startRoute
88
95
  ) {
89
96
  items.forEachIndexed { index, item ->
90
97
  composable(
@@ -125,11 +132,8 @@ fun BottomTab(
125
132
  navigationOptions = option,
126
133
  bottomTabIndex = index,
127
134
  onBackHandler = {
128
- if (index != 0) {
129
- navController.popBackStack(
130
- navController.graph.startDestinationRoute!!,
131
- inclusive = false
132
- )
135
+ if (backToInitialTab && "option$index" != startRoute) {
136
+ backToStartTab()
133
137
  } else {
134
138
  navigator.pop()
135
139
  }
@@ -139,17 +143,22 @@ fun BottomTab(
139
143
  }
140
144
  }
141
145
  }
146
+ BackHandler(enabled = !onStartTab) {
147
+ if (backToInitialTab) backToStartTab() else navigator.pop()
148
+ }
142
149
  Column {
143
150
  BottomTabBar(
144
151
  items = items,
145
152
  floatingButton = floatingButton,
146
153
  navController = navController,
147
- onTabSelected = {
148
- val currentRoute = navController.currentBackStackEntry?.destination?.route
149
- val targetRoute = "option$it"
150
- if (currentRoute != targetRoute) {
151
- navController.navigate(targetRoute)
154
+ onTabSelected = { index ->
155
+ val switchTab = {
156
+ val targetRoute = "option$index"
157
+ if (navController.currentBackStackEntry?.destination?.route != targetRoute) {
158
+ navController.navigate(targetRoute)
159
+ }
152
160
  }
161
+ onTabPress?.invoke(index, switchTab) ?: switchTab()
153
162
  }
154
163
  )
155
164
  Spacer(modifier = Modifier.fillMaxWidth().height(AppNavigationBar.current + Spacing.S).background(AppTheme.current.colors.background.surface))
package/gradle.properties CHANGED
@@ -18,7 +18,7 @@ kotlin.apple.xcodeCompatibility.nowarn=true
18
18
  name="ComposeKits"
19
19
  group=vn.momo.kits
20
20
  artifact.id=kits
21
- version=0.162.39
21
+ version=0.162.40
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.162.39-debug",
3
+ "version": "0.162.40-debug",
4
4
  "private": false,
5
5
  "dependeNavigationncies": {},
6
6
  "devDependencies": {},