@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.
Files changed (26) hide show
  1. package/compose/build.gradle.kts +5 -1
  2. package/compose/build.gradle.kts.backup +63 -59
  3. package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSGraphView.kt +250 -0
  4. package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSMonitor.kt +249 -0
  5. package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSOverlayView.kt +99 -0
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +33 -17
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +4 -0
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +1 -1
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +28 -16
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +46 -10
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +4 -2
  12. package/gradle/libs.versions.toml +5 -0
  13. package/gradle.properties +1 -1
  14. package/ios/FPSMonitor/FPSMonitor.swift +562 -0
  15. package/package.json +1 -1
  16. package/publish.sh +2 -2
  17. package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  18. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  19. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
  20. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  21. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  22. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
  23. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
  24. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
  25. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -46
  26. 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.getValue
7
- import androidx.compose.runtime.mutableStateOf
6
+ import androidx.compose.runtime.LaunchedEffect
8
7
  import androidx.compose.runtime.remember
9
- import androidx.compose.runtime.setValue
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 coil3.compose.AsyncImage
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
- var imageState by remember { mutableStateOf(ImageState.Loading) }
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
- AsyncImage(
136
+ SketchAsyncImage(
129
137
  modifier = Modifier.matchParentSize(),
130
- model = urlToLoad,
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 (imageState) {
142
- ImageState.Loading -> if (loading) Skeleton()
143
- ImageState.Error -> {
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
- ImageState.Success -> {}
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 52.dp
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.fillMaxWidth().height(getScreenHeight()), contentAlignment = Alignment.BottomCenter) {
70
+ Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
67
71
  Box(modifier = Modifier
68
72
  .fillMaxSize()
69
- .padding(bottom = BOTTOM_TAB_BAR_HEIGHT.dp + AppNavigationBar.current)
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
- Column {
129
- BottomTabBar(
130
- items = items,
131
- floatingButton = floatingButton,
132
- navController = navController,
133
- onTabSelected = {
134
- val currentRoute = navController.currentBackStackEntry?.destination?.route
135
- val targetRoute = "option$it"
136
- if (currentRoute != targetRoute){
137
- navController.navigate(targetRoute)
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
- Spacer(modifier = Modifier.fillMaxWidth().height(AppNavigationBar.current + Spacing.S).background(AppTheme.current.colors.background.surface))
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.M))
112
+ Spacer(Modifier.width(Spacing.S))
105
113
  }
106
114
 
107
- HeaderContent(
108
- options.headerTitle,
109
- headerColor.tintIconColor
110
- .copy(alpha = if (inputSearchType == InputSearchType.Animated) 1f - animatedAlpha else 1f)
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 RowScope.HeaderContent(headerTitle: HeaderTitle, tintIconColor: Color){
171
+ fun HeaderContent(
172
+ headerTitle: HeaderTitle,
173
+ tintIconColor: Color,
174
+ titlePosition: TitlePosition = TitlePosition.LEFT,
175
+ modifier: Modifier = Modifier,
176
+ ){
144
177
  Box(
145
- Modifier.weight(1f)
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 = Modifier.fillMaxWidth().zIndex(1f).setAutomationId("title_navigation_header"),
23
+ modifier = modifier.zIndex(1f).setAutomationId("title_navigation_header"),
22
24
  text = title,
23
- textAlign = TextAlign.Start,
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
@@ -18,7 +18,7 @@ kotlin.apple.xcodeCompatibility.nowarn=true
18
18
  name="ComposeKits"
19
19
  group=vn.momo.kits
20
20
  artifact.id=kits
21
- version=0.162.1
21
+ version=0.162.1-beta.7
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven