@momo-kits/native-kits 0.162.2-beta.23-debug → 0.162.2-beta.24-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.
Files changed (198) hide show
  1. package/CLAUDE.md +1 -1
  2. package/compose/build.gradle.kts +1 -1
  3. package/compose/compose.podspec +1 -1
  4. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
  5. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +5 -0
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +3 -0
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +20 -62
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +4 -0
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +8 -2
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +3 -1
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +93 -75
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +25 -7
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +3 -1
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
  17. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
  18. package/gradle.properties +1 -1
  19. package/ios/Application/ApplicationEnvironment.swift +11 -0
  20. package/ios/Application/Components.swift +34 -44
  21. package/ios/Application/FloatingButton.swift +10 -9
  22. package/ios/Application/HeaderRight.swift +79 -45
  23. package/ios/Application/Navigation/BottomTab/BottomTab.swift +103 -0
  24. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
  25. package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
  26. package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
  27. package/ios/Application/Navigation/HeaderTitle.swift +57 -0
  28. package/ios/Application/Navigation/HeaderUser.swift +209 -0
  29. package/ios/Application/Navigation/NavigationContainer.swift +176 -0
  30. package/ios/Application/Navigation/NavigationOptions.swift +109 -0
  31. package/ios/Application/Navigation/Navigator.swift +364 -0
  32. package/ios/Application/Navigation/Overplay/BottomSheet.swift +188 -0
  33. package/ios/Application/Navigation/Overplay/ModalScreen.swift +68 -0
  34. package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
  35. package/ios/Application/Navigation/component/Header.swift +178 -0
  36. package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
  37. package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
  38. package/ios/Application/Screen.swift +2 -1
  39. package/ios/Application/StackScreen.swift +453 -0
  40. package/ios/Avatar/Avatar.swift +193 -0
  41. package/ios/Badge/Badge.swift +11 -14
  42. package/ios/Badge/BadgeRibbon.swift +12 -21
  43. package/ios/BaselineView/BaselineView.swift +163 -0
  44. package/ios/Button/Button.swift +61 -22
  45. package/ios/Carousel/Carousel.swift +181 -0
  46. package/ios/Checkbox/Checkbox.swift +14 -13
  47. package/ios/Chip/Chip.swift +23 -9
  48. package/ios/Collapse/Collapse.swift +182 -0
  49. package/ios/Colors+Radius+Spacing/Colors.swift +12 -12
  50. package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
  51. package/ios/DateTimePicker/DateTimePicker.swift +210 -0
  52. package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
  53. package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
  54. package/ios/DateTimePicker/WheelPicker.swift +161 -0
  55. package/ios/Divider/Divider.swift +16 -0
  56. package/ios/Extensions/Color++.swift +32 -0
  57. package/ios/Icon/Icon.swift +6 -1
  58. package/ios/IconButton/IconButton.swift +112 -0
  59. package/ios/Input/Input.swift +41 -25
  60. package/ios/Input/InputPhoneNumber.swift +20 -19
  61. package/ios/Input/InputSearch.swift +100 -47
  62. package/ios/Input/InputTextArea.swift +66 -40
  63. package/ios/InputDropDown/InputDropDown.swift +198 -0
  64. package/ios/InputMoney/InputMoney.swift +335 -0
  65. package/ios/InputOTP/InputOTP.swift +210 -0
  66. package/ios/Loader/Loader.swift +113 -0
  67. package/ios/MoMoUIKits.podspec +5 -0
  68. package/ios/Pagination/PaginationDot.swift +61 -0
  69. package/ios/Pagination/PaginationNumber.swift +35 -0
  70. package/ios/Pagination/PaginationScroll.swift +101 -0
  71. package/ios/Pagination/PaginationWhiteDot.swift +37 -0
  72. package/ios/Popup/PopupDisplay.swift +8 -16
  73. package/ios/Popup/PopupInput.swift +2 -8
  74. package/ios/Popup/PopupNotify.swift +219 -0
  75. package/ios/ProgressInfo/ProgressInfo.swift +294 -0
  76. package/ios/Radio/Radio.swift +70 -0
  77. package/ios/Rating/Rating.swift +82 -0
  78. package/ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json +11 -0
  79. package/ios/Resources/MoMoUIKitsColors.xcassets/Background.colorset/Contents.json +38 -0
  80. package/ios/Resources/MoMoUIKitsColors.xcassets/Border.colorset/Contents.json +38 -0
  81. package/ios/Resources/MoMoUIKitsColors.xcassets/Card.colorset/Contents.json +38 -0
  82. package/ios/Resources/MoMoUIKitsColors.xcassets/Contents.json +6 -0
  83. package/ios/Resources/MoMoUIKitsColors.xcassets/Error.colorset/Contents.json +38 -0
  84. package/ios/Resources/MoMoUIKitsColors.xcassets/Primary.colorset/Contents.json +38 -0
  85. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryDark.colorset/Contents.json +38 -0
  86. package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryLight.colorset/Contents.json +38 -0
  87. package/ios/Resources/MoMoUIKitsColors.xcassets/Secondary.colorset/Contents.json +38 -0
  88. package/ios/Resources/MoMoUIKitsColors.xcassets/Success.colorset/Contents.json +38 -0
  89. package/ios/Resources/MoMoUIKitsColors.xcassets/Text.colorset/Contents.json +38 -0
  90. package/ios/Resources/MoMoUIKitsColors.xcassets/TextSecondary.colorset/Contents.json +38 -0
  91. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
  92. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
  93. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
  94. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
  95. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
  96. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
  97. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
  98. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
  99. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
  100. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
  101. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
  102. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
  103. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
  104. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
  105. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
  106. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
  107. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
  108. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
  109. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
  110. package/ios/Resources/MoMoUIKitsColors.xcassets/Warning.colorset/Contents.json +38 -0
  111. package/ios/Skeleton/Skeleton.swift +99 -0
  112. package/ios/Slider/Slider.swift +237 -0
  113. package/ios/Stepper/Stepper.swift +220 -0
  114. package/ios/Steps/Steps.swift +451 -0
  115. package/ios/SuggestAction/SuggestAction.swift +97 -0
  116. package/ios/Swipeable/SwipeCell.swift +185 -0
  117. package/ios/Swipeable/SwipeCellModel.swift +21 -0
  118. package/ios/TabView/TabView.swift +530 -0
  119. package/ios/Tag/Tag.swift +98 -0
  120. package/ios/Title/Title.swift +269 -0
  121. package/ios/Tooltip/Tooltip.swift +482 -0
  122. package/ios/Typography/FontScaleStore.swift +19 -0
  123. package/ios/Typography/Text.swift +79 -5
  124. package/ios/Typography/Typography.swift +3 -0
  125. package/ios/Uploader/Uploader.swift +183 -0
  126. package/ios/native-kits.podspec +61 -8
  127. package/ios-demo/MoMoUIKitsDemo.podspec +20 -0
  128. package/ios-demo/README.md +120 -0
  129. package/ios-demo/Resources/dot_loading.json +558 -0
  130. package/ios-demo/Resources/icon.json +4052 -0
  131. package/ios-demo/Resources/lottie_circle_loader.json +1 -0
  132. package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
  133. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
  134. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
  135. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
  136. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
  137. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
  138. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
  139. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
  140. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
  141. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
  142. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +24 -0
  143. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
  144. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
  145. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -0
  146. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
  147. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
  148. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +100 -0
  149. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
  150. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +63 -0
  151. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
  152. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
  153. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
  154. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
  155. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
  156. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
  157. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +278 -0
  158. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
  159. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
  160. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
  161. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
  162. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
  163. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
  164. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
  165. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
  166. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
  167. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
  168. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
  169. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +227 -0
  170. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
  171. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
  172. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
  173. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
  174. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
  175. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
  176. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
  177. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
  178. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
  179. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
  180. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
  181. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
  182. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
  183. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
  184. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
  185. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
  186. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
  187. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
  188. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
  189. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
  190. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
  191. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
  192. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +51 -0
  193. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
  194. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
  195. package/package.json +1 -1
  196. package/publish.sh +50 -0
  197. package/scripts/gen-ios-color.mjs +136 -0
  198. package/local.properties +0 -8
