@momo-kits/native-kits 0.167.1-beta.15-debug → 0.167.1-beta.16

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 (167) hide show
  1. package/CLAUDE.md +6 -4
  2. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +32 -0
  3. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  4. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  5. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +16 -0
  6. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
  7. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
  8. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
  9. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
  10. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
  11. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
  12. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
  13. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +58 -0
  14. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +58 -0
  15. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +60 -0
  16. package/ios/Application/ApplicationEnvironment.swift +13 -6
  17. package/ios/Application/DesignSystemKits.swift +100 -0
  18. package/ios/Application/DesignSystemKitsPayload.swift +68 -0
  19. package/ios/Template/TrustBanner/TrustBanner.swift +39 -7
  20. package/ios/Typography/FontScale.swift +14 -11
  21. package/ios/Typography/Text.swift +19 -7
  22. package/ios/Typography/Typography.swift +2 -2
  23. package/ios/native-kits.podspec +1 -1
  24. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  25. package/package.json +1 -1
  26. package/build.gradle.kts +0 -11
  27. package/compose/build.gradle.kts +0 -190
  28. package/compose/build.gradle.kts.backup +0 -190
  29. package/compose/compose.podspec +0 -47
  30. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  31. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  32. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  33. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  34. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -151
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -86
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -328
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -97
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -20
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -194
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -282
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -51
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -299
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -129
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -201
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -595
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -184
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -225
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -357
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -83
  137. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -106
  138. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -75
  139. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -309
  140. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -39
  141. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -364
  142. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  143. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  144. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  145. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  146. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  147. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -71
  148. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  149. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  150. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  151. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -105
  152. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -78
  153. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  154. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  155. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  156. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  157. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -213
  158. package/gradle/libs.versions.toml +0 -69
  159. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  160. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  161. package/gradle.properties +0 -26
  162. package/gradlew +0 -252
  163. package/gradlew.bat +0 -94
  164. package/ios/Typography/FontScaleStore.swift +0 -58
  165. package/ios/Typography/KitDesignSystem.swift +0 -17
  166. package/ios-demo/README.md +0 -120
  167. package/settings.gradle.kts +0 -64
@@ -1,595 +0,0 @@
1
- package vn.momo.kits.navigation
2
-
3
- import androidx.compose.animation.animateColorAsState
4
- import androidx.compose.foundation.ScrollState
5
- import androidx.compose.foundation.background
6
- import androidx.compose.foundation.border
7
- import androidx.compose.foundation.gestures.ScrollableState
8
- import androidx.compose.foundation.gestures.animateScrollBy
9
- import androidx.compose.foundation.layout.Box
10
- import androidx.compose.foundation.layout.Column
11
- import androidx.compose.foundation.layout.ColumnScope
12
- import androidx.compose.foundation.layout.Spacer
13
- import androidx.compose.foundation.layout.WindowInsets
14
- import androidx.compose.foundation.layout.asPaddingValues
15
- import androidx.compose.foundation.layout.aspectRatio
16
- import androidx.compose.foundation.layout.fillMaxSize
17
- import androidx.compose.foundation.layout.fillMaxWidth
18
- import androidx.compose.foundation.layout.height
19
- import androidx.compose.foundation.layout.ime
20
- import androidx.compose.foundation.layout.imePadding
21
- import androidx.compose.foundation.layout.offset
22
- import androidx.compose.foundation.layout.padding
23
- import androidx.compose.foundation.lazy.LazyListState
24
- import androidx.compose.foundation.rememberScrollState
25
- import androidx.compose.foundation.verticalScroll
26
- import androidx.compose.material.ExperimentalMaterialApi
27
- import androidx.compose.runtime.Composable
28
- import androidx.compose.runtime.CompositionLocalProvider
29
- import androidx.compose.runtime.LaunchedEffect
30
- import androidx.compose.runtime.State
31
- import androidx.compose.runtime.getValue
32
- import androidx.compose.runtime.mutableIntStateOf
33
- import androidx.compose.runtime.mutableStateOf
34
- import androidx.compose.runtime.remember
35
- import androidx.compose.runtime.rememberUpdatedState
36
- import androidx.compose.runtime.snapshotFlow
37
- import androidx.compose.runtime.staticCompositionLocalOf
38
- import androidx.compose.ui.Alignment
39
- import androidx.compose.ui.Modifier
40
- import androidx.compose.ui.graphics.Brush
41
- import androidx.compose.ui.graphics.Color
42
- import androidx.compose.ui.graphics.lerp
43
- import androidx.compose.ui.layout.onGloballyPositioned
44
- import androidx.compose.ui.platform.LocalDensity
45
- import androidx.compose.ui.unit.Dp
46
- import androidx.compose.ui.unit.dp
47
- import androidx.compose.ui.unit.lerp
48
- import androidx.compose.ui.zIndex
49
- import kotlinx.coroutines.flow.Flow
50
- import kotlinx.coroutines.flow.filter
51
- import kotlinx.coroutines.launch
52
- import vn.momo.kits.components.InputSearch
53
- import vn.momo.kits.const.AppNavigationBar
54
- import vn.momo.kits.const.AppStatusBar
55
- import vn.momo.kits.const.AppTheme
56
- import vn.momo.kits.application.IsShowBaseLineDebug
57
- import vn.momo.kits.const.Colors
58
- import vn.momo.kits.const.Spacing
59
- import vn.momo.kits.modifier.conditional
60
- import vn.momo.kits.modifier.hideKeyboardOnTap
61
- import vn.momo.kits.navigation.bottomtab.BOTTOM_TAB_BAR_HEIGHT
62
- import vn.momo.kits.navigation.component.FABPosition
63
- import vn.momo.kits.navigation.component.FloatingButton
64
- import vn.momo.kits.navigation.component.HEADER_HEIGHT
65
- import vn.momo.kits.navigation.component.Header
66
- import vn.momo.kits.navigation.component.HeaderBackground
67
- import vn.momo.kits.navigation.component.HeaderRight
68
- import vn.momo.kits.navigation.component.HeaderType
69
- import vn.momo.kits.navigation.component.InputSearchType
70
- import vn.momo.kits.platform.BackHandler
71
- import vn.momo.kits.platform.supportsImePadding
72
- import vn.momo.kits.navigation.tracking.ScreenTracker
73
- import vn.momo.kits.navigation.tracking.ScreenTrackingState
74
- import kotlinx.coroutines.delay
75
- import vn.momo.kits.application.LocalContext
76
- import kotlin.time.Clock
77
- import kotlin.time.Duration.Companion.milliseconds
78
- import kotlin.time.ExperimentalTime
79
-
80
- internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
81
- internal val LocalHeaderRightWidthPx = staticCompositionLocalOf { mutableIntStateOf(0) }
82
-
83
- @Composable
84
- private fun bottomTabBarInset(): Dp {
85
- if (LocalNavigation.current.bottomTabIndex == -1) return 0.dp
86
- val keyboard = keyboardSizeState().value
87
- return (BOTTOM_TAB_BAR_HEIGHT.dp + Spacing.S - keyboard).coerceAtLeast(0.dp)
88
- }
89
-
90
- @OptIn(ExperimentalMaterialApi::class, ExperimentalTime::class)
91
- @Composable
92
- internal fun StackScreen(
93
- content: @Composable () -> Unit,
94
- navigationOptions: NavigationOptions? = null,
95
- id: Int = -1,
96
- name: String = "",
97
- bottomTabIndex: Int = -1,
98
- onBackHandler: (() -> Unit)? = null,
99
- ) {
100
- val navigator = LocalNavigator.current
101
- val maxApi = LocalMaxApi.current
102
- val context = LocalContext.current
103
- val statusBar = AppStatusBar.current
104
- val density = LocalDensity.current
105
- val screenRegistry = LocalDynamicScreenRegistry.current
106
- val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions, registry = screenRegistry) }
107
-
108
- val options by navigation.currentOptions
109
- val isBottomTabChild = bottomTabIndex != -1
110
- val isBottomTabRoot = navigation.isBottomTabRoot
111
-
112
- // Auto tracking state
113
- val trackingState = remember {
114
- ScreenTrackingState().apply {
115
- time = Clock.System.now().toEpochMilliseconds()
116
- }
117
- }
118
-
119
- // Determine action: push or back
120
- val action = remember {
121
- if (ScreenTracker.getLastScreenName() != null) "push" else "back"
122
- }
123
-
124
- // Auto tracking effects
125
- LaunchedEffect(name) {
126
- // Track screen navigated immediately
127
- ScreenTracker.trackScreenNavigated(
128
- maxApi = maxApi,
129
- context = context,
130
- screenName = name,
131
- action = action,
132
- state = trackingState
133
- )
134
-
135
- // Track screen displayed after 2 seconds (debounce)
136
- delay(2000.milliseconds)
137
- val loadTime = Clock.System.now().toEpochMilliseconds() - trackingState.time
138
- ScreenTracker.trackScreenDisplayed(
139
- maxApi = maxApi,
140
- context = context,
141
- screenName = name,
142
- duration = loadTime,
143
- state = trackingState
144
- )
145
-
146
- // Track screen interacted after displayed
147
- val interactionTime = Clock.System.now().toEpochMilliseconds() - trackingState.time
148
- ScreenTracker.trackScreenInteracted(
149
- maxApi = maxApi,
150
- context = context,
151
- screenName = name,
152
- duration = interactionTime - loadTime,
153
- totalDuration = interactionTime,
154
- state = trackingState
155
- )
156
- }
157
-
158
- val limit = with(density) {
159
- (statusBar + HEADER_HEIGHT.dp).toPx()
160
- }.toInt()
161
-
162
- val lazyListState = options.scrollData.scrollState as? LazyListState
163
- val (scrollState, _) = if (lazyListState != null)
164
- lazyListState.proxyScrollState(limit, 1)
165
- else
166
- (options.scrollData.scrollState as? ScrollState ?: rememberScrollState()).proxyLimitedScrollState(limit, 1)
167
- val snapState: ScrollableState = lazyListState ?: scrollState
168
-
169
- val footerHeightPx = remember { mutableIntStateOf(0) }
170
- val headerRightWidthPx = remember { mutableIntStateOf(0) }
171
-
172
- if (navigation.options.scrollData.scrollToTopCallback != null) {
173
- RegisterScrollToTop(navigation.options.scrollData.scrollToTopCallback)
174
- }
175
-
176
- val canPop = navigator.canPop()
177
-
178
- val hasCustomBackHandling = !SwipeBackConfig.enabled ||
179
- OverplayComponentRegistry.isOverplayShowing() ||
180
- !canPop
181
-
182
- BackHandler(hasCustomBackHandling) { navigator.onBackSafe() }
183
-
184
- CompositionLocalProvider(
185
- StackScreenScrollableState provides options.scrollData.scrollState,
186
- LocalNavigation provides navigation,
187
- LocalScrollState provides scrollState,
188
- LocalOptions provides options,
189
- LocalFooterHeightPx provides footerHeightPx,
190
- LocalHeaderRightWidthPx provides headerRightWidthPx
191
- ) {
192
- Box(
193
- Modifier
194
- .fillMaxSize()
195
- .background(options.backgroundColor ?: AppTheme.current.colors.background.default)
196
- .conditional(options.keyboardOptions.keyboardShouldPersistTaps) {
197
- hideKeyboardOnTap()
198
- }
199
- .conditional(options.keyboardOptions.useAvoidKeyboard && supportsImePadding()) {
200
- imePadding()
201
- }
202
- ) {
203
- Box(Modifier.zIndex(1f)) {
204
- HeaderBackground()
205
- }
206
-
207
- Box(Modifier.zIndex(4f)) {
208
- Header(onBackHandler)
209
- }
210
-
211
- Column(Modifier.zIndex(5f)) {
212
- SearchAnimated(snapState = snapState)
213
- }
214
-
215
- Column(Modifier.zIndex(2f).fillMaxSize()) {
216
- MainContent(content = content, isBottomTabRoot = isBottomTabRoot, isBottomTabChild = isBottomTabChild)
217
- FooterContent()
218
- }
219
-
220
- Box(Modifier.zIndex(6f)) {
221
- FloatingContent(isBottomTabChild = isBottomTabChild)
222
- }
223
-
224
- OverplayView(isBottomTabChild = isBottomTabChild, id = id)
225
- }
226
- }
227
- }
228
-
229
- @Suppress("FrequentlyChangingValue")
230
- @Composable
231
- internal fun FloatingContent(isBottomTabChild: Boolean) {
232
- val options = LocalOptions.current
233
- val density = LocalDensity.current
234
- val footerHeightPx = LocalFooterHeightPx.current
235
- val scrollState = LocalScrollState.current
236
- val navigationBar = AppNavigationBar.current
237
-
238
- val fabProps = options.floatingButtonProps ?: return
239
- val bottomPadding = fabProps.bottom
240
- ?: (Spacing.M + when {
241
- options.hasFooter() -> with(density) { footerHeightPx.intValue.toDp() }
242
- isBottomTabChild -> bottomTabBarInset() + (navigationBar - keyboardSizeState().value).coerceAtLeast(0.dp)
243
- else -> navigationBar
244
- })
245
-
246
- FloatingButton(
247
- scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
248
- onClick = fabProps.onClick,
249
- containerColor = AppTheme.current.colors.primary,
250
- bottom = bottomPadding,
251
- icon = fabProps.icon,
252
- iconColor = fabProps.iconColor,
253
- text = fabProps.label,
254
- size = fabProps.size,
255
- position = fabProps.position ?: FABPosition.END,
256
- )
257
- }
258
-
259
- @Composable
260
- internal fun ColumnScope.MainContent(content: @Composable () -> Unit, isBottomTabRoot: Boolean, isBottomTabChild: Boolean) {
261
- val options = LocalOptions.current
262
- val inputSearchType = getInputSearchType(options)
263
- val density = LocalDensity.current
264
- val scrollState = LocalScrollState.current
265
- val navigationBar = AppNavigationBar.current
266
-
267
- Spacer(
268
- Modifier.height(
269
- if (options.headerType is HeaderType.DefaultOrExtended || (options.headerType is HeaderType.Transparent && !options.headerType.isFullScreenContent))
270
- AppStatusBar.current + HEADER_HEIGHT.dp else 0.dp
271
- )
272
- )
273
- if (inputSearchType == InputSearchType.Animated) {
274
- val scrollDp = with(density) { scrollState.value.toDp() }
275
-
276
- Spacer(Modifier.height((HEADER_HEIGHT.dp - scrollDp).coerceIn(0.dp, HEADER_HEIGHT.dp)))
277
- }
278
- Column(
279
- Modifier
280
- .fillMaxWidth()
281
- .weight(1f)
282
- .conditional(options.scrollData.scrollable && options.scrollData.scrollState is ScrollState) {
283
- verticalScroll(scrollState)
284
- }
285
- .padding(
286
- bottom = when {
287
- options.hasFooter() || isBottomTabRoot -> 0.dp
288
- isBottomTabChild -> bottomTabBarInset() + (navigationBar - keyboardSizeState().value).coerceAtLeast(0.dp)
289
- !options.scrollData.scrollable && options.scrollData.scrollState == null -> 0.dp
290
- else -> navigationBar
291
- }
292
- )
293
- ) {
294
- ScreenContent(content = content)
295
- }
296
-
297
- }
298
-
299
- @Composable
300
- internal fun ScreenContent(content: @Composable () -> Unit) {
301
- val scrollState = LocalScrollState.current
302
- val options = LocalOptions.current
303
-
304
- if (options.headerType is HeaderType.Animated) {
305
- val animatedHeader = options.headerType
306
- Box {
307
- val bannerModifier = animatedHeader.height
308
- ?.let { Modifier.fillMaxWidth().height(it) }
309
- ?: Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)
310
- Box(bannerModifier) {
311
- animatedHeader.composable.invoke(scrollState.value)
312
- }
313
- Box(Modifier.padding(top = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)) {
314
- content()
315
- }
316
- }
317
- } else {
318
- content()
319
- }
320
- }
321
-
322
- @Composable
323
- internal fun FooterContent() {
324
- val options = LocalOptions.current
325
- if (options.hasFooter()) {
326
- val keyboardSize = keyboardSizeState()
327
- val bottomPadding = (AppNavigationBar.current - keyboardSize.value).coerceAtLeast(0.dp)
328
- Footer(
329
- footerComponent = options.footerComponent,
330
- bottomPadding = bottomPadding,
331
- transparent = options.footerTransparent,
332
- useMargin = options.footerUseMargin
333
- )
334
- }
335
- }
336
-
337
- @Composable
338
- internal fun keyboardSizeState(): State<Dp> {
339
- val bottom = WindowInsets.ime.asPaddingValues()
340
- return rememberUpdatedState(bottom.calculateBottomPadding())
341
- }
342
-
343
- @Composable
344
- internal fun OverplayView(isBottomTabChild: Boolean, id: Int) {
345
- val overplayType = OverplayComponentRegistry.getOverplayType()
346
-
347
- if (overplayType != null) {
348
- Box(Modifier.zIndex(if (overplayType == OverplayComponentType.SNACK_BAR) 3f else 7f).fillMaxSize()) {
349
- if (isBottomTabChild) return@Box
350
- if (OverplayComponentRegistry.currentRootId() != id) return@Box
351
- OverplayComponentRegistry.OverlayComponent()
352
- }
353
- }
354
- }
355
-
356
- @Composable
357
- fun Footer(
358
- footerComponent: @Composable (() -> Unit)?,
359
- bottomPadding: Dp,
360
- transparent: Boolean = false,
361
- useMargin: Boolean = true,
362
- ) {
363
- if (footerComponent == null) return
364
-
365
- val footerHeightPx = LocalFooterHeightPx.current
366
-
367
- val shadowBrush = remember {
368
- Brush.verticalGradient(
369
- colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.05f))
370
- )
371
- }
372
-
373
- val backgroundColor = if (transparent) Color.Transparent else AppTheme.current.colors.background.surface
374
-
375
- Box(Modifier.onGloballyPositioned {
376
- if (footerHeightPx.intValue != it.size.height) footerHeightPx.intValue = it.size.height
377
- }) {
378
- Box(
379
- Modifier
380
- .fillMaxWidth()
381
- .background(backgroundColor)
382
- .conditional(IsShowBaseLineDebug) {
383
- border(1.dp, Colors.blue_03)
384
- }
385
- .padding(
386
- top = if (useMargin) Spacing.S else 0.dp,
387
- start = if (useMargin) Spacing.M else 0.dp,
388
- end = if (useMargin) Spacing.M else 0.dp,
389
- bottom = bottomPadding + if (useMargin) Spacing.S else 0.dp,
390
- )
391
- ) {
392
- footerComponent.invoke()
393
- }
394
-
395
- if (!transparent) {
396
- Box(
397
- modifier = Modifier
398
- .fillMaxWidth()
399
- .height(6.dp)
400
- .offset(x = 0.dp, y = (-6).dp)
401
- .background(shadowBrush)
402
- )
403
- }
404
- }
405
- }
406
-
407
- data class InputSearchLayoutParams(
408
- val topPadding: Dp,
409
- val startPadding: Dp,
410
- val endPadding: Dp
411
- )
412
-
413
- @Suppress("FrequentlyChangingValue")
414
- @Composable
415
- internal fun SearchAnimated(
416
- snapState: ScrollableState
417
- ) {
418
- val scrollState = LocalScrollState.current
419
- val options = LocalOptions.current
420
- val navigator = LocalNavigator.current
421
- val density = LocalDensity.current
422
-
423
- val scrollDp = with(density) { scrollState.value.toDp() }
424
-
425
- val inputSearchType = getInputSearchType(options)
426
- val headerRightWidthPx = LocalHeaderRightWidthPx.current
427
- val headerRightWidthDp = with(density) { headerRightWidthPx.intValue.toDp() }
428
-
429
- if (inputSearchType == InputSearchType.None) return
430
- val inputSearchProps = (options.headerType as? HeaderType.DefaultOrExtended)?.inputSearchProps ?: return
431
-
432
- val minTopPadding = AppStatusBar.current
433
- val maxTopPadding = AppStatusBar.current + HEADER_HEIGHT.dp
434
- val minStartPadding = Spacing.M
435
- val maxStartPadding = if (options.hiddenBack) Spacing.M else 48.dp // button back: size + left +right = 28 + 12 + 8 = 48
436
- val minEndPadding = Spacing.M
437
- val maxEndPadding = headerRightWidthDp + if (options.headerRight is HeaderRight.None) Spacing.M else Spacing.M * 2
438
-
439
- val targetColor = lerp(
440
- AppTheme.current.colors.background.surface,
441
- AppTheme.current.colors.background.default,
442
- (scrollDp / minTopPadding).coerceIn(0f, 1f)
443
- )
444
- val animatedColor by animateColorAsState(targetValue = targetColor, label = "BackgroundColor")
445
-
446
- val layoutParams = when (inputSearchType) {
447
- InputSearchType.Header -> {
448
- InputSearchLayoutParams(
449
- topPadding = minTopPadding,
450
- startPadding = maxStartPadding,
451
- endPadding = maxEndPadding
452
- )
453
- }
454
-
455
- InputSearchType.Animated -> {
456
- val collapsePx = with(density) { HEADER_HEIGHT.dp.roundToPx() }
457
- val progress = (scrollState.value / collapsePx.toFloat()).coerceIn(0f, 1f)
458
-
459
- LaunchedEffect(snapState, collapsePx) {
460
- snapshotFlow { snapState.isScrollInProgress }
461
- .filter { !it }
462
- .collect {
463
- val offset = snapState.headerOffsetPx() ?: return@collect
464
- if (offset <= 0 || offset >= collapsePx) return@collect
465
- val target = if (offset < collapsePx / 2) 0 else collapsePx
466
- launch { snapState.animateScrollBy((target - offset).toFloat()) }
467
- }
468
- }
469
-
470
- InputSearchLayoutParams(
471
- topPadding = lerp(maxTopPadding, minTopPadding, progress),
472
- startPadding = lerp(minStartPadding, maxStartPadding, progress),
473
- endPadding = lerp(minEndPadding, maxEndPadding, progress)
474
- )
475
- }
476
-
477
- InputSearchType.None -> return
478
- }
479
-
480
- Spacer(Modifier.height(layoutParams.topPadding))
481
- Box(
482
- modifier = Modifier
483
- .height(HEADER_HEIGHT.dp)
484
- .fillMaxWidth()
485
- .padding(
486
- start = layoutParams.startPadding,
487
- end = layoutParams.endPadding
488
- ),
489
- contentAlignment = Alignment.Center
490
- ) {
491
- InputSearch(
492
- inputSearchProps = inputSearchProps.copy(
493
- backgroundColor = animatedColor,
494
- onPressButtonText = {
495
- navigator.pop()
496
- }
497
- )
498
- )
499
- }
500
- }
501
-
502
- private fun ScrollableState.headerOffsetPx(): Int? = when (this) {
503
- is LazyListState -> if (firstVisibleItemIndex == 0) firstVisibleItemScrollOffset else null
504
- is ScrollState -> value
505
- else -> null
506
- }
507
-
508
- private fun quantize(value: Int, stepPx: Int): Int {
509
- if (stepPx <= 1) return value
510
- return (value / stepPx) * stepPx
511
- }
512
-
513
- @Composable
514
- internal fun LazyListState.proxyScrollState(
515
- thresholdPx: Int = 200,
516
- stepPx: Int = 4
517
- ): Pair<ScrollState, Boolean> = proxyScroll(
518
- source = this,
519
- thresholdPx = thresholdPx,
520
- stepPx = stepPx,
521
- isScrollInProgress = { isScrollInProgress },
522
- rawTargetFlow = {
523
- snapshotFlow {
524
- if (firstVisibleItemIndex == 0) firstVisibleItemScrollOffset
525
- else SCROLLED_PAST_FIRST_ITEM_THRESHOLD
526
- }
527
- },
528
- )
529
-
530
- @Composable
531
- internal fun ScrollState.proxyLimitedScrollState(
532
- thresholdPx: Int = 200,
533
- stepPx: Int = 4
534
- ): Pair<ScrollState, Boolean> = proxyScroll(
535
- source = this,
536
- thresholdPx = thresholdPx,
537
- stepPx = stepPx,
538
- isScrollInProgress = { isScrollInProgress },
539
- rawTargetFlow = { snapshotFlow { value } },
540
- )
541
-
542
- @Composable
543
- private fun proxyScroll(
544
- source: Any,
545
- thresholdPx: Int,
546
- stepPx: Int,
547
- isScrollInProgress: () -> Boolean,
548
- rawTargetFlow: () -> Flow<Int>,
549
- ): Pair<ScrollState, Boolean> {
550
- val proxy = rememberScrollState()
551
- val locked = remember { mutableStateOf(false) }
552
-
553
- LaunchedEffect(source, proxy, thresholdPx, stepPx) {
554
- rawTargetFlow().collect { rawTarget ->
555
- val shouldLock = rawTarget > thresholdPx
556
- if (locked.value != shouldLock) locked.value = shouldLock
557
-
558
- val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
559
-
560
- if (proxy.value != desired) {
561
- proxy.scrollTo(desired.coerceAtLeast(0))
562
- }
563
- }
564
- }
565
-
566
- val inProgress = remember { mutableStateOf(false) }
567
- LaunchedEffect(source, thresholdPx) {
568
- snapshotFlow { isScrollInProgress() }
569
- .collect { progressing ->
570
- inProgress.value = if (locked.value) false else progressing
571
- }
572
- }
573
-
574
- return proxy to inProgress.value
575
- }
576
-
577
- private const val SCROLLED_PAST_FIRST_ITEM_THRESHOLD = 10_000
578
-
579
- internal val LocalScrollState = staticCompositionLocalOf<ScrollState> { error("No Scroll State provided") }
580
- internal val LocalOptions = staticCompositionLocalOf<NavigationOptions> { error("No NavigationOptions provided") }
581
-
582
- val StackScreenScrollableState = staticCompositionLocalOf<ScrollableState?> { null }
583
-
584
- internal fun getInputSearchType(options: NavigationOptions): InputSearchType {
585
- return when (val headerType = options.headerType) {
586
- is HeaderType.DefaultOrExtended -> when {
587
- headerType.inputSearchProps == null -> InputSearchType.None
588
- headerType.useAnimated -> InputSearchType.Animated
589
- else -> InputSearchType.Header
590
- }
591
-
592
- else -> InputSearchType.None
593
- }
594
- }
595
-