@momo-kits/native-kits 0.168.1-beta.25-debug → 0.168.1-beta.25
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/package.json +1 -1
- package/build.gradle.kts +0 -11
- package/compose/build.gradle.kts +0 -198
- package/compose/build.gradle.kts.backup +0 -198
- package/compose/compose.podspec +0 -47
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -20
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -153
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReduceMotion.android.kt +0 -17
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +0 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -110
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/DesignSystemKits.kt +0 -62
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -1071
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -81
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -357
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -115
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -478
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -265
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -235
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -265
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -370
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -308
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -330
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -207
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -92
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -560
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -501
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -236
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -180
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -17
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -194
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -287
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -321
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -499
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -148
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -116
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -422
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -732
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -232
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -237
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +0 -97
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoLiquidSelection.kt +0 -380
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +0 -436
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -455
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -105
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -106
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -399
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -39
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -192
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -133
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -74
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReduceMotion.kt +0 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +0 -20
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -42
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -218
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReduceMotion.ios.kt +0 -48
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +0 -138
- package/gradle/libs.versions.toml +0 -69
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +0 -8
- package/gradle.properties +0 -26
- package/gradlew +0 -252
- package/gradlew.bat +0 -94
- package/ios-demo/README.md +0 -120
- package/settings.gradle.kts +0 -64
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation.bottomtab
|
|
2
|
-
|
|
3
|
-
import androidx.compose.foundation.background
|
|
4
|
-
import androidx.compose.foundation.border
|
|
5
|
-
import androidx.compose.foundation.clickable
|
|
6
|
-
import androidx.compose.foundation.combinedClickable
|
|
7
|
-
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
8
|
-
import androidx.compose.foundation.layout.Arrangement
|
|
9
|
-
import androidx.compose.foundation.layout.Box
|
|
10
|
-
import androidx.compose.foundation.layout.BoxScope
|
|
11
|
-
import androidx.compose.foundation.layout.Column
|
|
12
|
-
import androidx.compose.foundation.layout.Row
|
|
13
|
-
import androidx.compose.foundation.layout.absolutePadding
|
|
14
|
-
import androidx.compose.foundation.layout.fillMaxHeight
|
|
15
|
-
import androidx.compose.foundation.layout.fillMaxSize
|
|
16
|
-
import androidx.compose.foundation.layout.fillMaxWidth
|
|
17
|
-
import androidx.compose.foundation.layout.height
|
|
18
|
-
import androidx.compose.foundation.layout.offset
|
|
19
|
-
import androidx.compose.foundation.layout.padding
|
|
20
|
-
import androidx.compose.foundation.layout.size
|
|
21
|
-
import androidx.compose.foundation.layout.width
|
|
22
|
-
import androidx.compose.foundation.layout.widthIn
|
|
23
|
-
import androidx.compose.foundation.layout.wrapContentSize
|
|
24
|
-
import androidx.compose.foundation.shape.CircleShape
|
|
25
|
-
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
26
|
-
import androidx.compose.runtime.Composable
|
|
27
|
-
import androidx.compose.runtime.CompositionLocalProvider
|
|
28
|
-
import androidx.compose.runtime.compositionLocalOf
|
|
29
|
-
import androidx.compose.runtime.getValue
|
|
30
|
-
import androidx.compose.runtime.mutableStateOf
|
|
31
|
-
import androidx.compose.runtime.remember
|
|
32
|
-
import androidx.compose.runtime.setValue
|
|
33
|
-
import androidx.compose.ui.AbsoluteAlignment
|
|
34
|
-
import androidx.compose.ui.Alignment
|
|
35
|
-
import androidx.compose.ui.Modifier
|
|
36
|
-
import androidx.compose.ui.composed
|
|
37
|
-
import androidx.compose.ui.draw.clip
|
|
38
|
-
import androidx.compose.ui.draw.shadow
|
|
39
|
-
import androidx.compose.ui.graphics.Color
|
|
40
|
-
import androidx.compose.ui.graphics.Shape
|
|
41
|
-
import androidx.compose.ui.graphics.graphicsLayer
|
|
42
|
-
import androidx.compose.ui.layout.onSizeChanged
|
|
43
|
-
import androidx.compose.ui.platform.LocalDensity
|
|
44
|
-
import androidx.compose.ui.semantics.Role
|
|
45
|
-
import androidx.compose.ui.semantics.clearAndSetSemantics
|
|
46
|
-
import androidx.compose.ui.text.style.TextOverflow
|
|
47
|
-
import androidx.compose.ui.unit.Dp
|
|
48
|
-
import androidx.compose.ui.unit.dp
|
|
49
|
-
import vn.momo.kits.application.LocalContext
|
|
50
|
-
import vn.momo.kits.application.MiniAppContext
|
|
51
|
-
import vn.momo.kits.components.Badge
|
|
52
|
-
import vn.momo.kits.components.BadgeDot
|
|
53
|
-
import vn.momo.kits.components.DotSize
|
|
54
|
-
import vn.momo.kits.components.Icon
|
|
55
|
-
import vn.momo.kits.components.Text
|
|
56
|
-
import vn.momo.kits.const.AppTheme
|
|
57
|
-
import vn.momo.kits.const.Spacing
|
|
58
|
-
import vn.momo.kits.const.Typography
|
|
59
|
-
import vn.momo.kits.layout.DuoMetrics
|
|
60
|
-
import vn.momo.kits.layout.ScreenLayout
|
|
61
|
-
import vn.momo.kits.layout.SideBarEdge
|
|
62
|
-
import vn.momo.kits.modifier.noFeedbackClickable
|
|
63
|
-
import vn.momo.kits.modifier.setAutomationId
|
|
64
|
-
import vn.momo.kits.navigation.LocalMaxApi
|
|
65
|
-
|
|
66
|
-
// Figma Fold-Design-System MT1/MT2, mirrored from RN DuoTabBar.tsx.
|
|
67
|
-
private val ITEM_SIZE = DuoMetrics.controlSize
|
|
68
|
-
private val ICON_SIZE = 28.dp
|
|
69
|
-
private val QR_ICON_SIZE = 24.dp
|
|
70
|
-
private val RAIL_PADDING = 6.dp
|
|
71
|
-
private val RAIL_GAP = Spacing.XXS
|
|
72
|
-
// selection bubble overflows the 48 rail cell by 5 above and below
|
|
73
|
-
private val RAIL_BUBBLE_WIDTH = 44.dp
|
|
74
|
-
private val RAIL_BUBBLE_HEIGHT = 58.dp
|
|
75
|
-
private val FLOATING_HEIGHT = DuoMetrics.floatingTabBarHeight
|
|
76
|
-
private val FLOATING_PADDING = Spacing.XS
|
|
77
|
-
// the system bar sizes its pill to the tabs instead of stretching it across the display
|
|
78
|
-
private val FLOATING_ITEM_WIDTH = 80.dp
|
|
79
|
-
// the rail's badge stays inside the capsule: its end sits XXS off the cell's end edge
|
|
80
|
-
private val RAIL_BADGE_MAX_WIDTH = ITEM_SIZE - Spacing.XXS * 2
|
|
81
|
-
private val RAIL_BADGE_END_OFFSET = (ITEM_SIZE - ICON_SIZE) / 2 - Spacing.XXS
|
|
82
|
-
// Figma Home-2026 tab bar "Selection": brand pink at 8%
|
|
83
|
-
private const val SELECTION_TINT_ALPHA = 0x14 / 255f
|
|
84
|
-
|
|
85
|
-
// Space from the window bottom the rail stack and its gap take, so the header side bar stays above it.
|
|
86
|
-
internal val LocalDuoRailReserve = compositionLocalOf { 0.dp }
|
|
87
|
-
|
|
88
|
-
// Rail plus the QR button under it; compressed, the rail is a single button.
|
|
89
|
-
internal fun duoRailHeight(itemCount: Int, hasQr: Boolean, compressed: Boolean = false): Dp {
|
|
90
|
-
val rail = if (compressed) ITEM_SIZE
|
|
91
|
-
else RAIL_PADDING * 2 + ITEM_SIZE * itemCount + RAIL_GAP * (itemCount - 1).coerceAtLeast(0)
|
|
92
|
-
return rail + if (hasQr) Spacing.M + ITEM_SIZE else 0.dp
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Overlaps the home indicator inset like the system tab bar (21pt above the bottom with a 34pt inset).
|
|
96
|
-
private fun floatingTabBarBottom(insetBottom: Dp): Dp =
|
|
97
|
-
maxOf(insetBottom - DuoMetrics.floatingTabBarInsetOverlap, Spacing.S)
|
|
98
|
-
|
|
99
|
-
// Space tab content leaves under the floating bar; 0 when the rail sits in the side strip or off Duo.
|
|
100
|
-
internal fun duoFloatingTabBarInset(layout: ScreenLayout): Dp =
|
|
101
|
-
if (layout.isIPhoneDuo && layout.sideBar == null) FLOATING_HEIGHT + floatingTabBarBottom(layout.insetBottom) else 0.dp
|
|
102
|
-
|
|
103
|
-
// iPhone Duo tab bar: rail in the side bar, or a floating bar when unfolded portrait.
|
|
104
|
-
@Composable
|
|
105
|
-
internal fun BoxScope.DuoTabBar(
|
|
106
|
-
layout: ScreenLayout,
|
|
107
|
-
items: List<BottomTabItem>,
|
|
108
|
-
floatingButton: BottomTabFloatingButton?,
|
|
109
|
-
selectedIndex: Int,
|
|
110
|
-
onTabSelected: (Int) -> Unit,
|
|
111
|
-
compression: DuoBarCompression = DuoBarCompression(),
|
|
112
|
-
onTabLongPress: ((Int) -> Unit)? = null,
|
|
113
|
-
) {
|
|
114
|
-
val maxApi = LocalMaxApi.current
|
|
115
|
-
// a tick per tab the lens enters while dragged
|
|
116
|
-
val onTick = remember(maxApi) { { runCatching { maxApi?.triggerEventVibration("light", callback = null) }; Unit } }
|
|
117
|
-
if (layout.sideBar != null) {
|
|
118
|
-
DuoRailTabBar(layout, items, floatingButton, selectedIndex, onTabSelected, compression, onTabLongPress, onTick)
|
|
119
|
-
} else {
|
|
120
|
-
DuoFloatingTabBar(layout, items, floatingButton, selectedIndex, onTabSelected, onTabLongPress, onTick)
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Vertical bar anchored to the bottom of the side bar, QR button below it (Figma MT1-C/E). When the
|
|
125
|
-
// side bar is short it can shrink to one button showing the current tab (HIG "Tab bar compressed");
|
|
126
|
-
// tapping it expands the rail and compresses the toolbar.
|
|
127
|
-
@Composable
|
|
128
|
-
private fun BoxScope.DuoRailTabBar(
|
|
129
|
-
layout: ScreenLayout,
|
|
130
|
-
items: List<BottomTabItem>,
|
|
131
|
-
floatingButton: BottomTabFloatingButton?,
|
|
132
|
-
selectedIndex: Int,
|
|
133
|
-
onTabSelected: (Int) -> Unit,
|
|
134
|
-
compression: DuoBarCompression,
|
|
135
|
-
onTabLongPress: ((Int) -> Unit)?,
|
|
136
|
-
onTick: () -> Unit,
|
|
137
|
-
) {
|
|
138
|
-
val sideBar = layout.sideBar ?: return
|
|
139
|
-
val isRight = sideBar.edge == SideBarEdge.RIGHT
|
|
140
|
-
|
|
141
|
-
Column(
|
|
142
|
-
modifier = Modifier
|
|
143
|
-
.align(if (isRight) AbsoluteAlignment.BottomRight else AbsoluteAlignment.BottomLeft)
|
|
144
|
-
.width(sideBar.width)
|
|
145
|
-
.padding(bottom = sideBar.bottom)
|
|
146
|
-
.absolutePadding(left = if (isRight) Spacing.M else 0.dp, right = if (isRight) 0.dp else Spacing.M),
|
|
147
|
-
horizontalAlignment = if (isRight) AbsoluteAlignment.Left else AbsoluteAlignment.Right,
|
|
148
|
-
verticalArrangement = Arrangement.spacedBy(Spacing.M),
|
|
149
|
-
) {
|
|
150
|
-
val current = items.getOrNull(selectedIndex)
|
|
151
|
-
if (compression.tabBarCompressed && current != null) {
|
|
152
|
-
val interactionSource = remember { MutableInteractionSource() }
|
|
153
|
-
Box(
|
|
154
|
-
modifier = Modifier
|
|
155
|
-
.pressLift(interactionSource)
|
|
156
|
-
.size(ITEM_SIZE)
|
|
157
|
-
.tabBarMaterial(CircleShape)
|
|
158
|
-
.clickable(interactionSource = interactionSource, indication = null, onClick = compression.expandTabBar)
|
|
159
|
-
.setAutomationId("bottom_tab_bar"),
|
|
160
|
-
contentAlignment = Alignment.Center,
|
|
161
|
-
) {
|
|
162
|
-
DuoTabIcon(current, selected = true, badgeMaxWidth = RAIL_BADGE_MAX_WIDTH, inRail = true)
|
|
163
|
-
}
|
|
164
|
-
} else {
|
|
165
|
-
Rail(items, selectedIndex, onTabLongPress, onTick) {
|
|
166
|
-
onTabSelected(it)
|
|
167
|
-
compression.onTabSelected()
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (floatingButton != null) {
|
|
171
|
-
QrButton(floatingButton, size = ITEM_SIZE)
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Column of icon-only tab items with the sliding selection lens.
|
|
177
|
-
@Composable
|
|
178
|
-
private fun Rail(
|
|
179
|
-
items: List<BottomTabItem>,
|
|
180
|
-
selectedIndex: Int,
|
|
181
|
-
onTabLongPress: ((Int) -> Unit)?,
|
|
182
|
-
onTick: () -> Unit,
|
|
183
|
-
onItemClick: (Int) -> Unit,
|
|
184
|
-
) {
|
|
185
|
-
val selection = rememberDuoLiquidSelection(
|
|
186
|
-
count = items.size,
|
|
187
|
-
pitch = ITEM_SIZE + RAIL_GAP,
|
|
188
|
-
firstCenter = RAIL_PADDING + ITEM_SIZE / 2,
|
|
189
|
-
axis = LiquidAxis.Y,
|
|
190
|
-
index = selectedIndex,
|
|
191
|
-
onSelect = onItemClick,
|
|
192
|
-
onTick = onTick,
|
|
193
|
-
)
|
|
194
|
-
Box(
|
|
195
|
-
Modifier
|
|
196
|
-
.then(selection.barTransform)
|
|
197
|
-
.width(ITEM_SIZE)
|
|
198
|
-
.tabBarMaterial(CircleShape)
|
|
199
|
-
.setAutomationId("bottom_tab_bar")
|
|
200
|
-
.then(selection.dragGesture)
|
|
201
|
-
) {
|
|
202
|
-
Box(
|
|
203
|
-
Modifier
|
|
204
|
-
.offset(
|
|
205
|
-
x = (ITEM_SIZE - RAIL_BUBBLE_WIDTH) / 2,
|
|
206
|
-
y = RAIL_PADDING - (RAIL_BUBBLE_HEIGHT - ITEM_SIZE) / 2,
|
|
207
|
-
)
|
|
208
|
-
.then(selection.bubbleTransform)
|
|
209
|
-
.size(RAIL_BUBBLE_WIDTH, RAIL_BUBBLE_HEIGHT)
|
|
210
|
-
.selectionTint()
|
|
211
|
-
)
|
|
212
|
-
Column(
|
|
213
|
-
modifier = Modifier.padding(vertical = RAIL_PADDING),
|
|
214
|
-
verticalArrangement = Arrangement.spacedBy(RAIL_GAP),
|
|
215
|
-
) {
|
|
216
|
-
items.forEachIndexed { index, item ->
|
|
217
|
-
LiquidTab(
|
|
218
|
-
selection = selection,
|
|
219
|
-
index = index,
|
|
220
|
-
onSelect = { onItemClick(index) },
|
|
221
|
-
onLongPress = onTabLongPress?.let { { it(index) } },
|
|
222
|
-
modifier = Modifier.size(ITEM_SIZE),
|
|
223
|
-
) { active ->
|
|
224
|
-
DuoTabIcon(item, active, badgeMaxWidth = RAIL_BADGE_MAX_WIDTH, inRail = true)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Floating labelled bar for the unfolded portrait display, QR pinned in its own platter beside it.
|
|
232
|
-
@Composable
|
|
233
|
-
private fun BoxScope.DuoFloatingTabBar(
|
|
234
|
-
layout: ScreenLayout,
|
|
235
|
-
items: List<BottomTabItem>,
|
|
236
|
-
floatingButton: BottomTabFloatingButton?,
|
|
237
|
-
selectedIndex: Int,
|
|
238
|
-
onTabSelected: (Int) -> Unit,
|
|
239
|
-
onTabLongPress: ((Int) -> Unit)?,
|
|
240
|
-
onTick: () -> Unit,
|
|
241
|
-
) {
|
|
242
|
-
val density = LocalDensity.current
|
|
243
|
-
var rowWidth by remember { mutableStateOf(0.dp) }
|
|
244
|
-
val cellWidth = rowWidth / items.size.coerceAtLeast(1)
|
|
245
|
-
val selection = rememberDuoLiquidSelection(
|
|
246
|
-
count = items.size,
|
|
247
|
-
pitch = cellWidth,
|
|
248
|
-
firstCenter = cellWidth / 2,
|
|
249
|
-
axis = LiquidAxis.X,
|
|
250
|
-
index = selectedIndex,
|
|
251
|
-
onSelect = onTabSelected,
|
|
252
|
-
onTick = onTick,
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
Row(
|
|
256
|
-
modifier = Modifier
|
|
257
|
-
.align(Alignment.BottomCenter)
|
|
258
|
-
.fillMaxWidth()
|
|
259
|
-
.absolutePadding(
|
|
260
|
-
left = layout.insetLeft + DuoMetrics.floatingTabBarMargin,
|
|
261
|
-
right = layout.insetRight + DuoMetrics.floatingTabBarMargin,
|
|
262
|
-
)
|
|
263
|
-
.padding(bottom = floatingTabBarBottom(layout.insetBottom)),
|
|
264
|
-
horizontalArrangement = Arrangement.spacedBy(Spacing.S, Alignment.CenterHorizontally),
|
|
265
|
-
) {
|
|
266
|
-
Box(
|
|
267
|
-
modifier = Modifier
|
|
268
|
-
.weight(1f, fill = false)
|
|
269
|
-
.width(FLOATING_ITEM_WIDTH * items.size + FLOATING_PADDING * 2)
|
|
270
|
-
.height(FLOATING_HEIGHT)
|
|
271
|
-
.then(selection.barTransform)
|
|
272
|
-
.tabBarMaterial(RoundedCornerShape(FLOATING_HEIGHT / 2))
|
|
273
|
-
.padding(FLOATING_PADDING)
|
|
274
|
-
.setAutomationId("bottom_tab_bar")
|
|
275
|
-
) {
|
|
276
|
-
Box(
|
|
277
|
-
Modifier
|
|
278
|
-
.fillMaxSize()
|
|
279
|
-
.onSizeChanged { rowWidth = with(density) { it.width.toDp() } }
|
|
280
|
-
.then(selection.dragGesture)
|
|
281
|
-
) {
|
|
282
|
-
if (rowWidth > 0.dp) {
|
|
283
|
-
Box(
|
|
284
|
-
Modifier
|
|
285
|
-
.then(selection.bubbleTransform)
|
|
286
|
-
.width(cellWidth)
|
|
287
|
-
.fillMaxHeight()
|
|
288
|
-
.selectionTint()
|
|
289
|
-
)
|
|
290
|
-
}
|
|
291
|
-
Row(Modifier.fillMaxSize()) {
|
|
292
|
-
items.forEachIndexed { index, item ->
|
|
293
|
-
LiquidTab(
|
|
294
|
-
selection = selection,
|
|
295
|
-
index = index,
|
|
296
|
-
onSelect = { onTabSelected(index) },
|
|
297
|
-
onLongPress = onTabLongPress?.let { { it(index) } },
|
|
298
|
-
modifier = Modifier.weight(1f).fillMaxHeight(),
|
|
299
|
-
) { active ->
|
|
300
|
-
FloatingCellContent(item, active, badgeMaxWidth = cellWidth / 2 - Spacing.XXS)
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (floatingButton != null) {
|
|
307
|
-
QrButton(floatingButton, size = FLOATING_HEIGHT, Modifier.shadow(3.dp, CircleShape))
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// A tab drawn twice, inactive with the active layer over it fading in as the lens passes; the tab
|
|
313
|
-
// the lens lands on pops. A tap is the clickable's, a drag over the bar is the bar's.
|
|
314
|
-
@Composable
|
|
315
|
-
private fun LiquidTab(
|
|
316
|
-
selection: DuoLiquidSelection,
|
|
317
|
-
index: Int,
|
|
318
|
-
onSelect: () -> Unit,
|
|
319
|
-
onLongPress: (() -> Unit)?,
|
|
320
|
-
modifier: Modifier = Modifier,
|
|
321
|
-
content: @Composable (active: Boolean) -> Unit,
|
|
322
|
-
) {
|
|
323
|
-
val interactionSource = remember { MutableInteractionSource() }
|
|
324
|
-
val onLongClick = selection.rememberPressTracking(index, interactionSource, onSelect, onLongPress)
|
|
325
|
-
val pop = selection.rememberIconPop(index)
|
|
326
|
-
Box(
|
|
327
|
-
modifier = modifier
|
|
328
|
-
.combinedClickable(
|
|
329
|
-
interactionSource = interactionSource,
|
|
330
|
-
indication = null,
|
|
331
|
-
role = Role.Tab,
|
|
332
|
-
onLongClick = onLongClick,
|
|
333
|
-
onClick = onSelect,
|
|
334
|
-
)
|
|
335
|
-
.graphicsLayer {
|
|
336
|
-
scaleX = pop.value
|
|
337
|
-
scaleY = pop.value
|
|
338
|
-
},
|
|
339
|
-
contentAlignment = Alignment.Center,
|
|
340
|
-
) {
|
|
341
|
-
content(false)
|
|
342
|
-
Box(
|
|
343
|
-
Modifier
|
|
344
|
-
.matchParentSize()
|
|
345
|
-
.graphicsLayer { alpha = selection.activeAlpha(index) }
|
|
346
|
-
.clearAndSetSemantics {},
|
|
347
|
-
contentAlignment = Alignment.Center,
|
|
348
|
-
) {
|
|
349
|
-
content(true)
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
@Composable
|
|
355
|
-
private fun FloatingCellContent(item: BottomTabItem, active: Boolean, badgeMaxWidth: Dp) {
|
|
356
|
-
val colors = AppTheme.current.colors
|
|
357
|
-
Column(
|
|
358
|
-
horizontalAlignment = Alignment.CenterHorizontally,
|
|
359
|
-
verticalArrangement = Arrangement.spacedBy(Spacing.XXS),
|
|
360
|
-
) {
|
|
361
|
-
DuoTabIcon(item, active, badgeMaxWidth)
|
|
362
|
-
// like the system tab bar the label keeps its design size; Text grows it up to 5pt on the wide Duo displays
|
|
363
|
-
val context = LocalContext.current
|
|
364
|
-
val fixedScale = remember(context) {
|
|
365
|
-
(context ?: MiniAppContext()).copy(userScaleRate = 1f, useOSScaleRate = false)
|
|
366
|
-
}
|
|
367
|
-
CompositionLocalProvider(LocalContext provides fixedScale) {
|
|
368
|
-
Text(
|
|
369
|
-
text = item.label,
|
|
370
|
-
style = Typography.labelXsMedium,
|
|
371
|
-
color = if (active) colors.primary else colors.text.hint,
|
|
372
|
-
maxLines = 1,
|
|
373
|
-
overflow = TextOverflow.Ellipsis,
|
|
374
|
-
)
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
private fun Modifier.selectionTint(): Modifier = composed {
|
|
380
|
-
background(AppTheme.current.colors.primary.copy(alpha = SELECTION_TINT_ALPHA), CircleShape)
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Floating bar: the badge starts at the icon's center and grows toward the cell's end edge.
|
|
384
|
-
// Rail: the material clips to the capsule, so the badge ends just inside the rail and grows back
|
|
385
|
-
// over the icon (RN TabBarIcon `end: -3`). Either way it never resizes the icon box.
|
|
386
|
-
@Composable
|
|
387
|
-
private fun DuoTabIcon(item: BottomTabItem, selected: Boolean, badgeMaxWidth: Dp, inRail: Boolean = false) {
|
|
388
|
-
val colors = AppTheme.current.colors
|
|
389
|
-
val badgeLabel = item.badgeLabel?.takeUnless { it.toIntOrNull() == 0 }
|
|
390
|
-
Box {
|
|
391
|
-
Icon(
|
|
392
|
-
source = item.icon,
|
|
393
|
-
size = ICON_SIZE,
|
|
394
|
-
color = if (selected) colors.primary else colors.text.hint,
|
|
395
|
-
)
|
|
396
|
-
when {
|
|
397
|
-
badgeLabel == null && !item.showDot -> Unit
|
|
398
|
-
badgeLabel.isNullOrEmpty() -> BadgeDot(
|
|
399
|
-
size = DotSize.Small,
|
|
400
|
-
modifier = Modifier.align(Alignment.TopEnd),
|
|
401
|
-
)
|
|
402
|
-
else -> Badge(
|
|
403
|
-
badgeLabel,
|
|
404
|
-
modifier = Modifier
|
|
405
|
-
.matchParentSize()
|
|
406
|
-
.wrapContentSize(if (inRail) Alignment.TopEnd else Alignment.TopStart, unbounded = true)
|
|
407
|
-
.offset(x = if (inRail) RAIL_BADGE_END_OFFSET else ICON_SIZE / 2, y = -Spacing.XS)
|
|
408
|
-
.widthIn(max = badgeMaxWidth.coerceAtLeast(0.dp)),
|
|
409
|
-
)
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
@Composable
|
|
415
|
-
private fun QrButton(data: BottomTabFloatingButton, size: Dp, modifier: Modifier = Modifier) {
|
|
416
|
-
Box(
|
|
417
|
-
modifier = modifier
|
|
418
|
-
.size(size)
|
|
419
|
-
.clip(CircleShape)
|
|
420
|
-
.background(AppTheme.current.colors.primary)
|
|
421
|
-
.noFeedbackClickable(onClick = data.onPress)
|
|
422
|
-
.setAutomationId(data.label),
|
|
423
|
-
contentAlignment = Alignment.Center,
|
|
424
|
-
) {
|
|
425
|
-
Icon(source = data.icon, color = Color.White, size = QR_ICON_SIZE)
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// RN BarMaterial: surface with a 1dp border.
|
|
430
|
-
@Composable
|
|
431
|
-
private fun Modifier.tabBarMaterial(shape: Shape): Modifier {
|
|
432
|
-
val colors = AppTheme.current.colors
|
|
433
|
-
return shadow(3.dp, shape)
|
|
434
|
-
.background(colors.background.surface)
|
|
435
|
-
.border(1.dp, colors.border.default, shape)
|
|
436
|
-
}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation.component
|
|
2
|
-
|
|
3
|
-
import androidx.compose.animation.*
|
|
4
|
-
import androidx.compose.animation.core.CubicBezierEasing
|
|
5
|
-
import androidx.compose.animation.core.LinearEasing
|
|
6
|
-
import androidx.compose.animation.core.animateDpAsState
|
|
7
|
-
import androidx.compose.animation.core.tween
|
|
8
|
-
import androidx.compose.foundation.ScrollState
|
|
9
|
-
import androidx.compose.foundation.background
|
|
10
|
-
import androidx.compose.foundation.border
|
|
11
|
-
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
12
|
-
import androidx.compose.foundation.layout.*
|
|
13
|
-
import androidx.compose.material3.AlertDialogDefaults
|
|
14
|
-
import androidx.compose.material3.FloatingActionButton
|
|
15
|
-
import androidx.compose.material3.FloatingActionButtonDefaults
|
|
16
|
-
import androidx.compose.material3.FloatingActionButtonElevation
|
|
17
|
-
import androidx.compose.runtime.*
|
|
18
|
-
import androidx.compose.runtime.saveable.rememberSaveable
|
|
19
|
-
import androidx.compose.ui.Alignment
|
|
20
|
-
import androidx.compose.ui.Modifier
|
|
21
|
-
import androidx.compose.ui.graphics.Color
|
|
22
|
-
import androidx.compose.ui.unit.Dp
|
|
23
|
-
import androidx.compose.ui.unit.dp
|
|
24
|
-
import kotlinx.coroutines.delay
|
|
25
|
-
import kotlinx.coroutines.flow.MutableStateFlow
|
|
26
|
-
import kotlinx.coroutines.flow.collectLatest
|
|
27
|
-
import kotlinx.coroutines.launch
|
|
28
|
-
import vn.momo.kits.application.IsShowBaseLineDebug
|
|
29
|
-
import vn.momo.kits.components.Icon
|
|
30
|
-
import vn.momo.kits.components.Text
|
|
31
|
-
import vn.momo.kits.const.Colors
|
|
32
|
-
import vn.momo.kits.const.Typography
|
|
33
|
-
import vn.momo.kits.modifier.conditional
|
|
34
|
-
import kotlin.time.Duration.Companion.milliseconds
|
|
35
|
-
|
|
36
|
-
enum class FABSize { SMALL, DEFAULT }
|
|
37
|
-
enum class FABPosition { END, CENTER }
|
|
38
|
-
|
|
39
|
-
data class FloatingButtonProps(
|
|
40
|
-
val icon: String,
|
|
41
|
-
val iconColor: Color? = null,
|
|
42
|
-
val label: String? = null,
|
|
43
|
-
val onClick: () -> Unit,
|
|
44
|
-
val size: FABSize = FABSize.DEFAULT,
|
|
45
|
-
val bottom: Dp? = null,
|
|
46
|
-
val scrollState: ScrollState? = null,
|
|
47
|
-
val position: FABPosition? = FABPosition.END,
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
private val FabSmallSize = 36.dp
|
|
51
|
-
private val FabDefaultSize = 48.dp
|
|
52
|
-
private val FabExpandedWidth = 80.dp
|
|
53
|
-
private val FabIconSizeSmall = 12.dp
|
|
54
|
-
private val FabIconSizeDefault = 24.dp
|
|
55
|
-
private val FabPaddingHorizontal = 12.dp
|
|
56
|
-
|
|
57
|
-
@Composable
|
|
58
|
-
internal fun FloatingButton(
|
|
59
|
-
scrollPosition: Int,
|
|
60
|
-
bottom: Dp,
|
|
61
|
-
onClick: () -> Unit,
|
|
62
|
-
containerColor: Color,
|
|
63
|
-
contentColor: Color = containerColor,
|
|
64
|
-
icon: String,
|
|
65
|
-
iconColor: Color? = null,
|
|
66
|
-
text: String? = null,
|
|
67
|
-
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(4.dp),
|
|
68
|
-
size: FABSize = FABSize.DEFAULT,
|
|
69
|
-
position: FABPosition = FABPosition.END,
|
|
70
|
-
keyboardSize: Dp = 0.dp,
|
|
71
|
-
) {
|
|
72
|
-
val scrollStateFlow = remember { MutableStateFlow(scrollPosition) }
|
|
73
|
-
var lastScrollPosition by rememberSaveable { mutableStateOf(0) }
|
|
74
|
-
var isExpanded by rememberSaveable { mutableStateOf(false) }
|
|
75
|
-
|
|
76
|
-
val coroutineScope = rememberCoroutineScope()
|
|
77
|
-
|
|
78
|
-
// Animations
|
|
79
|
-
val baseSize = if (size == FABSize.SMALL) FabSmallSize else FabDefaultSize
|
|
80
|
-
val width by animateDpAsState(
|
|
81
|
-
targetValue = if (isExpanded && text != null) FabExpandedWidth else baseSize,
|
|
82
|
-
animationSpec = tween(100, easing = CubicBezierEasing(0.2f, 0.2f, 0.2f, 0.2f))
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
// Scroll listener
|
|
86
|
-
LaunchedEffect(text) {
|
|
87
|
-
if (text != null) {
|
|
88
|
-
coroutineScope.launch {
|
|
89
|
-
scrollStateFlow.collectLatest { newScroll ->
|
|
90
|
-
isExpanded = newScroll <= lastScrollPosition
|
|
91
|
-
delay(100.milliseconds)
|
|
92
|
-
lastScrollPosition = newScroll
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
LaunchedEffect(scrollPosition) {
|
|
99
|
-
scrollStateFlow.value = scrollPosition
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
Box(
|
|
103
|
-
modifier = Modifier
|
|
104
|
-
.fillMaxSize()
|
|
105
|
-
.padding(end = 12.dp, bottom = bottom)
|
|
106
|
-
.offset(y = -keyboardSize)
|
|
107
|
-
.background(Color.Transparent),
|
|
108
|
-
contentAlignment = if (position == FABPosition.END) Alignment.BottomEnd else Alignment.BottomCenter,
|
|
109
|
-
) {
|
|
110
|
-
FloatingActionButton(
|
|
111
|
-
onClick = onClick,
|
|
112
|
-
shape = AlertDialogDefaults.shape,
|
|
113
|
-
containerColor = containerColor,
|
|
114
|
-
contentColor = contentColor,
|
|
115
|
-
elevation = elevation,
|
|
116
|
-
interactionSource = remember { MutableInteractionSource() },
|
|
117
|
-
modifier = Modifier
|
|
118
|
-
.sizeIn(minWidth = width)
|
|
119
|
-
.height(baseSize)
|
|
120
|
-
.conditional(IsShowBaseLineDebug) {
|
|
121
|
-
border(1.dp, Colors.blue_03)
|
|
122
|
-
}
|
|
123
|
-
) {
|
|
124
|
-
Row(
|
|
125
|
-
modifier = Modifier.padding(
|
|
126
|
-
start = if (isExpanded) FabPaddingHorizontal else 0.dp,
|
|
127
|
-
end = if (isExpanded) FabPaddingHorizontal else 0.dp,
|
|
128
|
-
),
|
|
129
|
-
verticalAlignment = Alignment.CenterVertically,
|
|
130
|
-
horizontalArrangement = if (isExpanded) Arrangement.Start else Arrangement.Center
|
|
131
|
-
) {
|
|
132
|
-
Icon(
|
|
133
|
-
source = icon,
|
|
134
|
-
size = if (size == FABSize.SMALL) FabIconSizeSmall else FabIconSizeDefault,
|
|
135
|
-
color = iconColor ?: Color.White
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
AnimatedVisibility(
|
|
139
|
-
visible = isExpanded,
|
|
140
|
-
enter = fadeInExpandAnimation,
|
|
141
|
-
exit = fadeOutShrinkAnimation,
|
|
142
|
-
) {
|
|
143
|
-
Row {
|
|
144
|
-
Spacer(Modifier.width(12.dp))
|
|
145
|
-
Text(
|
|
146
|
-
text = text ?: "",
|
|
147
|
-
color = Color.White,
|
|
148
|
-
style = Typography.actionDefaultBold
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private val fadeOutShrinkAnimation = fadeOut(
|
|
158
|
-
animationSpec = tween(100, easing = LinearEasing)
|
|
159
|
-
) + shrinkHorizontally(
|
|
160
|
-
animationSpec = tween(100, easing = LinearEasing),
|
|
161
|
-
shrinkTowards = Alignment.Start
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
private val fadeInExpandAnimation = fadeIn(
|
|
165
|
-
animationSpec = tween(100, easing = LinearEasing)
|
|
166
|
-
) + expandHorizontally(
|
|
167
|
-
animationSpec = tween(100, easing = LinearEasing),
|
|
168
|
-
expandFrom = Alignment.Start
|
|
169
|
-
)
|