package/CLAUDE.md CHANGED
@@ -40,7 +40,7 @@ Publishing is automated (`publish.sh` + GitLab CI on `[ci build]` / `main`). Do
40
40
  ## Architecture essentials
41
41
 
42
42
  - **Entry point:** wrap content in `NavigationContainer(...)` from `navigation/`. It builds the `Navigator`, takes a host-supplied `Localize` (falls back to an empty one), and provides the CompositionLocals below. **Do not use** `ApplicationContainer` (`application/NavigationContainer.kt`) — deprecated and does **not** wire `LocalLocalize` / `LocalNavigator` / `LocalMaxApi`.
43
- - **Configuration flows via CompositionLocals**, not params. Public ones: `AppTheme`, `AppStatusBar`, `AppNavigationBar` (`const/Theme.kt`); `ApplicationContext`, `AppConfig`, `AppLanguage`, `LocalLocalize`, `ScaleSizeMaxRate` (`application/`); `LocalNavigator`, `LocalMaxApi` (`navigation/`). Read with `X.current`.
43
+ - **Configuration flows via CompositionLocals**, not params. Public ones: `AppTheme`, `AppStatusBar`, `AppNavigationBar` (`const/Theme.kt`); `ApplicationContext`, `AppConfig`, `AppLanguage`, `LocalLocalize` (`application/`); `LocalNavigator`, `LocalMaxApi` (`navigation/`). Read with `X.current`.
44
44
  - **Platform code** goes through `expect`/`actual` in `platform/` — never reference Android/iOS APIs from `commonMain` directly.
45
45
  - **Native bridge:** `IMaxApi` (`vn.momo.maxapi`, exposed as `LocalMaxApi`) is the host-app bridge (dismiss, tracking, device info, language).
46
46
  - Navigation uses a runtime `DynamicScreenRegistry`; overlays (modal/bottom-sheet/snackbar) go through `Navigator` + `OverplayComponentRegistry`.
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.162.2-beta.23-debug"
43
+ version = "0.162.2-beta.24-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |spec|
2
2
  spec.name = 'compose'
3
- spec.version = '0.162.2-beta.19'
3
+ spec.version = '0.162.2-sp.7-debug'
4
4
  spec.homepage = 'https://momo.vn'
5
5
  spec.source = { :http=> ''}
6
6
  spec.authors = ''
@@ -0,0 +1,7 @@
1
+ package vn.momo.kits.platform
2
+
3
+ import androidx.compose.runtime.Composable
4
+
5
+ // Android's LocalDensity.fontScale already tracks Configuration.fontScale live.
6
+ @Composable
7
+ actual fun ProvideOsFontScale(content: @Composable () -> Unit) = content()
@@ -29,6 +29,8 @@ data class MiniAppContext(
29
29
  val permissions: List<Map<String, Any>>? = emptyList(),
30
30
  val features: FeatureFlags? = null,
31
31
  val scaleSizeMaxRate: Float? = null,
32
+ val userScaleRate: Float? = null,
33
+ val useOSScaleRate: Boolean? = null,
32
34
  ) {
33
35
  companion object {
34
36
 
@@ -61,6 +63,8 @@ data class MiniAppContext(
61
63
  permissions = if (!parent.permissions.isNullOrEmpty()) parent.permissions else child.permissions,
62
64
  features = mergeFeatureFlags(parent.features, child.features),
63
65
  scaleSizeMaxRate = parent.scaleSizeMaxRate ?: child.scaleSizeMaxRate,
66
+ userScaleRate = parent.userScaleRate ?: child.userScaleRate,
67
+ useOSScaleRate = parent.useOSScaleRate ?: child.useOSScaleRate,
64
68
  )
65
69
  }
66
70
 
@@ -98,4 +102,5 @@ val LocalComponentInformation = staticCompositionLocalOf<ComponentInformation?>
98
102
  null
99
103
  }
100
104
 
105
+ @Deprecated("Max font scale is fixed at MAX_FONT_SCALE (1.5); this CompositionLocal is no longer read.")
101
106
  val ScaleSizeMaxRate = staticCompositionLocalOf<Float?> { null }
@@ -7,6 +7,7 @@ import androidx.compose.ui.Modifier
7
7
  import androidx.compose.ui.unit.Dp
8
8
  import vn.momo.kits.const.*
9
9
  import vn.momo.kits.modifier.DeprecatedModifier
10
+ import vn.momo.kits.platform.ProvideOsFontScale
10
11
  import vn.momo.kits.platform.getStatusBarHeight
11
12
 
12
13
  @Deprecated("Use IMaxApi instead", ReplaceWith("IMaxApi"))
@@ -93,6 +94,7 @@ fun ApplicationContainer(
93
94
 
94
95
  val appStatusBarHeight = statusBarHeight ?: getStatusBarHeight()
95
96
 
97
+ ProvideOsFontScale {
96
98
  CompositionLocalProvider(
97
99
  AppTheme provides appTheme,
98
100
  PlatformApi provides composeApi,
@@ -103,5 +105,6 @@ fun ApplicationContainer(
103
105
  content()
104
106
  }
105
107
  }
108
+ }
106
109
 
107
110
  }
@@ -0,0 +1,56 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.CompositionLocalProvider
5
+ import androidx.compose.runtime.LaunchedEffect
6
+ import androidx.compose.runtime.remember
7
+ import vn.momo.kits.const.AppTheme
8
+ import vn.momo.kits.const.Theme
9
+ import vn.momo.kits.navigation.LocalMaxApi
10
+ import vn.momo.kits.platform.ProvideOsFontScale
11
+ import vn.momo.maxapi.IMaxApi
12
+
13
+
14
+ @Composable
15
+ fun WidgetContainer(
16
+ theme: Theme? = null,
17
+ miniAppContext: MiniAppContext? = null,
18
+ maxApi: IMaxApi? = null,
19
+ localize: Localize? = null,
20
+ content: @Composable () -> Unit,
21
+ ) {
22
+ val parentContext = LocalContext.current
23
+ val mergedContext = remember(parentContext, miniAppContext) {
24
+ MiniAppContext.merge(parentContext, miniAppContext)
25
+ }
26
+ val resolvedTheme = theme ?: AppTheme.current
27
+ val resolvedLocalize = localize ?: LocalLocalize.current
28
+ val resolvedMaxApi = maxApi ?: LocalMaxApi.current
29
+
30
+ LaunchedEffect(resolvedMaxApi, localize) {
31
+ val api = resolvedMaxApi ?: return@LaunchedEffect
32
+ val target = localize ?: return@LaunchedEffect
33
+ runCatching {
34
+ api.getLanguage(callback = { data ->
35
+ if (parseLanguage(data) == Localize.EN) target.changeLanguage(Localize.EN)
36
+ })
37
+ }
38
+ }
39
+
40
+ ProvideOsFontScale {
41
+ CompositionLocalProvider(
42
+ AppTheme provides resolvedTheme,
43
+ LocalContext provides mergedContext,
44
+ LocalLocalize provides resolvedLocalize,
45
+ LocalMaxApi provides resolvedMaxApi,
46
+ ) {
47
+ content()
48
+ }
49
+ }
50
+ }
51
+
52
+ private fun parseLanguage(raw: Map<String, Any?>?): String? {
53
+ val code = (raw?.get("response") as? String)?.trim()?.lowercase()
54
+ if (code.isNullOrEmpty()) return null
55
+ return if (code.startsWith(Localize.EN)) Localize.EN else Localize.VI
56
+ }
@@ -5,6 +5,7 @@ import androidx.compose.foundation.border
5
5
  import androidx.compose.foundation.clickable
