@momo-kits/native-kits 0.164.1-beta.7-debug → 0.164.1-beta.7
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 -190
- package/compose/build.gradle.kts.backup +0 -190
- package/compose/compose.podspec +0 -47
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
- 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 -150
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -106
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -826
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
- 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 -82
- 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 -356
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
- 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 -23
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
- 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 -134
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
- 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 -214
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -216
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -259
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -182
- 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 -328
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -97
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
- 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 -323
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -217
- 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 -199
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -470
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -131
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -203
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -175
- 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 -234
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
- 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 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
- 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 -188
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -263
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -52
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -38
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -39
- 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 -299
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -129
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -103
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -190
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -406
- 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 -612
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -164
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -156
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -225
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
- 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 -320
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -81
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -309
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -34
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -360
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
- 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 -69
- 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 -105
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -118
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
- 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 -220
- 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/local.properties +0 -8
- package/settings.gradle.kts +0 -64
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation
|
|
2
|
-
|
|
3
|
-
import androidx.compose.animation.AnimatedContentTransitionScope
|
|
4
|
-
import androidx.compose.animation.AnimatedVisibilityScope
|
|
5
|
-
import androidx.compose.animation.EnterExitState
|
|
6
|
-
import androidx.compose.animation.EnterTransition
|
|
7
|
-
import androidx.compose.animation.ExitTransition
|
|
8
|
-
import androidx.compose.animation.core.LinearEasing
|
|
9
|
-
import androidx.compose.animation.core.animateFloat
|
|
10
|
-
import androidx.compose.animation.core.tween
|
|
11
|
-
import androidx.compose.animation.slideInHorizontally
|
|
12
|
-
import androidx.compose.animation.slideOutHorizontally
|
|
13
|
-
import androidx.compose.foundation.layout.Box
|
|
14
|
-
import androidx.compose.foundation.layout.fillMaxSize
|
|
15
|
-
import androidx.compose.runtime.Composable
|
|
16
|
-
import androidx.compose.runtime.DisposableEffect
|
|
17
|
-
import androidx.compose.runtime.Stable
|
|
18
|
-
import androidx.compose.runtime.derivedStateOf
|
|
19
|
-
import androidx.compose.runtime.getValue
|
|
20
|
-
import androidx.compose.runtime.mutableStateMapOf
|
|
21
|
-
import androidx.compose.runtime.mutableStateOf
|
|
22
|
-
import androidx.compose.runtime.remember
|
|
23
|
-
import androidx.compose.runtime.setValue
|
|
24
|
-
import androidx.compose.runtime.staticCompositionLocalOf
|
|
25
|
-
import androidx.compose.ui.Modifier
|
|
26
|
-
import androidx.compose.ui.draw.drawBehind
|
|
27
|
-
import androidx.compose.ui.geometry.Offset
|
|
28
|
-
import androidx.compose.ui.geometry.Size
|
|
29
|
-
import androidx.compose.ui.graphics.Brush
|
|
30
|
-
import androidx.compose.ui.graphics.Color
|
|
31
|
-
import androidx.compose.ui.platform.LocalDensity
|
|
32
|
-
import androidx.compose.ui.unit.IntOffset
|
|
33
|
-
import androidx.compose.ui.unit.dp
|
|
34
|
-
import androidx.navigation.NavBackStackEntry
|
|
35
|
-
import androidx.navigation.NavDestination.Companion.hasRoute
|
|
36
|
-
import vn.momo.kits.const.Colors
|
|
37
|
-
import kotlin.math.roundToInt
|
|
38
|
-
|
|
39
|
-
internal const val STACK_TRANSITION_DURATION = 300
|
|
40
|
-
|
|
41
|
-
// Ported 1:1 from the RN kit's `forStackTransitionWithOverlay` so both kits look identical.
|
|
42
|
-
private const val PARALLAX_RATIO = 0.3f
|
|
43
|
-
private const val SCRIM_MAX_ALPHA = 0.6f
|
|
44
|
-
private const val EDGE_SHADOW_MAX_ALPHA = 0.3f
|
|
45
|
-
private val EDGE_SHADOW_WIDTH = 8.dp
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Kill switch for the swipe-back gesture. Set to `false` to make kit back handling always win,
|
|
49
|
-
* which disables the predictive-back drag on both platforms — on iOS that means the host-driven
|
|
50
|
-
* seek stops following the finger, though the host's own gesture still fires a plain back. Screen
|
|
51
|
-
* transitions stay on the parallax curve either way.
|
|
52
|
-
*/
|
|
53
|
-
object SwipeBackConfig {
|
|
54
|
-
// Snapshot-backed so a host toggle takes effect on the next frame instead of waiting for an
|
|
55
|
-
// unrelated recomposition of StackScreen.
|
|
56
|
-
var enabled: Boolean by mutableStateOf(true)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// LinearEasing is mandatory, not a style choice: SeekableTransitionState.seekTo() maps the drag
|
|
60
|
-
// fraction straight onto the animation timeline, so any curve would decouple the card from the
|
|
61
|
-
// finger mid-gesture.
|
|
62
|
-
private val stackSpec = tween<IntOffset>(STACK_TRANSITION_DURATION, easing = LinearEasing)
|
|
63
|
-
|
|
64
|
-
internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackEnter(): EnterTransition =
|
|
65
|
-
slideInHorizontally(stackSpec) { it }
|
|
66
|
-
|
|
67
|
-
internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackExit(): ExitTransition =
|
|
68
|
-
if (targetState.destination.hasRoute<DynamicDialogRoute>()) ExitTransition.None
|
|
69
|
-
else slideOutHorizontally(stackSpec) { -(it * PARALLAX_RATIO).roundToInt() }
|
|
70
|
-
|
|
71
|
-
internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackPopEnter(): EnterTransition =
|
|
72
|
-
if (initialState.destination.hasRoute<DynamicDialogRoute>()) EnterTransition.None
|
|
73
|
-
else slideInHorizontally(stackSpec) { -(it * PARALLAX_RATIO).roundToInt() }
|
|
74
|
-
|
|
75
|
-
internal fun AnimatedContentTransitionScope<NavBackStackEntry>.stackPopExit(): ExitTransition =
|
|
76
|
-
slideOutHorizontally(stackSpec) { it }
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Tracks which screen ids are currently composed so a screen can tell whether it is the top card
|
|
80
|
-
* or the one underneath.
|
|
81
|
-
*
|
|
82
|
-
* Screen ids come from a single monotonic process-wide counter and NavHost keeps both entries
|
|
83
|
-
* composed for the whole transition segment, so "highest composed stack id" is stable in both
|
|
84
|
-
* directions. `currentBackStackEntry` is not usable here: it flips at frame 0 of a pop, which
|
|
85
|
-
* would make the scrim vanish instantly instead of fading.
|
|
86
|
-
*/
|
|
87
|
-
@Stable
|
|
88
|
-
internal class StackTransitionCoordinator {
|
|
89
|
-
private val composedRoutes = mutableStateMapOf<Int, Boolean>()
|
|
90
|
-
|
|
91
|
-
val topStackId: Int by derivedStateOf {
|
|
92
|
-
composedRoutes.entries.filter { it.value }.maxOfOrNull { it.key } ?: -1
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
fun attach(id: Int, isStackRoute: Boolean) {
|
|
96
|
-
composedRoutes[id] = isStackRoute
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
fun detach(id: Int) {
|
|
100
|
-
composedRoutes.remove(id)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
internal val LocalStackTransition = staticCompositionLocalOf { StackTransitionCoordinator() }
|
|
105
|
-
|
|
106
|
-
/** Draws the covered-screen scrim and the top card's left-edge shadow around a stack destination. */
|
|
107
|
-
@Composable
|
|
108
|
-
internal fun AnimatedVisibilityScope.StackTransitionDecor(
|
|
109
|
-
id: Int,
|
|
110
|
-
isStackRoute: Boolean,
|
|
111
|
-
content: @Composable () -> Unit,
|
|
112
|
-
) {
|
|
113
|
-
val coordinator = LocalStackTransition.current
|
|
114
|
-
// attach() writes state that derivedStateOf { topStackId } reads in the same pass, so it has to
|
|
115
|
-
// stay out of the composable body.
|
|
116
|
-
DisposableEffect(coordinator, id, isStackRoute) {
|
|
117
|
-
coordinator.attach(id, isStackRoute)
|
|
118
|
-
onDispose { coordinator.detach(id) }
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
val isTopCard = isStackRoute && id == coordinator.topStackId
|
|
122
|
-
val isCovered = isStackRoute && !isTopCard
|
|
123
|
-
|
|
124
|
-
val scrimAlpha = transition.animateFloat(
|
|
125
|
-
transitionSpec = { tween(STACK_TRANSITION_DURATION, easing = LinearEasing) },
|
|
126
|
-
label = "stackScrimAlpha",
|
|
127
|
-
) { state -> if (isCovered && state != EnterExitState.Visible) SCRIM_MAX_ALPHA else 0f }
|
|
128
|
-
|
|
129
|
-
val shadowAlpha = transition.animateFloat(
|
|
130
|
-
transitionSpec = { tween(STACK_TRANSITION_DURATION, easing = LinearEasing) },
|
|
131
|
-
label = "stackEdgeShadowAlpha",
|
|
132
|
-
) { state -> if (isTopCard && state == EnterExitState.Visible) EDGE_SHADOW_MAX_ALPHA else 0f }
|
|
133
|
-
|
|
134
|
-
val shadowWidthPx = with(LocalDensity.current) { EDGE_SHADOW_WIDTH.toPx() }
|
|
135
|
-
val shadowBrush = remember(shadowWidthPx) {
|
|
136
|
-
Brush.horizontalGradient(
|
|
137
|
-
colors = listOf(Color.Transparent, Colors.black_20),
|
|
138
|
-
startX = -shadowWidthPx,
|
|
139
|
-
endX = 0f,
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
Box(Modifier.fillMaxSize()) {
|
|
144
|
-
content()
|
|
145
|
-
|
|
146
|
-
if (isStackRoute) {
|
|
147
|
-
Box(
|
|
148
|
-
Modifier
|
|
149
|
-
.matchParentSize()
|
|
150
|
-
// Both alphas are read inside drawBehind so a drag only re-draws; reading them
|
|
151
|
-
// in the composable body would recompose the whole screen every gesture frame.
|
|
152
|
-
.drawBehind {
|
|
153
|
-
drawRect(
|
|
154
|
-
brush = shadowBrush,
|
|
155
|
-
topLeft = Offset(-shadowWidthPx, 0f),
|
|
156
|
-
size = Size(shadowWidthPx, size.height),
|
|
157
|
-
alpha = shadowAlpha.value,
|
|
158
|
-
)
|
|
159
|
-
drawRect(Colors.pink_09, alpha = scrimAlpha.value)
|
|
160
|
-
}
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation.bottomtab
|
|
2
|
-
|
|
3
|
-
import androidx.compose.animation.core.tween
|
|
4
|
-
import androidx.compose.animation.fadeIn
|
|
5
|
-
import androidx.compose.animation.fadeOut
|
|
6
|
-
import androidx.compose.animation.scaleIn
|
|
7
|
-
import androidx.compose.animation.scaleOut
|
|
8
|
-
import androidx.compose.foundation.background
|
|
9
|
-
import androidx.compose.foundation.layout.*
|
|
10
|
-
import androidx.compose.runtime.Composable
|
|
11
|
-
import androidx.compose.runtime.LaunchedEffect
|
|
12
|
-
import androidx.compose.ui.Alignment
|
|
13
|
-
import androidx.compose.ui.Modifier
|
|
14
|
-
import androidx.compose.ui.unit.dp
|
|
15
|
-
import androidx.navigation.compose.NavHost
|
|
16
|
-
import androidx.navigation.compose.composable
|
|
17
|
-
import androidx.navigation.compose.rememberNavController
|
|
18
|
-
import vn.momo.kits.const.AppNavigationBar
|
|
19
|
-
import vn.momo.kits.const.AppTheme
|
|
20
|
-
import vn.momo.kits.const.Spacing
|
|
21
|
-
import vn.momo.kits.navigation.KeyboardOptions
|
|
22
|
-
import vn.momo.kits.navigation.LocalNavigation
|
|
23
|
-
import vn.momo.kits.navigation.LocalNavigator
|
|
24
|
-
import vn.momo.kits.navigation.NavigationOptions
|
|
25
|
-
import vn.momo.kits.navigation.StackScreen
|
|
26
|
-
import vn.momo.kits.navigation.component.HeaderType
|
|
27
|
-
|
|
28
|
-
private var bottomTabOptionItems : MutableList<NavigationOptions?> = mutableListOf()
|
|
29
|
-
internal fun setBottomTabOption(index: Int, options: NavigationOptions){
|
|
30
|
-
if (index in bottomTabOptionItems.indices) {
|
|
31
|
-
bottomTabOptionItems[index] = options
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
internal fun getBottomTabOption(index: Int): NavigationOptions? {
|
|
35
|
-
return if (index in bottomTabOptionItems.indices) {
|
|
36
|
-
bottomTabOptionItems[index]
|
|
37
|
-
} else null
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@Composable
|
|
41
|
-
fun BottomTab(
|
|
42
|
-
items: List<BottomTabItem>,
|
|
43
|
-
floatingButton: BottomTabFloatingButton? = null
|
|
44
|
-
) {
|
|
45
|
-
val navigation = LocalNavigation.current
|
|
46
|
-
val navigator = LocalNavigator.current
|
|
47
|
-
val navController = rememberNavController()
|
|
48
|
-
|
|
49
|
-
bottomTabOptionItems = items.mapIndexed { index, item ->
|
|
50
|
-
item.options ?: NavigationOptions()
|
|
51
|
-
}.toMutableList()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
LaunchedEffect(Unit){
|
|
55
|
-
navigation.markAsBottomTabRoot()
|
|
56
|
-
navigation.setOptions(
|
|
57
|
-
headerType = HeaderType.None,
|
|
58
|
-
keyboardOptions = KeyboardOptions(useAvoidKeyboard = false)
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
|
|
63
|
-
Box(modifier = Modifier
|
|
64
|
-
.fillMaxSize()
|
|
65
|
-
) {
|
|
66
|
-
NavHost(
|
|
67
|
-
navController = navController,
|
|
68
|
-
startDestination = "option0"
|
|
69
|
-
) {
|
|
70
|
-
items.forEachIndexed { index, item ->
|
|
71
|
-
composable(
|
|
72
|
-
route = "option$index",
|
|
73
|
-
enterTransition = {
|
|
74
|
-
fadeIn(animationSpec = tween(200)) +
|
|
75
|
-
scaleIn(
|
|
76
|
-
initialScale = 0.97f,
|
|
77
|
-
animationSpec = tween(200)
|
|
78
|
-
)
|
|
79
|
-
},
|
|
80
|
-
exitTransition = {
|
|
81
|
-
fadeOut(animationSpec = tween(200)) +
|
|
82
|
-
scaleOut(
|
|
83
|
-
targetScale = 0.97f,
|
|
84
|
-
animationSpec = tween(200)
|
|
85
|
-
)
|
|
86
|
-
},
|
|
87
|
-
popEnterTransition = {
|
|
88
|
-
fadeIn(animationSpec = tween(200)) +
|
|
89
|
-
scaleIn(
|
|
90
|
-
initialScale = 0.97f,
|
|
91
|
-
animationSpec = tween(200)
|
|
92
|
-
)
|
|
93
|
-
},
|
|
94
|
-
popExitTransition = {
|
|
95
|
-
fadeOut(animationSpec = tween(200)) +
|
|
96
|
-
scaleOut(
|
|
97
|
-
targetScale = 0.97f,
|
|
98
|
-
animationSpec = tween(200)
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
) {
|
|
102
|
-
val option = getBottomTabOption(index)
|
|
103
|
-
|
|
104
|
-
StackScreen(
|
|
105
|
-
content = item.screen,
|
|
106
|
-
navigationOptions = option,
|
|
107
|
-
bottomTabIndex = index,
|
|
108
|
-
onBackHandler = {
|
|
109
|
-
if (index != 0) {
|
|
110
|
-
navController.popBackStack(
|
|
111
|
-
navController.graph.startDestinationRoute!!,
|
|
112
|
-
inclusive = false
|
|
113
|
-
)
|
|
114
|
-
} else {
|
|
115
|
-
navigator.pop()
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
Column {
|
|
124
|
-
BottomTabBar(
|
|
125
|
-
items = items,
|
|
126
|
-
floatingButton = floatingButton,
|
|
127
|
-
navController = navController,
|
|
128
|
-
onTabSelected = {
|
|
129
|
-
val currentRoute = navController.currentBackStackEntry?.destination?.route
|
|
130
|
-
val targetRoute = "option$it"
|
|
131
|
-
if (currentRoute != targetRoute) {
|
|
132
|
-
navController.navigate(targetRoute)
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
)
|
|
136
|
-
Spacer(modifier = Modifier.fillMaxWidth().height(AppNavigationBar.current + Spacing.S).background(AppTheme.current.colors.background.surface))
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
data class BottomTabItem(
|
|
142
|
-
val name: String,
|
|
143
|
-
val label: String,
|
|
144
|
-
val icon: String,
|
|
145
|
-
val showDot: Boolean = false,
|
|
146
|
-
val badgeLabel: String? = null,
|
|
147
|
-
val screen: @Composable () -> Unit,
|
|
148
|
-
val options: NavigationOptions? = null,
|
|
149
|
-
val initialParams: Any? = null
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
data class BottomTabFloatingButton(
|
|
153
|
-
val icon: String,
|
|
154
|
-
val label: String,
|
|
155
|
-
val onPress: () -> Unit,
|
|
156
|
-
)
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation.bottomtab
|
|
2
|
-
|
|
3
|
-
import androidx.compose.animation.core.FastOutSlowInEasing
|
|
4
|
-
import androidx.compose.animation.core.animateDpAsState
|
|
5
|
-
import androidx.compose.animation.core.tween
|
|
6
|
-
import androidx.compose.foundation.background
|
|
7
|
-
import androidx.compose.foundation.border
|
|
8
|
-
import androidx.compose.foundation.layout.*
|
|
9
|
-
import androidx.compose.foundation.shape.CircleShape
|
|
10
|
-
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
11
|
-
import androidx.compose.runtime.Composable
|
|
12
|
-
import androidx.compose.runtime.getValue
|
|
13
|
-
import androidx.compose.ui.Alignment
|
|
14
|
-
import androidx.compose.ui.Modifier
|
|
15
|
-
import androidx.compose.ui.draw.clip
|
|
16
|
-
import androidx.compose.ui.graphics.Brush
|
|
17
|
-
import androidx.compose.ui.graphics.Color
|
|
18
|
-
import androidx.compose.ui.text.style.TextAlign
|
|
19
|
-
import androidx.compose.ui.text.style.TextOverflow
|
|
20
|
-
import androidx.compose.ui.unit.dp
|
|
21
|
-
import androidx.navigation.NavController
|
|
22
|
-
import androidx.navigation.compose.currentBackStackEntryAsState
|
|
23
|
-
import vn.momo.kits.application.IsShowBaseLineDebug
|
|
24
|
-
import vn.momo.kits.components.*
|
|
25
|
-
import vn.momo.kits.const.*
|
|
26
|
-
import vn.momo.kits.modifier.InternalApi
|
|
27
|
-
import vn.momo.kits.modifier.conditional
|
|
28
|
-
import vn.momo.kits.modifier.noFeedbackClickable
|
|
29
|
-
import vn.momo.kits.platform.getScreenDimensions
|
|
30
|
-
|
|
31
|
-
internal val floatingButtonWidth = 75.dp
|
|
32
|
-
@InternalApi
|
|
33
|
-
const val BOTTOM_TAB_BAR_HEIGHT = 64
|
|
34
|
-
|
|
35
|
-
@Composable
|
|
36
|
-
internal fun BottomTabBar(
|
|
37
|
-
items: List<BottomTabItem>,
|
|
38
|
-
floatingButton: BottomTabFloatingButton? = null,
|
|
39
|
-
navController: NavController,
|
|
40
|
-
onTabSelected: (Int) -> Unit,
|
|
41
|
-
) {
|
|
42
|
-
val currentRoute = navController.currentBackStackEntryAsState().value?.destination?.route
|
|
43
|
-
val selectedIndex = items.indexOfFirst { "option${items.indexOf(it)}" == currentRoute }
|
|
44
|
-
|
|
45
|
-
val screenWidth = getScreenDimensions().width.dp
|
|
46
|
-
val mid = items.size / 2
|
|
47
|
-
|
|
48
|
-
val tabWidth = if (floatingButton != null) {
|
|
49
|
-
(screenWidth - floatingButtonWidth) / items.size
|
|
50
|
-
} else {
|
|
51
|
-
screenWidth / items.size
|
|
52
|
-
}
|
|
53
|
-
val adjustSize = if(floatingButton != null && selectedIndex >= mid) floatingButtonWidth else 0.dp
|
|
54
|
-
val targetOffset = tabWidth * selectedIndex + tabWidth / 2 - screenWidth / 2 + adjustSize
|
|
55
|
-
|
|
56
|
-
val indicatorOffsetX by animateDpAsState(
|
|
57
|
-
targetValue = targetOffset,
|
|
58
|
-
animationSpec = tween(durationMillis = 250, easing = FastOutSlowInEasing),
|
|
59
|
-
label = "IndicatorX"
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
Box(
|
|
63
|
-
contentAlignment = Alignment.BottomCenter
|
|
64
|
-
) {
|
|
65
|
-
Row(
|
|
66
|
-
modifier = Modifier
|
|
67
|
-
.fillMaxWidth()
|
|
68
|
-
.height(BOTTOM_TAB_BAR_HEIGHT.dp)
|
|
69
|
-
.background(AppTheme.current.colors.background.surface)
|
|
70
|
-
.conditional(IsShowBaseLineDebug) {
|
|
71
|
-
border(1.dp, Colors.blue_03)
|
|
72
|
-
},
|
|
73
|
-
horizontalArrangement = Arrangement.SpaceAround,
|
|
74
|
-
) {
|
|
75
|
-
if (floatingButton == null) {
|
|
76
|
-
RenderTabBarItem(items, 0, items.size, selectedIndex, onTabSelected)
|
|
77
|
-
} else {
|
|
78
|
-
RenderTabBarItem(items, 0, mid, selectedIndex, onTabSelected)
|
|
79
|
-
Spacer(modifier = Modifier.width(floatingButtonWidth).padding(horizontal = Spacing.XXS))
|
|
80
|
-
RenderTabBarItem(items, mid, items.size, selectedIndex, onTabSelected)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
Box(modifier = Modifier
|
|
85
|
-
.offset(x = indicatorOffsetX, y = (-BOTTOM_TAB_BAR_HEIGHT + 2).dp)
|
|
86
|
-
.height(2.dp)
|
|
87
|
-
.width(44.dp)
|
|
88
|
-
.background(
|
|
89
|
-
color = AppTheme.current.colors.primary ,
|
|
90
|
-
shape = RoundedCornerShape(bottomStart = 2.dp, bottomEnd = 2.dp)
|
|
91
|
-
)
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
Box(modifier = Modifier
|
|
95
|
-
.fillMaxWidth()
|
|
96
|
-
.height(6.dp)
|
|
97
|
-
.offset(x = 0.dp, y = (-BOTTOM_TAB_BAR_HEIGHT).dp)
|
|
98
|
-
.background(
|
|
99
|
-
brush = Brush.verticalGradient(
|
|
100
|
-
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.05f))
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
)
|
|
104
|
-
floatingButton?.let { FloatingButton(it) }
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@Composable
|
|
109
|
-
internal fun RowScope.RenderTabBarItem(
|
|
110
|
-
items: List<BottomTabItem>,
|
|
111
|
-
fromIndex: Int,
|
|
112
|
-
toIndex: Int,
|
|
113
|
-
selectedIndex: Int,
|
|
114
|
-
onTabSelected: (Int) -> Unit
|
|
115
|
-
){
|
|
116
|
-
for (index in fromIndex until toIndex) {
|
|
117
|
-
Box(modifier = Modifier.weight(1f)) {
|
|
118
|
-
TabBarItem(
|
|
119
|
-
item = items[index],
|
|
120
|
-
selected = index == selectedIndex,
|
|
121
|
-
onClick = { onTabSelected(index) }
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
@Composable
|
|
128
|
-
internal fun TabBarItem(item: BottomTabItem, selected: Boolean, onClick: () -> Unit) {
|
|
129
|
-
fun isNumber(label: String): Boolean {
|
|
130
|
-
val numberRegex = "^\\d+$".toRegex()
|
|
131
|
-
return numberRegex.matches(label)
|
|
132
|
-
}
|
|
133
|
-
fun formatLabel(label: String): String? {
|
|
134
|
-
if (isNumber(label) && label.toInt() == 0) {
|
|
135
|
-
return null
|
|
136
|
-
}
|
|
137
|
-
return label
|
|
138
|
-
}
|
|
139
|
-
val badgeLabel = item.badgeLabel?.let { formatLabel(it) }
|
|
140
|
-
|
|
141
|
-
Box(modifier = Modifier
|
|
142
|
-
.fillMaxSize()
|
|
143
|
-
.padding(horizontal = Spacing.XXS)
|
|
144
|
-
.conditional(IsShowBaseLineDebug) {
|
|
145
|
-
border(1.dp, Colors.blue_03)
|
|
146
|
-
}
|
|
147
|
-
.noFeedbackClickable {
|
|
148
|
-
onClick()
|
|
149
|
-
},
|
|
150
|
-
contentAlignment = Alignment.BottomStart
|
|
151
|
-
){
|
|
152
|
-
Column(
|
|
153
|
-
modifier = Modifier
|
|
154
|
-
.fillMaxSize()
|
|
155
|
-
.padding(horizontal = Spacing.S, vertical = Spacing.S)
|
|
156
|
-
.noFeedbackClickable {
|
|
157
|
-
onClick()
|
|
158
|
-
},
|
|
159
|
-
horizontalAlignment = Alignment.CenterHorizontally,
|
|
160
|
-
verticalArrangement = Arrangement.Center
|
|
161
|
-
) {
|
|
162
|
-
Icon(
|
|
163
|
-
source = item.icon,
|
|
164
|
-
size = 28.dp,
|
|
165
|
-
modifier = Modifier.padding(Spacing.XS),
|
|
166
|
-
color = if (selected) AppTheme.current.colors.primary else AppTheme.current.colors.text.hint)
|
|
167
|
-
Text(
|
|
168
|
-
text = item.label,
|
|
169
|
-
color = if (selected) AppTheme.current.colors.primary else AppTheme.current.colors.text.hint,
|
|
170
|
-
style = if (selected) Typography.labelXsMedium else Typography.descriptionXsRegular,
|
|
171
|
-
maxLines = 1,
|
|
172
|
-
overflow = TextOverflow.Ellipsis
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
if (badgeLabel != null) {
|
|
176
|
-
if (badgeLabel.isEmpty())
|
|
177
|
-
BadgeDot(
|
|
178
|
-
size = DotSize.Small,
|
|
179
|
-
modifier = Modifier.offset(x = 50.dp, y = (-48).dp)
|
|
180
|
-
)
|
|
181
|
-
else
|
|
182
|
-
Badge(badgeLabel, modifier = Modifier.offset(x = 44.dp, y = (-42).dp))
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
@Composable
|
|
188
|
-
internal fun FloatingButton(data: BottomTabFloatingButton) {
|
|
189
|
-
Column(
|
|
190
|
-
modifier = Modifier
|
|
191
|
-
.width(floatingButtonWidth)
|
|
192
|
-
.padding(horizontal = Spacing.XXS, vertical = Spacing.S)
|
|
193
|
-
.conditional(IsShowBaseLineDebug) {
|
|
194
|
-
border(1.dp, Colors.blue_03)
|
|
195
|
-
}
|
|
196
|
-
.noFeedbackClickable {
|
|
197
|
-
data.onPress()
|
|
198
|
-
},
|
|
199
|
-
verticalArrangement = Arrangement.Bottom,
|
|
200
|
-
horizontalAlignment = Alignment.CenterHorizontally
|
|
201
|
-
|
|
202
|
-
){
|
|
203
|
-
CurvedContainer()
|
|
204
|
-
Box(
|
|
205
|
-
modifier = Modifier
|
|
206
|
-
.size(48.dp)
|
|
207
|
-
.clip(CircleShape)
|
|
208
|
-
.background(AppTheme.current.colors.primary),
|
|
209
|
-
contentAlignment = Alignment.Center
|
|
210
|
-
) {
|
|
211
|
-
Icon(source = data.icon, color = Color.White, size = 28.dp)
|
|
212
|
-
}
|
|
213
|
-
Spacer(modifier = Modifier.height(4.dp))
|
|
214
|
-
Text(
|
|
215
|
-
text = data.label,
|
|
216
|
-
style = Typography.labelXsMedium,
|
|
217
|
-
color = Colors.black_01,
|
|
218
|
-
textAlign = TextAlign.Center,
|
|
219
|
-
modifier = Modifier
|
|
220
|
-
.height(14.dp)
|
|
221
|
-
.fillMaxWidth()
|
|
222
|
-
.background(AppTheme.current.colors.primary, shape = RoundedCornerShape(size = Radius.XL))
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation.bottomtab
|
|
2
|
-
|
|
3
|
-
import androidx.compose.foundation.Canvas
|
|
4
|
-
import androidx.compose.foundation.layout.Box
|
|
5
|
-
import androidx.compose.foundation.layout.height
|
|
6
|
-
import androidx.compose.foundation.layout.offset
|
|
7
|
-
import androidx.compose.foundation.layout.width
|
|
8
|
-
import androidx.compose.runtime.Composable
|
|
9
|
-
import androidx.compose.ui.Alignment
|
|
10
|
-
import androidx.compose.ui.Modifier
|
|
11
|
-
import androidx.compose.ui.graphics.Path
|
|
12
|
-
import androidx.compose.ui.platform.LocalDensity
|
|
13
|
-
import androidx.compose.ui.unit.Dp
|
|
14
|
-
import androidx.compose.ui.unit.IntOffset
|
|
15
|
-
import androidx.compose.ui.unit.dp
|
|
16
|
-
import androidx.compose.ui.zIndex
|
|
17
|
-
import vn.momo.kits.const.AppTheme
|
|
18
|
-
|
|
19
|
-
@Composable
|
|
20
|
-
internal fun CurvedContainer(
|
|
21
|
-
circleSize: Dp = 48.dp,
|
|
22
|
-
tabBarItemIconSize: Dp = 28.dp,
|
|
23
|
-
circleOverSize: Dp = 2.dp,
|
|
24
|
-
width: Dp = 71.dp,
|
|
25
|
-
height: Dp = 16.dp
|
|
26
|
-
) {
|
|
27
|
-
val theme = AppTheme.current
|
|
28
|
-
val density = LocalDensity.current
|
|
29
|
-
val widthPx = with(density) { width.toPx()}
|
|
30
|
-
|
|
31
|
-
val circleSizePx = with(density) { circleSize.toPx() }
|
|
32
|
-
val tabBarItemIconSizePx = with(density) { tabBarItemIconSize.toPx() }
|
|
33
|
-
val circleOverSizePx = with(density) { circleOverSize.toPx() }
|
|
34
|
-
|
|
35
|
-
val circlePositionTop = circleSizePx - tabBarItemIconSizePx - 10f
|
|
36
|
-
val circleOverTop = circlePositionTop + circleOverSizePx
|
|
37
|
-
val circleR = circleSizePx / 2
|
|
38
|
-
val circleOverR = circleR + circleOverSizePx
|
|
39
|
-
|
|
40
|
-
val centerX = widthPx / 2
|
|
41
|
-
|
|
42
|
-
val curvedPath = getPath(
|
|
43
|
-
circleOverTop = circleOverTop,
|
|
44
|
-
centerX = centerX,
|
|
45
|
-
circleOverR = circleOverR,
|
|
46
|
-
widthPx = widthPx
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
Box(
|
|
50
|
-
contentAlignment = Alignment.BottomCenter
|
|
51
|
-
){
|
|
52
|
-
Canvas(
|
|
53
|
-
modifier = Modifier
|
|
54
|
-
.width(width)
|
|
55
|
-
.height(height)
|
|
56
|
-
.offset{ IntOffset(x = 0, y = 24) }
|
|
57
|
-
.zIndex(-1f)
|
|
58
|
-
) {
|
|
59
|
-
drawPath(path = curvedPath, color = theme.colors.background.surface)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private fun getPath(circleOverTop: Float, centerX: Float, circleOverR: Float, widthPx: Float): Path{
|
|
65
|
-
return Path().apply {
|
|
66
|
-
moveTo(0f, circleOverTop)
|
|
67
|
-
lineTo(centerX - circleOverR - 40f, circleOverTop)
|
|
68
|
-
|
|
69
|
-
cubicTo(
|
|
70
|
-
centerX - circleOverR, circleOverTop,
|
|
71
|
-
centerX - circleOverR, 0f,
|
|
72
|
-
centerX, 0f
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
cubicTo(
|
|
76
|
-
centerX + circleOverR, 0f,
|
|
77
|
-
centerX + circleOverR, circleOverTop,
|
|
78
|
-
centerX + circleOverR + 40f, circleOverTop
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
lineTo(widthPx, circleOverTop)
|
|
82
|
-
lineTo(widthPx, 60f)
|
|
83
|
-
lineTo(0f, 60f)
|
|
84
|
-
close()
|
|
85
|
-
}
|
|
86
|
-
}
|