@momo-kits/native-kits 0.162.1-debug → 0.162.1-gif.1-debug
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compose/build.gradle.kts +5 -1
- package/compose/build.gradle.kts.backup +63 -59
- package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSGraphView.kt +250 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSMonitor.kt +249 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSOverlayView.kt +99 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +33 -17
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +4 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +28 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +46 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +4 -2
- package/gradle/libs.versions.toml +5 -0
- package/gradle.properties +1 -1
- package/ios/FPSMonitor/FPSMonitor.swift +562 -0
- package/package.json +1 -1
- package/publish.sh +2 -2
- package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -46
- package/local.properties +0 -8
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
package vn.momo.kits.fpsmonitor
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.view.Gravity
|
|
5
|
+
import android.view.MotionEvent
|
|
6
|
+
import android.view.ViewGroup
|
|
7
|
+
import android.widget.FrameLayout
|
|
8
|
+
import kotlin.math.abs
|
|
9
|
+
|
|
10
|
+
class FPSOverlayView(context: Context) : FrameLayout(context) {
|
|
11
|
+
private val graphView = FPSGraphView(context)
|
|
12
|
+
private var downX = 0f
|
|
13
|
+
private var downY = 0f
|
|
14
|
+
private var startX = 0f
|
|
15
|
+
private var startY = 0f
|
|
16
|
+
private var dragging = false
|
|
17
|
+
private val touchSlop = 8.dp
|
|
18
|
+
|
|
19
|
+
init {
|
|
20
|
+
addView(
|
|
21
|
+
graphView,
|
|
22
|
+
LayoutParams(
|
|
23
|
+
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
24
|
+
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
25
|
+
),
|
|
26
|
+
)
|
|
27
|
+
isClickable = true
|
|
28
|
+
isFocusable = false
|
|
29
|
+
alpha = 0.92f
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean = true
|
|
33
|
+
|
|
34
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
35
|
+
when (event.actionMasked) {
|
|
36
|
+
MotionEvent.ACTION_DOWN -> {
|
|
37
|
+
downX = event.rawX
|
|
38
|
+
downY = event.rawY
|
|
39
|
+
startX = x
|
|
40
|
+
startY = y
|
|
41
|
+
dragging = false
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
MotionEvent.ACTION_MOVE -> {
|
|
46
|
+
val deltaX = event.rawX - downX
|
|
47
|
+
val deltaY = event.rawY - downY
|
|
48
|
+
if (!dragging && (abs(deltaX) > touchSlop || abs(deltaY) > touchSlop)) {
|
|
49
|
+
dragging = true
|
|
50
|
+
}
|
|
51
|
+
if (dragging) moveTo(startX + deltaX, startY + deltaY)
|
|
52
|
+
return true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
|
56
|
+
if (!dragging) performClick()
|
|
57
|
+
dragging = false
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return super.onTouchEvent(event)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun performClick(): Boolean {
|
|
65
|
+
super.performClick()
|
|
66
|
+
graphView.toggleCollapse()
|
|
67
|
+
requestLayout()
|
|
68
|
+
post { moveTo(x, y) }
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fun updateMetrics(metrics: FPSMetrics) {
|
|
73
|
+
graphView.updateMetrics(metrics)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private fun moveTo(nextX: Float, nextY: Float) {
|
|
77
|
+
val parentView = parent as? ViewGroup
|
|
78
|
+
val maxX = ((parentView?.width ?: resources.displayMetrics.widthPixels) - width).coerceAtLeast(0)
|
|
79
|
+
val maxY = ((parentView?.height ?: resources.displayMetrics.heightPixels) - height).coerceAtLeast(0)
|
|
80
|
+
x = nextX.coerceIn(0f, maxX.toFloat())
|
|
81
|
+
y = nextY.coerceIn(0f, maxY.toFloat())
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
companion object {
|
|
85
|
+
fun defaultLayoutParams(): FrameLayout.LayoutParams {
|
|
86
|
+
return FrameLayout.LayoutParams(
|
|
87
|
+
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
88
|
+
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
89
|
+
Gravity.START or Gravity.TOP,
|
|
90
|
+
).apply {
|
|
91
|
+
leftMargin = 10
|
|
92
|
+
topMargin = 100
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private val Int.dp: Float
|
|
98
|
+
get() = this * resources.displayMetrics.density
|
|
99
|
+
}
|
|
@@ -3,10 +3,9 @@ package vn.momo.kits.components
|
|
|
3
3
|
import androidx.compose.foundation.border
|
|
4
4
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
5
5
|
import androidx.compose.runtime.Composable
|
|
6
|
-
import androidx.compose.runtime.
|
|
7
|
-
import androidx.compose.runtime.mutableStateOf
|
|
6
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
8
7
|
import androidx.compose.runtime.remember
|
|
9
|
-
import androidx.compose.runtime.
|
|
8
|
+
import androidx.compose.runtime.rememberUpdatedState
|
|
10
9
|
import androidx.compose.ui.Alignment
|
|
11
10
|
import androidx.compose.ui.Modifier
|
|
12
11
|
import androidx.compose.ui.graphics.ColorFilter
|
|
@@ -17,7 +16,9 @@ import androidx.compose.ui.semantics.contentDescription
|
|
|
17
16
|
import androidx.compose.ui.semantics.semantics
|
|
18
17
|
import androidx.compose.ui.platform.LocalDensity
|
|
19
18
|
import androidx.compose.ui.unit.dp
|
|
20
|
-
import
|
|
19
|
+
import com.github.panpf.sketch.AsyncImage as SketchAsyncImage
|
|
20
|
+
import com.github.panpf.sketch.PainterState
|
|
21
|
+
import com.github.panpf.sketch.rememberAsyncImageState
|
|
21
22
|
import vn.momo.kits.application.IsShowBaseLineDebug
|
|
22
23
|
import vn.momo.kits.const.AppTheme
|
|
23
24
|
import vn.momo.kits.const.Colors
|
|
@@ -73,6 +74,11 @@ private fun getHostFromUrl(url: String): String? {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
private fun isGifUrl(url: String): Boolean {
|
|
78
|
+
val path = url.substringBefore('#').substringBefore('?')
|
|
79
|
+
return path.endsWith(".gif", ignoreCase = true)
|
|
80
|
+
}
|
|
81
|
+
|
|
76
82
|
// Optimized query parameter appending
|
|
77
83
|
private fun appendSizeQueryParam(url: String, value: String): String {
|
|
78
84
|
val fragmentIndex = url.indexOf('#')
|
|
@@ -95,12 +101,14 @@ fun Image(
|
|
|
95
101
|
modifier: Modifier = Modifier,
|
|
96
102
|
options: Options? = null,
|
|
97
103
|
loading: Boolean = true,
|
|
104
|
+
onLoadingChanged: (Boolean) -> Unit = {},
|
|
98
105
|
) {
|
|
99
106
|
val imageOptions = remember(options) {
|
|
100
107
|
options ?: Options()
|
|
101
108
|
}
|
|
102
109
|
|
|
103
|
-
|
|
110
|
+
val asyncImageState = rememberAsyncImageState()
|
|
111
|
+
val currentOnLoadingChanged = rememberUpdatedState(onLoadingChanged)
|
|
104
112
|
val density = LocalDensity.current
|
|
105
113
|
|
|
106
114
|
BoxWithConstraints(
|
|
@@ -121,26 +129,34 @@ fun Image(
|
|
|
121
129
|
processedUrl
|
|
122
130
|
}
|
|
123
131
|
}
|
|
124
|
-
else -> source
|
|
132
|
+
else -> source.toString()
|
|
125
133
|
}
|
|
126
134
|
}
|
|
127
135
|
|
|
128
|
-
|
|
136
|
+
SketchAsyncImage(
|
|
129
137
|
modifier = Modifier.matchParentSize(),
|
|
130
|
-
|
|
138
|
+
uri = urlToLoad,
|
|
139
|
+
state = asyncImageState,
|
|
131
140
|
contentDescription = null,
|
|
132
141
|
contentScale = imageOptions.contentScale,
|
|
133
142
|
alignment = imageOptions.alignment,
|
|
134
143
|
colorFilter = imageOptions.colorFilter,
|
|
135
144
|
alpha = imageOptions.alpha,
|
|
136
|
-
onLoading = { imageState = ImageState.Loading },
|
|
137
|
-
onSuccess = { imageState = ImageState.Success },
|
|
138
|
-
onError = { imageState = ImageState.Error },
|
|
139
145
|
)
|
|
140
146
|
|
|
141
|
-
when (
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
val isLoading = when (asyncImageState.painterState) {
|
|
148
|
+
is PainterState.Success,
|
|
149
|
+
is PainterState.Error -> false
|
|
150
|
+
else -> true
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
LaunchedEffect(isLoading) {
|
|
154
|
+
currentOnLoadingChanged.value(isLoading)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
when (asyncImageState.painterState) {
|
|
158
|
+
is PainterState.Success -> {}
|
|
159
|
+
is PainterState.Error -> {
|
|
144
160
|
val theme = AppTheme.current
|
|
145
161
|
Icon(
|
|
146
162
|
source = "media_fail",
|
|
@@ -148,7 +164,7 @@ fun Image(
|
|
|
148
164
|
modifier = Modifier.align(Alignment.Center)
|
|
149
165
|
)
|
|
150
166
|
}
|
|
151
|
-
|
|
167
|
+
else -> if (loading) Skeleton()
|
|
152
168
|
}
|
|
153
169
|
}
|
|
154
170
|
}
|
|
@@ -156,7 +172,7 @@ fun Image(
|
|
|
156
172
|
// Extracted URL processing logic for better performance
|
|
157
173
|
private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp, density: androidx.compose.ui.unit.Density): String {
|
|
158
174
|
val host = getHostFromUrl(url)
|
|
159
|
-
return if (host != null && supportedDomains.contains(host)) {
|
|
175
|
+
return if (!isGifUrl(url) && host != null && supportedDomains.contains(host)) {
|
|
160
176
|
val widthPx = with(density) { maxWidth.roundToPx() }
|
|
161
177
|
val pixelRatio = density.density
|
|
162
178
|
val pixelFitForWidth = widthPx * pixelRatio
|
|
@@ -185,4 +201,4 @@ fun Image(
|
|
|
185
201
|
colorFilter = colorFilter,
|
|
186
202
|
alpha = alpha,
|
|
187
203
|
)
|
|
188
|
-
}
|
|
204
|
+
}
|
|
@@ -13,6 +13,7 @@ import vn.momo.kits.navigation.component.HeaderBackProps
|
|
|
13
13
|
import vn.momo.kits.navigation.component.HeaderRight
|
|
14
14
|
import vn.momo.kits.navigation.component.HeaderTitle
|
|
15
15
|
import vn.momo.kits.navigation.component.HeaderType
|
|
16
|
+
import vn.momo.kits.navigation.component.TitlePosition
|
|
16
17
|
|
|
17
18
|
class Navigation(
|
|
18
19
|
val id: Int = -1,
|
|
@@ -28,6 +29,7 @@ class Navigation(
|
|
|
28
29
|
hiddenBack: Boolean? = null,
|
|
29
30
|
headerBackProps: HeaderBackProps? = null,
|
|
30
31
|
headerTitle: HeaderTitle? = null,
|
|
32
|
+
titlePosition: TitlePosition? = null,
|
|
31
33
|
headerRight: HeaderRight? = null,
|
|
32
34
|
headerType: HeaderType? = null,
|
|
33
35
|
scrollData: ScrollData? = null,
|
|
@@ -43,6 +45,7 @@ class Navigation(
|
|
|
43
45
|
hiddenBack = hiddenBack ?: options.hiddenBack,
|
|
44
46
|
headerBackProps = headerBackProps ?: options.headerBackProps,
|
|
45
47
|
headerTitle = headerTitle ?: options.headerTitle,
|
|
48
|
+
titlePosition = titlePosition ?: options.titlePosition,
|
|
46
49
|
headerRight = headerRight ?: options.headerRight,
|
|
47
50
|
headerType = headerType ?: options.headerType,
|
|
48
51
|
scrollData = scrollData ?: options.scrollData,
|
|
@@ -77,6 +80,7 @@ data class NavigationOptions(
|
|
|
77
80
|
val hiddenBack: Boolean = false,
|
|
78
81
|
val headerBackProps: HeaderBackProps = HeaderBackProps(),
|
|
79
82
|
val headerTitle: HeaderTitle = HeaderTitle.Default("Stack"),
|
|
83
|
+
val titlePosition: TitlePosition = TitlePosition.LEFT,
|
|
80
84
|
val headerRight: HeaderRight = HeaderRight.Toolkit(),
|
|
81
85
|
val headerType: HeaderType = HeaderType.Default(),
|
|
82
86
|
val scrollData: ScrollData = ScrollData(),
|
|
@@ -376,7 +376,7 @@ fun SearchAnimated(
|
|
|
376
376
|
val minTopPadding = AppStatusBar.current
|
|
377
377
|
val maxTopPadding = AppStatusBar.current + HEADER_HEIGHT.dp
|
|
378
378
|
val minStartPadding = Spacing.M
|
|
379
|
-
val maxStartPadding = if (options.hiddenBack) Spacing.M else
|
|
379
|
+
val maxStartPadding = if (options.hiddenBack) Spacing.M else 48.dp // button back: size + left +right = 28 + 12 + 8 = 48
|
|
380
380
|
val minEndPadding = Spacing.M
|
|
381
381
|
val maxEndPadding = headerRightWidthDp + if (options.headerRight is HeaderRight.None) Spacing.M else Spacing.M * 2
|
|
382
382
|
|
|
@@ -9,9 +9,12 @@ import androidx.compose.foundation.background
|
|
|
9
9
|
import androidx.compose.foundation.layout.Box
|
|
10
10
|
import androidx.compose.foundation.layout.Column
|
|
11
11
|
import androidx.compose.foundation.layout.Spacer
|
|
12
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
13
|
+
import androidx.compose.foundation.layout.asPaddingValues
|
|
12
14
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
13
15
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
14
16
|
import androidx.compose.foundation.layout.height
|
|
17
|
+
import androidx.compose.foundation.layout.ime
|
|
15
18
|
import androidx.compose.foundation.layout.padding
|
|
16
19
|
import androidx.compose.runtime.Composable
|
|
17
20
|
import androidx.compose.runtime.LaunchedEffect
|
|
@@ -29,7 +32,6 @@ import vn.momo.kits.navigation.LocalNavigator
|
|
|
29
32
|
import vn.momo.kits.navigation.NavigationOptions
|
|
30
33
|
import vn.momo.kits.navigation.StackScreen
|
|
31
34
|
import vn.momo.kits.navigation.component.HeaderType
|
|
32
|
-
import vn.momo.kits.platform.getScreenHeight
|
|
33
35
|
|
|
34
36
|
private var bottomTabOptionItems : MutableList<NavigationOptions?> = mutableListOf()
|
|
35
37
|
fun setBottomTabOption(index: Int, options: NavigationOptions){
|
|
@@ -51,6 +53,8 @@ fun BottomTab(
|
|
|
51
53
|
val navigation = LocalNavigation.current
|
|
52
54
|
val navigator = LocalNavigator.current
|
|
53
55
|
val navController = rememberNavController()
|
|
56
|
+
val keyboardBottomPadding = WindowInsets.ime.asPaddingValues().calculateBottomPadding()
|
|
57
|
+
val shouldShowBottomTab = keyboardBottomPadding == 0.dp
|
|
54
58
|
|
|
55
59
|
bottomTabOptionItems = items.mapIndexed { index, item ->
|
|
56
60
|
item.options ?: NavigationOptions()
|
|
@@ -63,10 +67,16 @@ fun BottomTab(
|
|
|
63
67
|
)
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
Box(modifier = Modifier.
|
|
70
|
+
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
|
|
67
71
|
Box(modifier = Modifier
|
|
68
72
|
.fillMaxSize()
|
|
69
|
-
.padding(
|
|
73
|
+
.padding(
|
|
74
|
+
bottom = if (shouldShowBottomTab) {
|
|
75
|
+
BOTTOM_TAB_BAR_HEIGHT.dp + AppNavigationBar.current
|
|
76
|
+
} else {
|
|
77
|
+
0.dp
|
|
78
|
+
}
|
|
79
|
+
)
|
|
70
80
|
) {
|
|
71
81
|
NavHost(
|
|
72
82
|
navController = navController,
|
|
@@ -125,20 +135,22 @@ fun BottomTab(
|
|
|
125
135
|
}
|
|
126
136
|
}
|
|
127
137
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
if (shouldShowBottomTab) {
|
|
139
|
+
Column {
|
|
140
|
+
BottomTabBar(
|
|
141
|
+
items = items,
|
|
142
|
+
floatingButton = floatingButton,
|
|
143
|
+
navController = navController,
|
|
144
|
+
onTabSelected = {
|
|
145
|
+
val currentRoute = navController.currentBackStackEntry?.destination?.route
|
|
146
|
+
val targetRoute = "option$it"
|
|
147
|
+
if (currentRoute != targetRoute) {
|
|
148
|
+
navController.navigate(targetRoute)
|
|
149
|
+
}
|
|
138
150
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
151
|
+
)
|
|
152
|
+
Spacer(modifier = Modifier.fillMaxWidth().height(AppNavigationBar.current + Spacing.S).background(AppTheme.current.colors.background.surface))
|
|
153
|
+
}
|
|
142
154
|
}
|
|
143
155
|
}
|
|
144
156
|
}
|
|
@@ -6,7 +6,6 @@ import androidx.compose.foundation.border
|
|
|
6
6
|
import androidx.compose.foundation.layout.Arrangement
|
|
7
7
|
import androidx.compose.foundation.layout.Box
|
|
8
8
|
import androidx.compose.foundation.layout.Row
|
|
9
|
-
import androidx.compose.foundation.layout.RowScope
|
|
10
9
|
import androidx.compose.foundation.layout.Spacer
|
|
11
10
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
12
11
|
import androidx.compose.foundation.layout.height
|
|
@@ -23,6 +22,7 @@ import androidx.compose.ui.graphics.Brush
|
|
|
23
22
|
import androidx.compose.ui.graphics.Color
|
|
24
23
|
import androidx.compose.ui.layout.onGloballyPositioned
|
|
25
24
|
import androidx.compose.ui.platform.LocalDensity
|
|
25
|
+
import androidx.compose.ui.text.style.TextAlign
|
|
26
26
|
import androidx.compose.ui.unit.Dp
|
|
27
27
|
import androidx.compose.ui.unit.dp
|
|
28
28
|
import vn.momo.kits.components.Icon
|
|
@@ -44,6 +44,7 @@ import vn.momo.kits.navigation.getInputSearchType
|
|
|
44
44
|
|
|
45
45
|
const val HEADER_HEIGHT = 52
|
|
46
46
|
enum class InputSearchType { None, Header, Animated }
|
|
47
|
+
enum class TitlePosition { LEFT, CENTER }
|
|
47
48
|
|
|
48
49
|
@Composable
|
|
49
50
|
fun Header(onBackHandler: (() -> Unit)? = null) {
|
|
@@ -76,6 +77,13 @@ fun Header(onBackHandler: (() -> Unit)? = null) {
|
|
|
76
77
|
AppTheme.current.colors.background.surface
|
|
77
78
|
|
|
78
79
|
if (options.headerType == HeaderType.None) return
|
|
80
|
+
|
|
81
|
+
val titlePosition = options.titlePosition
|
|
82
|
+
val titleColor = headerColor.tintIconColor
|
|
83
|
+
.copy(alpha = if (inputSearchType == InputSearchType.Animated) 1f - animatedAlpha else 1f)
|
|
84
|
+
// Centered title needs a full-width overlay to stay screen-centered, not boxed between back button and header right.
|
|
85
|
+
val centerTitle = titlePosition == TitlePosition.CENTER && options.headerTitle is HeaderTitle.Default
|
|
86
|
+
|
|
79
87
|
Box(
|
|
80
88
|
Modifier.height(AppStatusBar.current + HEADER_HEIGHT.dp)
|
|
81
89
|
.fillMaxWidth()
|
|
@@ -101,20 +109,40 @@ fun Header(onBackHandler: (() -> Unit)? = null) {
|
|
|
101
109
|
onBackHandler?.invoke() ?: navigator.onBackSafe { }
|
|
102
110
|
}
|
|
103
111
|
)
|
|
104
|
-
Spacer(Modifier.width(Spacing.
|
|
112
|
+
Spacer(Modifier.width(Spacing.S))
|
|
105
113
|
}
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
if (centerTitle) {
|
|
116
|
+
Spacer(Modifier.weight(1f))
|
|
117
|
+
} else {
|
|
118
|
+
HeaderContent(
|
|
119
|
+
headerTitle = options.headerTitle,
|
|
120
|
+
tintIconColor = titleColor,
|
|
121
|
+
titlePosition = titlePosition,
|
|
122
|
+
modifier = Modifier.weight(1f)
|
|
123
|
+
)
|
|
124
|
+
}
|
|
112
125
|
Box(Modifier.onGloballyPositioned {
|
|
113
126
|
if(headerRightWidthPx.intValue != it.size.width) headerRightWidthPx.intValue = it.size.width
|
|
114
127
|
}){
|
|
115
128
|
HeaderRight(options.headerRight, options.tintColor, headerColor)
|
|
116
129
|
}
|
|
117
130
|
}
|
|
131
|
+
if (centerTitle) {
|
|
132
|
+
Box(
|
|
133
|
+
modifier = Modifier.height(HEADER_HEIGHT.dp)
|
|
134
|
+
.fillMaxWidth()
|
|
135
|
+
.padding(horizontal = Spacing.M),
|
|
136
|
+
contentAlignment = Alignment.Center
|
|
137
|
+
) {
|
|
138
|
+
HeaderContent(
|
|
139
|
+
headerTitle = options.headerTitle,
|
|
140
|
+
tintIconColor = titleColor,
|
|
141
|
+
titlePosition = titlePosition,
|
|
142
|
+
modifier = Modifier.fillMaxWidth()
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
118
146
|
VerticalShadow(opacity)
|
|
119
147
|
}
|
|
120
148
|
}
|
|
@@ -140,15 +168,23 @@ private fun BackButton(borderColor: Color, backgroundButton: Color, tintIconColo
|
|
|
140
168
|
}
|
|
141
169
|
|
|
142
170
|
@Composable
|
|
143
|
-
fun
|
|
171
|
+
fun HeaderContent(
|
|
172
|
+
headerTitle: HeaderTitle,
|
|
173
|
+
tintIconColor: Color,
|
|
174
|
+
titlePosition: TitlePosition = TitlePosition.LEFT,
|
|
175
|
+
modifier: Modifier = Modifier,
|
|
176
|
+
){
|
|
144
177
|
Box(
|
|
145
|
-
|
|
178
|
+
modifier = modifier,
|
|
179
|
+
contentAlignment = if (titlePosition == TitlePosition.CENTER) Alignment.Center else Alignment.CenterStart
|
|
146
180
|
) {
|
|
147
181
|
when (headerTitle){
|
|
148
182
|
is HeaderTitle.Default -> {
|
|
149
183
|
HeaderTitle(
|
|
150
184
|
title = headerTitle.title,
|
|
151
|
-
color = tintIconColor
|
|
185
|
+
color = tintIconColor,
|
|
186
|
+
modifier = Modifier.fillMaxWidth(fraction = if (titlePosition == TitlePosition.CENTER) 0.5f else 1f),
|
|
187
|
+
textAlign = if (titlePosition == TitlePosition.CENTER) TextAlign.Center else TextAlign.Start
|
|
152
188
|
)
|
|
153
189
|
}
|
|
154
190
|
is HeaderTitle.Journey -> {}
|
|
@@ -16,11 +16,13 @@ import vn.momo.kits.modifier.setAutomationId
|
|
|
16
16
|
fun HeaderTitle(
|
|
17
17
|
title: String = "",
|
|
18
18
|
color: Color? = null,
|
|
19
|
+
modifier: Modifier = Modifier.fillMaxWidth(),
|
|
20
|
+
textAlign: TextAlign = TextAlign.Start,
|
|
19
21
|
) {
|
|
20
22
|
Text(
|
|
21
|
-
modifier =
|
|
23
|
+
modifier = modifier.zIndex(1f).setAutomationId("title_navigation_header"),
|
|
22
24
|
text = title,
|
|
23
|
-
textAlign =
|
|
25
|
+
textAlign = textAlign,
|
|
24
26
|
style = Typography.actionSBold.copy(
|
|
25
27
|
fontSize = 15.sp,
|
|
26
28
|
lineHeight = 22.sp,
|
|
@@ -21,6 +21,7 @@ maxapi = "0.1.1"
|
|
|
21
21
|
vanniktechMavenPublish = "0.34.0"
|
|
22
22
|
kits = "0.159.1-beta.7"
|
|
23
23
|
nativemaxapi = "0.0.6"
|
|
24
|
+
sketch = "4.4.0"
|
|
24
25
|
|
|
25
26
|
[libraries]
|
|
26
27
|
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor-version" }
|
|
@@ -53,6 +54,10 @@ androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "a
|
|
|
53
54
|
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
|
|
54
55
|
material = { module = "com.google.android.material:material", version.ref = "material" }
|
|
55
56
|
|
|
57
|
+
sketch-compose = { module = "io.github.panpf.sketch4:sketch-compose", version.ref = "sketch" }
|
|
58
|
+
sketch-http = { module = "io.github.panpf.sketch4:sketch-http", version.ref = "sketch" }
|
|
59
|
+
sketch-animated-core = { module = "io.github.panpf.sketch4:sketch-animated-core", version.ref = "sketch" }
|
|
60
|
+
sketch-animated-gif = { module = "io.github.panpf.sketch4:sketch-animated-gif", version.ref = "sketch" }
|
|
56
61
|
[plugins]
|
|
57
62
|
jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
|
58
63
|
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
package/gradle.properties
CHANGED