6
6
  import androidx.compose.foundation.layout.Box
7
7
  import androidx.compose.foundation.layout.size
8
+ import androidx.compose.foundation.shape.CircleShape
8
9
  import androidx.compose.foundation.shape.RoundedCornerShape
9
10
  import androidx.compose.runtime.Composable
10
11
  import androidx.compose.runtime.remember
@@ -19,65 +20,32 @@ import vn.momo.kits.application.IsShowBaseLineDebug
19
20
  import vn.momo.kits.const.AppTheme
20
21
  import vn.momo.kits.const.Colors
21
22
  import vn.momo.kits.const.Radius
22
- import vn.momo.kits.const.Spacing
23
23
  import vn.momo.kits.modifier.conditional
24
24
 
25
25
  data class IconSpecs(
26
- val width: Dp,
27
- val height: Dp,
28
- val radius: Dp,
29
- val size: Dp
26
+ val box: Dp,
27
+ val icon: Dp,
30
28
  )
31
29
 
32
30
  enum class IconSize(val value: IconSpecs) {
33
- LARGE(
34
- IconSpecs(
35
- height = 48.dp,
36
- radius = Radius.XL,
37
- width = 48.dp,
38
- size = 48.dp
39
- )
40
- ),
41
- SMALL(
42
- IconSpecs(
43
- height = 40.dp,
44
- radius = Radius.XL,
45
- width = 40.dp,
46
- size = 40.dp
47
- )
48
- )
31
+ LARGE(IconSpecs(box = 48.dp, icon = 24.dp)),
32
+ MEDIUM(IconSpecs(box = 36.dp, icon = 16.dp)),
33
+ SMALL(IconSpecs(box = 28.dp, icon = 16.dp)),
49
34
  }
50
35
 
51
- enum class IconButtonShape {
36
+ enum class IconShape {
52
37
  CIRCLE,
53
38
  SQUARE,
54
- RECTANGLE
55
39
  }
56
40
 
57
- // Resolved footprint + corner radius for a (size, shape) pair.
58
- data class IconButtonGeometry(
59
- val width: Dp,
60
- val height: Dp,
61
- val radius: Dp
62
- )
41
+ // Square keeps an 8dp rounded corner; circle is fully rounded regardless of size.
42
+ private val squareShape = RoundedCornerShape(Radius.S)
63
43
 
64
- // CIRCLE keeps the square footprint fully rounded (legacy default); SQUARE/RECTANGLE use the
65
- // standard button corner (Radius.S) and RECTANGLE widens the footprint so it reads horizontal.
66
- internal fun resolveIconButtonGeometry(size: IconSize, shape: IconButtonShape): IconButtonGeometry {
67
- val base = size.value.height
68
- return when (shape) {
69
- IconButtonShape.CIRCLE -> IconButtonGeometry(base, base, size.value.radius)
70
- IconButtonShape.SQUARE -> IconButtonGeometry(base, base, Radius.S)
71
- IconButtonShape.RECTANGLE -> IconButtonGeometry(base + Spacing.S, base, Radius.S)
72
- }
44
+ private fun IconShape.toShape(): Shape = when (this) {
45
+ IconShape.CIRCLE -> CircleShape
46
+ IconShape.SQUARE -> squareShape
73
47
  }
74
48
 
75
- // Cache for icon sizes to avoid repeated calculations
76
- private val iconSizeMap = mapOf(
77
- IconSize.SMALL to 16.dp,
78
- IconSize.LARGE to 24.dp
79
- )
80
-
81
49
  @Composable
82
50
  internal fun getIconStyle(type: ButtonType, shape: Shape, color: Color? = null): Modifier {
83
51
  val theme = AppTheme.current
@@ -126,42 +94,32 @@ fun IconButton(
126
94
  onClick: () -> Unit,
127
95
  type: ButtonType = ButtonType.PRIMARY,
128
96
  size: IconSize = IconSize.SMALL,
129
- shape: IconButtonShape = IconButtonShape.CIRCLE,
97
+ shape: IconShape = IconShape.CIRCLE,
130
98
  icon: String = "",
131
99
  ) {
132
- // Memoize icon size calculation
133
- val iconSize = remember(size) {
134
- iconSizeMap[size] ?: 16.dp
135
- }
100
+ val specs = size.value
136
101
 
137
- // Memoize enabled state
138
102
  val isEnabled = remember(type) {
139
103
  type != ButtonType.DISABLED
140
104
  }
141
105
 
142
- // Memoize footprint + corner shape for the requested shape
143
- val geometry = remember(size, shape) {
144
- resolveIconButtonGeometry(size, shape)
145
- }
146
- val cornerShape = remember(geometry.radius) {
147
- RoundedCornerShape(geometry.radius)
148
- }
106
+ val boxShape = remember(shape) { shape.toShape() }
149
107
 
150
108
  Box(
151
109
  modifier = Modifier
152
- .size(width = geometry.width, height = geometry.height)
153
- .then(getIconStyle(type, cornerShape))
110
+ .size(specs.box)
111
+ .then(getIconStyle(type, boxShape))
154
112
  .conditional(IsShowBaseLineDebug) {
155
113
  border(1.dp, Colors.blue_03)
156
114
  }
157
- .clip(cornerShape)
115
+ .clip(boxShape)
158
116
  .clickable(enabled = isEnabled, onClick = onClick),
159
117
  contentAlignment = Alignment.Center
160
118
  ) {
161
119
  Icon(
162
120
  source = icon,
163
121
  color = getIconColor(type),
164
- size = iconSize,
122
+ size = specs.icon,
165
123
  )
166
124
  }
167
- }
125
+ }
@@ -4,6 +4,10 @@ import androidx.compose.runtime.Composable
4
4
  import androidx.compose.runtime.CompositionLocalProvider
5
5
  import vn.momo.kits.application.ScaleSizeMaxRate
6
6
 
7
+ @Deprecated(
8
+ "Max font scale is fixed at MAX_FONT_SCALE (1.5); this override is no longer applied. Remove the wrapper.",
9
+ ReplaceWith("content()"),
10
+ )
7
11
  @Composable
8
12
  fun ScaleSizeScope(
9
13
  scaleSizeMaxRate: Float? = null,
@@ -0,0 +1,22 @@
1
+ package vn.momo.kits.const
2
+
3
+ import androidx.compose.runtime.getValue
4
+ import androidx.compose.runtime.mutableStateOf
5
+ import androidx.compose.runtime.setValue
6
+
7
+ // App-wide font-scale holder. The kit is sandboxed and can't read the host cache directly, so the
8
+ // host (which sees both core and this kit) seeds this once at startup and pushes runtime updates into
9
+ // it. scaleSize() reads it as the fallback, so every screen — including direct NavigationContainer
10
+ // screens with no host-pushed MiniAppContext — scales with no per-render prop and no async flicker.
11
+ // Backed by snapshot state: writes recompose text automatically.
12
+ object KitFontScale {
13
+ var userScaleRate by mutableStateOf(1f)
14
+ private set
15
+ var useOSScaleRate by mutableStateOf(true)
16
+ private set
17
+
18
+ fun update(userScaleRate: Float, useOSScaleRate: Boolean) {
19
+ this.userScaleRate = userScaleRate
20
+ this.useOSScaleRate = useOSScaleRate
21
+ }
22
+ }
@@ -11,7 +11,7 @@ import androidx.compose.ui.unit.*
11
11
  import org.jetbrains.compose.resources.Font
12
12
  import org.jetbrains.compose.resources.FontResource
13
13
  import org.jetbrains.compose.resources.InternalResourceApi
14
- import vn.momo.kits.application.ScaleSizeMaxRate
14
+ import vn.momo.kits.application.LocalContext
15
15
  import vn.momo.kits.platform.getScreenDimensions
16
16
  import vn.momo.uikits.resources.*
17
17
  import kotlin.math.max
@@ -23,7 +23,13 @@ const val MAX_DEVICE_SCALE = 5
23
23
 
24
24
  @Composable
25
25
  fun scaleSize(size: Float): Float {
26
- val scaleSizeMaxRate: Float = ScaleSizeMaxRate.current ?: MAX_FONT_SCALE
26
+ val context = LocalContext.current
27
+ // Host-pushed context wins; otherwise fall back to the app-wide KitFontScale holder.
28
+ val useOsScale = context?.useOSScaleRate ?: KitFontScale.useOSScaleRate
29
+ if (!useOsScale) {
30
+ return size * (context?.userScaleRate ?: KitFontScale.userScaleRate)
31
+ }
32
+ val scaleSizeMaxRate: Float = MAX_FONT_SCALE
27
33
  val deviceWidth = getScreenDimensions().width
28
34
  val deviceScale = deviceWidth / DEFAULT_SCREEN_SIZE
29
35
 
@@ -85,7 +85,9 @@ data class NavigationOptions(
85
85
  val footerComponent: @Composable (() -> Unit)? = null,
86
86
  val floatingButtonProps: FloatingButtonProps? = null,
87
87
  val keyboardOptions: KeyboardOptions = KeyboardOptions()
88
- )
88
+ ) {
89
+ internal fun hasFooter() : Boolean = footerComponent != null
90
+ }
89
91
 
90
92
  data class KeyboardOptions(
91
93
  val keyboardShouldPersistTaps: Boolean = false,
@@ -1,17 +1,35 @@
1
1
  package vn.momo.kits.navigation
2
2
 
3
- import androidx.compose.animation.*
4
3
  import androidx.compose.animation.core.tween
5
- import androidx.compose.runtime.*
4
+ import androidx.compose.animation.fadeIn
5
+ import androidx.compose.animation.slideInHorizontally
6
+ import androidx.compose.animation.slideInVertically
7
+ import androidx.compose.animation.slideOutHorizontally
8
+ import androidx.compose.animation.slideOutVertically
9
+ import androidx.compose.runtime.Composable
10
+ import androidx.compose.runtime.CompositionLocalProvider
11
+ import androidx.compose.runtime.DisposableEffect
12
+ import androidx.compose.runtime.LaunchedEffect
13
+ import androidx.compose.runtime.mutableStateOf
14
+ import androidx.compose.runtime.remember
6
15
  import androidx.compose.runtime.saveable.rememberSaveable
16
+ import androidx.compose.runtime.staticCompositionLocalOf
7
17
  import androidx.compose.ui.unit.Dp
8
18
  import androidx.navigation.compose.NavHost
9
19
  import androidx.navigation.compose.composable
10
20
  import androidx.navigation.compose.rememberNavController
11
21
  import androidx.navigation.toRoute
12
- import vn.momo.kits.application.*
13
- import vn.momo.kits.const.*
22
+ import vn.momo.kits.application.LocalContext
23
+ import vn.momo.kits.application.LocalLocalize
24
+ import vn.momo.kits.application.Localize
25
+ import vn.momo.kits.application.MiniAppContext
26
+ import vn.momo.kits.const.AppNavigationBar
27
+ import vn.momo.kits.const.AppStatusBar
28
+ import vn.momo.kits.const.AppTheme
29
+ import vn.momo.kits.const.Theme
30
+ import vn.momo.kits.const.defaultTheme
14
31
  import vn.momo.kits.platform.ProvideNavigationEventDispatcherOwner
32
+ import vn.momo.kits.platform.ProvideOsFontScale
15
33
  import vn.momo.kits.utils.getAppStatusBarHeight
16
34
  import vn.momo.kits.utils.getNavigationBarHeight
17
35
  import vn.momo.maxapi.IMaxApi
@@ -27,7 +45,7 @@ fun NavigationContainer(
27
45
  setNavigator: ((Navigator) -> Unit)? = null,
28
46
  statusBarHeight: Dp? = null,
29
47
  localize: Localize? = null,
30
- ){
48
+ ) {
31
49
  val navController = rememberNavController()
32
50
  val registry = remember { DynamicScreenRegistry() }
33
51
  val navigator = remember { Navigator(navController = navController, maxApi = maxApi, registry = registry) }
@@ -57,77 +75,79 @@ fun NavigationContainer(
57
75
  registry.bind(screenId, initialScreenName, initialScreen, options)
58
76
  val startDestination = remember(screenId) { DynamicScreenRoute(screenId) }
59
77
 
60
- ProvideNavigationEventDispatcherOwner {
61
- CompositionLocalProvider(
62
- LocalNavigator provides navigator,
63
- LocalDynamicScreenRegistry provides registry,
64
- LocalMaxApi provides maxApi,
65
- AppTheme provides theme.value,
66
- AppStatusBar provides statusBarHeight,
67
- AppNavigationBar provides navigationBarHeight,
68
- LocalContext provides mergedContext,
69
- LocalLocalize provides resolvedLocalize,
78
+ ProvideOsFontScale {
79
+ ProvideNavigationEventDispatcherOwner {
80
+ CompositionLocalProvider(
81
+ LocalNavigator provides navigator,
82
+ LocalDynamicScreenRegistry provides registry,
83
+ LocalMaxApi provides maxApi,
84
+ AppTheme provides theme.value,
85
+ AppStatusBar provides statusBarHeight,
86
+ AppNavigationBar provides navigationBarHeight,
87
+ LocalContext provides mergedContext,
88
+ LocalLocalize provides resolvedLocalize,
70
89
  ) {
71
- LaunchedEffect(Unit) {
72
- setNavigator?.invoke(navigator)
73
- }
74
-
75
- NavHost(navController, startDestination = startDestination) {
76
- composable<DynamicScreenRoute>(
77
- enterTransition = {
78
- slideInHorizontally(
79
- animationSpec = tween(300),
80
- initialOffsetX = { it }
81
- )
82
- },
83
- exitTransition = null,
84
- popEnterTransition = { fadeIn(animationSpec = tween(0)) },
85
- popExitTransition = {
86
- slideOutHorizontally(
87
- animationSpec = tween(300),
88
- targetOffsetX = { it }
89
- )
90
- }
91
- ) { backStackEntry ->
92
- val route = backStackEntry.toRoute<DynamicScreenRoute>()
93
- val screen = registry.getScreen(route.id)
94
-
95
- if (screen != null) {
96
- StackScreen(
97
- id = route.id,
98
- name = screen.name,
99
- content = screen.content,
100
- navigationOptions = screen.options
101
- )
102
- }
90
+ LaunchedEffect(Unit) {
91
+ setNavigator?.invoke(navigator)
103
92
  }
104
93
 
105
- composable<DynamicDialogRoute>(
106
- enterTransition = {
107
- slideInVertically(
108
- animationSpec = tween(300),
109
- initialOffsetY = { it }
110
- )
111
- },
112
- exitTransition = null,
113
- popEnterTransition = { fadeIn(animationSpec = tween(0)) },
114
- popExitTransition = {
115
- slideOutVertically(
116
- animationSpec = tween(300),
117
- targetOffsetY = { it }
118
- )
94
+ NavHost(navController, startDestination = startDestination) {
95
+ composable<DynamicScreenRoute>(
96
+ enterTransition = {
97
+ slideInHorizontally(
98
+ animationSpec = tween(300),
99
+ initialOffsetX = { it }
100
+ )
101
+ },
102
+ exitTransition = null,
103
+ popEnterTransition = { fadeIn(animationSpec = tween(0)) },
104
+ popExitTransition = {
105
+ slideOutHorizontally(
106
+ animationSpec = tween(300),
107
+ targetOffsetX = { it }
108
+ )
109
+ }
110
+ ) { backStackEntry ->
111
+ val route = backStackEntry.toRoute<DynamicScreenRoute>()
112
+ val screen = registry.getScreen(route.id)
113
+
114
+ if (screen != null) {
115
+ StackScreen(
116
+ id = route.id,
117
+ name = screen.name,
118
+ content = screen.content,
119
+ navigationOptions = screen.options
120
+ )
121
+ }
119
122
  }
120
- ) { backStackEntry ->
121
- val route = backStackEntry.toRoute<DynamicDialogRoute>()
122
- val screen = registry.getScreen(route.id)
123
-
124
- if (screen != null) {
125
- StackScreen(
126
- id = route.id,
127
- name = screen.name,
128
- content = screen.content,
129
- navigationOptions = screen.options
130
- )
123
+
124
+ composable<DynamicDialogRoute>(
125
+ enterTransition = {
126
+ slideInVertically(
127
+ animationSpec = tween(300),
128
+ initialOffsetY = { it }
129
+ )
130
+ },
131
+ exitTransition = null,
132
+ popEnterTransition = { fadeIn(animationSpec = tween(0)) },
133
+ popExitTransition = {
134
+ slideOutVertically(
135
+ animationSpec = tween(300),
136
+ targetOffsetY = { it }
137
+ )
138
+ }
139
+ ) { backStackEntry ->
140
+ val route = backStackEntry.toRoute<DynamicDialogRoute>()
141
+ val screen = registry.getScreen(route.id)
142
+
143
+ if (screen != null) {
144
+ StackScreen(
145
+ id = route.id,
146
+ name = screen.name,
147
+ content = screen.content,
148
+ navigationOptions = screen.options
149
+ )
150
+ }
131
151
  }
132
152
  }
133
153
  }
@@ -142,9 +162,7 @@ fun NavigationContainer(
142
162
  }
143
163
  }
144
164
 
145
- val LocalMaxApi = staticCompositionLocalOf<IMaxApi?> {
146
- error("No MaxApi provided")
147
- }
165
+ val LocalMaxApi = staticCompositionLocalOf<IMaxApi?> { null }
148
166
 
149
167
  private fun parseLanguage(raw: Map<String, Any?>?): String? {
150
168
  val code = (raw?.get("response") as? String)?.trim()?.lowercase()
@@ -56,6 +56,7 @@ import vn.momo.kits.const.Colors
56
56
  import vn.momo.kits.const.Spacing
57
57
  import vn.momo.kits.modifier.conditional
58
58
  import vn.momo.kits.modifier.hideKeyboardOnTap
59
+ import vn.momo.kits.navigation.bottomtab.BOTTOM_TAB_BAR_HEIGHT
59
60
  import vn.momo.kits.navigation.component.FABPosition
60
61
  import vn.momo.kits.navigation.component.FloatingButton
61
62
  import vn.momo.kits.navigation.component.HEADER_HEIGHT
@@ -77,6 +78,13 @@ import kotlin.time.ExperimentalTime
77
78
  internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
78
79
  internal val LocalHeaderRightWidthPx = staticCompositionLocalOf { mutableIntStateOf(0) }
79
80
 
81
+ @Composable
82
+ private fun bottomTabBarInset(): Dp {
83
+ if (LocalNavigation.current.bottomTabIndex == -1) return 0.dp
84
+ val keyboard = keyboardSizeState().value
85
+ return (BOTTOM_TAB_BAR_HEIGHT.dp + Spacing.S - keyboard).coerceAtLeast(0.dp)
86
+ }
87
+
80
88
  @OptIn(ExperimentalMaterialApi::class, ExperimentalTime::class)
81
89
  @Composable
82
90
  internal fun StackScreen(
@@ -195,12 +203,12 @@ internal fun StackScreen(
195
203
  }
196
204
 
197
205
  Column(Modifier.zIndex(2f).fillMaxSize()) {
198
- MainContent(content = content, isBottomTab = isBottomTabRoot)
206
+ MainContent(content = content, isBottomTabRoot = isBottomTabRoot, isBottomTabChild = isBottomTabChild)
199
207
  FooterContent()
200
208
  }
201
209
 
202
210
  Box(Modifier.zIndex(6f)) {
203
- FloatingContent()
211
+ FloatingContent(isBottomTabChild = isBottomTabChild)
204
212
  }
205
213
 
206
214
  OverplayView(isBottomTabChild = isBottomTabChild, id = id)
@@ -210,7 +218,7 @@ internal fun StackScreen(
210
218
 
211
219
  @Suppress("FrequentlyChangingValue")
212
220
  @Composable
213
- internal fun FloatingContent() {
221
+ internal fun FloatingContent(isBottomTabChild: Boolean) {
214
222
  val options = LocalOptions.current
215
223
  val density = LocalDensity.current
216
224
  val footerHeightPx = LocalFooterHeightPx.current
@@ -219,7 +227,11 @@ internal fun FloatingContent() {
219
227
 
220
228
  val fabProps = options.floatingButtonProps ?: return
221
229
  val bottomPadding = fabProps.bottom
222
- ?: (Spacing.M + if (options.footerComponent != null) with(density) { footerHeightPx.intValue.toDp() } else navigationBar)
230
+ ?: (Spacing.M + when {
231
+ options.hasFooter() -> with(density) { footerHeightPx.intValue.toDp() }
232
+ isBottomTabChild -> bottomTabBarInset() + (navigationBar - keyboardSizeState().value).coerceAtLeast(0.dp)
233
+ else -> navigationBar
234
+ })
223
235
 
224
236
  FloatingButton(
225
237
  scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
@@ -235,7 +247,7 @@ internal fun FloatingContent() {
235
247
  }
236
248
 
237
249
  @Composable
238
- internal fun ColumnScope.MainContent(content: @Composable () -> Unit, isBottomTab: Boolean) {
250
+ internal fun ColumnScope.MainContent(content: @Composable () -> Unit, isBottomTabRoot: Boolean, isBottomTabChild: Boolean) {
239
251
  val options = LocalOptions.current
240
252
  val inputSearchType = getInputSearchType(options)
241
253
  val density = LocalDensity.current
@@ -264,7 +276,13 @@ internal fun ColumnScope.MainContent(content: @Composable () -> Unit, isBottomTa
264
276
  .conditional(options.scrollData.scrollable && options.scrollData.scrollState is ScrollState) {
265
277
  verticalScroll(scrollState)
266
278
  }
267
- .padding(bottom = if (options.footerComponent != null || isBottomTab) 0.dp else navigationBar)
279
+ .padding(
280
+ bottom = when {
281
+ options.hasFooter() || isBottomTabRoot -> 0.dp
282
+ isBottomTabChild -> bottomTabBarInset() + (navigationBar - keyboardSizeState().value).coerceAtLeast(0.dp)
283
+ else -> navigationBar
284
+ }
285
+ )
268
286
  ) {
269
287
  ScreenContent(content = content)
270
288
  }
@@ -294,7 +312,7 @@ internal fun ScreenContent(content: @Composable () -> Unit) {
294
312
  @Composable
295
313
  internal fun FooterContent() {
296
314
  val options = LocalOptions.current
297
- if (options.footerComponent != null) {
315
+ if (options.hasFooter()) {
298
316
  val keyboardSize = keyboardSizeState()
299
317
  val bottomPadding = (AppNavigationBar.current - keyboardSize.value).coerceAtLeast(0.dp)
300
318
  Footer(footerComponent = options.footerComponent, bottomPadding = bottomPadding)
@@ -18,6 +18,7 @@ import androidx.navigation.compose.rememberNavController
18
18
  import vn.momo.kits.const.AppNavigationBar
19
19
  import vn.momo.kits.const.AppTheme
20
20
  import vn.momo.kits.const.Spacing
21
+ import vn.momo.kits.navigation.KeyboardOptions
21
22
  import vn.momo.kits.navigation.LocalNavigation
22
23
  import vn.momo.kits.navigation.LocalNavigator
23
24
  import vn.momo.kits.navigation.NavigationOptions
@@ -53,7 +54,8 @@ fun BottomTab(
53
54
  LaunchedEffect(Unit){
54
55
  navigation.markAsBottomTabRoot()
55
56
  navigation.setOptions(
56
- headerType = HeaderType.None
57
+ headerType = HeaderType.None,
58
+ keyboardOptions = KeyboardOptions(useAvoidKeyboard = false)
57
59
  )
58
60
  }
59
61