@momo-kits/native-kits 0.163.1-beta.7-debug → 0.163.1-beta.8-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/.claude/settings.local.json +62 -0
- package/compose/build.gradle.kts +2 -1
- package/compose/build.gradle.kts.backup +1 -0
- package/compose/compose.podspec +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +3 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +11 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +40 -55
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +69 -26
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +3 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +22 -21
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +4 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +19 -40
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +11 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +3 -4
- package/gradle/libs.versions.toml +2 -0
- package/gradle.properties +1 -1
- package/ios/Application/ApplicationEnvironment.swift +0 -1
- package/ios/Typography/Text.swift +7 -12
- package/ios/Typography/Typography.swift +9 -14
- package/local.properties +2 -2
- package/package.json +1 -1
- 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/ios/Application/FontScaleStore.swift +0 -59
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(curl -s -o /dev/null -w \"%{http_code}\" \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.pom\")",
|
|
5
|
+
"Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/maven-metadata.xml\")",
|
|
6
|
+
"Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko/maven-metadata.xml\")",
|
|
7
|
+
"Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko/0.144.6/skiko-0.144.6.module\")",
|
|
8
|
+
"Bash(curl -s -o /dev/null -w '%{http_code}' https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.__TRACKED_VAR__)",
|
|
9
|
+
"Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/\")",
|
|
10
|
+
"Bash(curl -s \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/\")",
|
|
11
|
+
"Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.148.1/skiko-android-0.148.1.pom\")",
|
|
12
|
+
"Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" \"https://repo.maven.apache.org/maven2/org/jetbrains/skiko/skiko-android/0.144.5/skiko-android-0.144.5.pom\")",
|
|
13
|
+
"Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" \"https://dl.google.com/dl/android/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.pom\")",
|
|
14
|
+
"Bash(curl -s \"https://search.maven.org/solrsearch/select?q=a:skiko-android&rows=5&wt=json\")",
|
|
15
|
+
"Bash(curl -sL -o /dev/null -w \"%{http_code} %{url_effective}\\\\n\" \"https://repo1.maven.org/maven2/org/jetbrains/skiko/skiko-android/0.144.6/skiko-android-0.144.6.pom\")",
|
|
16
|
+
"Bash(curl *)",
|
|
17
|
+
"Bash(./gradlew :sample:androidApp:dependencies --configuration debugRuntimeClasspath)",
|
|
18
|
+
"Bash(./gradlew :sample:shared:compileDebugKotlinAndroid)",
|
|
19
|
+
"Bash(./gradlew :sample:androidApp:compileDebugKotlin)",
|
|
20
|
+
"Bash(ls -d *.xcodeproj)",
|
|
21
|
+
"Bash(grep -c ChipDemo.swift __TRACKED_VAR__/project.pbxproj)",
|
|
22
|
+
"Bash(grep -c PBXFileSystemSynchronizedRootGroup __TRACKED_VAR__/project.pbxproj)",
|
|
23
|
+
"Bash(grep -c InformationDemo.swift __TRACKED_VAR__/project.pbxproj)",
|
|
24
|
+
"Bash(plutil -lint project.pbxproj)",
|
|
25
|
+
"Bash(xcode-select -p)",
|
|
26
|
+
"Bash(/usr/bin/xcrun xcodebuild *)",
|
|
27
|
+
"Bash(echo \"exit: $?\")",
|
|
28
|
+
"Bash(/Applications/Xcode26.app/Contents/Developer/usr/bin/xcodebuild -version)",
|
|
29
|
+
"Bash(./gradlew :compose:tasks --all)",
|
|
30
|
+
"Bash(grep -n \"vanniktech\\\\|mavenPublishing\\\\|^publishing\\\\|version = gitlabVersion\\\\|namespace =\\\\|compileSdk =\\\\|minSdk =\\\\|GitLabPackages\\\\|name = \\\\\"\\\\${gitlabRepo}Packages\\\\\"\")",
|
|
31
|
+
"Bash(git checkout *)",
|
|
32
|
+
"Bash(./gradlew :compose:publishAllPublicationsToGitLabPackagesRepository --dry-run)",
|
|
33
|
+
"Bash(git fetch *)",
|
|
34
|
+
"Bash(git pull *)",
|
|
35
|
+
"Bash(git push *)",
|
|
36
|
+
"Bash(git branch *)",
|
|
37
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -list)",
|
|
38
|
+
"Bash(xcrun simctl *)",
|
|
39
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14 Pro' -configuration Debug build CODE_SIGNING_ALLOWED=NO)",
|
|
40
|
+
"Bash(pod install *)",
|
|
41
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'id=1E6F9A79-5E64-4590-BEA2-828D75D99393' -configuration Debug build CODE_SIGNING_ALLOWED=NO)",
|
|
42
|
+
"Bash(xcrun swiftc *)",
|
|
43
|
+
"Bash(echo \"=== exit: $? \\(1=none found\\) ===\")",
|
|
44
|
+
"Bash(cat Radius.swift)",
|
|
45
|
+
"Bash(cat Spacing.swift)",
|
|
46
|
+
"Bash(echo \"exit=$?\")",
|
|
47
|
+
"Bash(ruby *)",
|
|
48
|
+
"Bash(xcodebuild -list -workspace iosApp.xcworkspace)",
|
|
49
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14 Pro' build)",
|
|
50
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme MoMoUIKits -sdk iphonesimulator -destination 'platform=iOS Simulator,id=E6A899C0-098E-473A-95B8-A2BBD2D42A92' build)",
|
|
51
|
+
"Bash(xcodebuild -workspace iosApp.xcworkspace -scheme iosApp -sdk iphonesimulator -destination 'platform=iOS Simulator,id=E6A899C0-098E-473A-95B8-A2BBD2D42A92' build)",
|
|
52
|
+
"Bash(xcodebuild build *)",
|
|
53
|
+
"Bash(git stash *)",
|
|
54
|
+
"Bash(plutil -lint sample/iosApp/iosApp.xcodeproj/project.pbxproj)",
|
|
55
|
+
"Bash(git add *)",
|
|
56
|
+
"Bash(git commit -m 'feat: DS-646 [ci build] *)",
|
|
57
|
+
"Bash(git commit -q -m 'fix: DS-656 [ci build] *)",
|
|
58
|
+
"Bash(xargs git log --oneline -1)",
|
|
59
|
+
"Bash(git rev-list *)"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
package/compose/build.gradle.kts
CHANGED
|
@@ -40,7 +40,7 @@ kotlin {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
cocoapods {
|
|
43
|
-
version = "0.163.1-beta.
|
|
43
|
+
version = "0.163.1-beta.8-debug"
|
|
44
44
|
summary = "IOS Shared module"
|
|
45
45
|
homepage = "https://momo.vn"
|
|
46
46
|
ios.deploymentTarget = "15.0"
|
|
@@ -77,6 +77,7 @@ kotlin {
|
|
|
77
77
|
implementation(libs.kotlinx.datetime)
|
|
78
78
|
api(libs.native.max.api)
|
|
79
79
|
implementation(libs.compottie)
|
|
80
|
+
implementation(libs.gif.image)
|
|
80
81
|
}
|
|
81
82
|
androidMain.dependencies {
|
|
82
83
|
implementation(libs.ktor.client.okhttp)
|
package/compose/compose.podspec
CHANGED
|
@@ -28,7 +28,7 @@ data class MiniAppContext(
|
|
|
28
28
|
val providerId: String = "",
|
|
29
29
|
val permissions: List<Map<String, Any>>? = emptyList(),
|
|
30
30
|
val features: FeatureFlags? = null,
|
|
31
|
-
val
|
|
31
|
+
val scaleSizeMaxRate: Float? = null,
|
|
32
32
|
) {
|
|
33
33
|
companion object {
|
|
34
34
|
|
|
@@ -60,7 +60,7 @@ data class MiniAppContext(
|
|
|
60
60
|
providerId = parent.providerId.ifBlank { child.providerId },
|
|
61
61
|
permissions = if (!parent.permissions.isNullOrEmpty()) parent.permissions else child.permissions,
|
|
62
62
|
features = mergeFeatureFlags(parent.features, child.features),
|
|
63
|
-
|
|
63
|
+
scaleSizeMaxRate = parent.scaleSizeMaxRate ?: child.scaleSizeMaxRate,
|
|
64
64
|
)
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -98,11 +98,4 @@ val LocalComponentInformation = staticCompositionLocalOf<ComponentInformation?>
|
|
|
98
98
|
null
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
data class FontScaleConfig(
|
|
103
|
-
val useOSFontScale: Boolean = true,
|
|
104
|
-
val userScaleRate: Float? = null,
|
|
105
|
-
val osFontScale: Float? = null,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
val LocalFontScaleConfig = staticCompositionLocalOf { FontScaleConfig() }
|
|
101
|
+
val ScaleSizeMaxRate = staticCompositionLocalOf<Float?> { null }
|
|
@@ -95,11 +95,13 @@ private fun getStyle(size: Size): TextStyle {
|
|
|
95
95
|
return styleCache[size] ?: Typography.actionDefaultBold
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
@InternalApi
|
|
99
|
+
fun getIconSize(size: Size): Dp = iconSizeCache[size] ?: 24.dp
|
|
99
100
|
private fun getIconSpace(size: Size): Dp = iconSpaceCache[size] ?: Spacing.S
|
|
100
101
|
|
|
102
|
+
@InternalApi
|
|
101
103
|
@Composable
|
|
102
|
-
|
|
104
|
+
fun getTextColor(loading: Boolean, type: ButtonType): Color {
|
|
103
105
|
val theme = AppTheme.current
|
|
104
106
|
|
|
105
107
|
return remember(type, theme, loading) {
|
|
@@ -140,7 +142,6 @@ fun RenderIcon(
|
|
|
140
142
|
useTintColor: Boolean = true,
|
|
141
143
|
icon: String = "",
|
|
142
144
|
forceLoading: Boolean = false,
|
|
143
|
-
bgColor: Color? = null,
|
|
144
145
|
textColor: Color? = null,
|
|
145
146
|
) {
|
|
146
147
|
val iconSize = remember(size) { getIconSize(size) }
|
|
@@ -156,9 +157,10 @@ fun RenderIcon(
|
|
|
156
157
|
Box(modifier) {
|
|
157
158
|
LottieAnimation(
|
|
158
159
|
modifier = Modifier.size(iconSize),
|
|
159
|
-
bgColor =
|
|
160
|
+
bgColor = null,
|
|
160
161
|
tintColor = color,
|
|
161
|
-
path = "files/lottie_circle_loader"
|
|
162
|
+
path = "files/lottie_circle_loader",
|
|
163
|
+
useCompose = true
|
|
162
164
|
)
|
|
163
165
|
}
|
|
164
166
|
} else if (icon.isNotEmpty()) {
|
|
@@ -183,8 +185,9 @@ private fun shouldLoadingOnLeft(iconLeft: String, iconRight: String): Boolean {
|
|
|
183
185
|
}
|
|
184
186
|
}
|
|
185
187
|
|
|
188
|
+
@InternalApi
|
|
186
189
|
@Composable
|
|
187
|
-
|
|
190
|
+
fun getTypeStyle(
|
|
188
191
|
type: ButtonType,
|
|
189
192
|
color: Color? = AppTheme.current.colors.primary,
|
|
190
193
|
size: Size,
|
|
@@ -219,8 +222,9 @@ internal fun getTypeStyle(
|
|
|
219
222
|
}
|
|
220
223
|
}
|
|
221
224
|
|
|
225
|
+
@InternalApi
|
|
222
226
|
@Composable
|
|
223
|
-
|
|
227
|
+
fun getButtonBackgroundColor(
|
|
224
228
|
loading: Boolean,
|
|
225
229
|
type: ButtonType
|
|
226
230
|
): Color {
|
|
@@ -336,7 +340,6 @@ fun Button(
|
|
|
336
340
|
useTintColor = useTintColor,
|
|
337
341
|
icon = iconLeft,
|
|
338
342
|
forceLoading = loading && loadingOnLeft,
|
|
339
|
-
bgColor = bgColor,
|
|
340
343
|
textColor = textColor
|
|
341
344
|
)
|
|
342
345
|
RenderTitle(size, title, textColor = textColor)
|
|
@@ -346,7 +349,6 @@ fun Button(
|
|
|
346
349
|
useTintColor = useTintColor,
|
|
347
350
|
icon = iconRight,
|
|
348
351
|
forceLoading = loading && !loadingOnLeft,
|
|
349
|
-
bgColor = bgColor,
|
|
350
352
|
textColor = textColor
|
|
351
353
|
)
|
|
352
354
|
}
|
|
@@ -5,6 +5,7 @@ import androidx.compose.foundation.border
|
|
|
5
5
|
import androidx.compose.foundation.clickable
|
|
6
6
|
import androidx.compose.foundation.layout.Box
|
|
7
7
|
import androidx.compose.foundation.layout.size
|
|
8
|
+
import androidx.compose.foundation.shape.CircleShape
|
|
8
9
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
9
10
|
import androidx.compose.runtime.Composable
|
|
10
11
|
import androidx.compose.runtime.remember
|
|
@@ -12,6 +13,7 @@ import androidx.compose.ui.Alignment
|
|
|
12
13
|
import androidx.compose.ui.Modifier
|
|
13
14
|
import androidx.compose.ui.draw.clip
|
|
14
15
|
import androidx.compose.ui.graphics.Color
|
|
16
|
+
import androidx.compose.ui.graphics.Shape
|
|
15
17
|
import androidx.compose.ui.unit.Dp
|
|
16
18
|
import androidx.compose.ui.unit.dp
|
|
17
19
|
import vn.momo.kits.application.IsShowBaseLineDebug
|
|
@@ -21,69 +23,58 @@ import vn.momo.kits.const.Radius
|
|
|
21
23
|
import vn.momo.kits.modifier.conditional
|
|
22
24
|
|
|
23
25
|
data class IconSpecs(
|
|
24
|
-
val
|
|
25
|
-
val
|
|
26
|
-
val radius: Dp,
|
|
27
|
-
val size: Dp
|
|
26
|
+
val box: Dp,
|
|
27
|
+
val icon: Dp,
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
enum class IconSize(val value: IconSpecs) {
|
|
31
|
-
LARGE(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
radius = Radius.XL,
|
|
35
|
-
width = 48.dp,
|
|
36
|
-
size = 48.dp
|
|
37
|
-
)
|
|
38
|
-
),
|
|
39
|
-
SMALL(
|
|
40
|
-
IconSpecs(
|
|
41
|
-
height = 40.dp,
|
|
42
|
-
radius = Radius.XL,
|
|
43
|
-
width = 40.dp,
|
|
44
|
-
size = 40.dp
|
|
45
|
-
)
|
|
46
|
-
)
|
|
31
|
+
LARGE(IconSpecs(box = 48.dp, icon = 24.dp)),
|
|
32
|
+
MEDIUM(IconSpecs(box = 36.dp, icon = 16.dp)),
|
|
33
|
+
SMALL(IconSpecs(box = 28.dp, icon = 16.dp)),
|
|
47
34
|
}
|
|
48
35
|
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
enum class IconShape {
|
|
37
|
+
CIRCLE,
|
|
38
|
+
SQUARE,
|
|
39
|
+
}
|
|
51
40
|
|
|
52
|
-
//
|
|
53
|
-
private val
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
41
|
+
// Square keeps an 8dp rounded corner; circle is fully rounded regardless of size.
|
|
42
|
+
private val squareShape = RoundedCornerShape(Radius.S)
|
|
43
|
+
|
|
44
|
+
private fun IconShape.toShape(): Shape = when (this) {
|
|
45
|
+
IconShape.CIRCLE -> CircleShape
|
|
46
|
+
IconShape.SQUARE -> squareShape
|
|
47
|
+
}
|
|
57
48
|
|
|
58
49
|
@Composable
|
|
59
|
-
internal fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
|
|
50
|
+
internal fun getIconStyle(type: ButtonType, shape: Shape, color: Color? = null): Modifier {
|
|
60
51
|
val theme = AppTheme.current
|
|
61
52
|
|
|
62
|
-
return remember(type, color, theme) {
|
|
53
|
+
return remember(type, shape, color, theme) {
|
|
63
54
|
when (type) {
|
|
64
55
|
ButtonType.DISABLED -> Modifier
|
|
65
|
-
.background(theme.colors.background.disable,
|
|
66
|
-
.border(0.dp, Color.Unspecified,
|
|
56
|
+
.background(theme.colors.background.disable, shape)
|
|
57
|
+
.border(0.dp, Color.Unspecified, shape)
|
|
67
58
|
|
|
68
59
|
ButtonType.PRIMARY -> Modifier
|
|
69
|
-
.background(theme.colors.primary,
|
|
70
|
-
.border(0.dp, Color.Unspecified,
|
|
60
|
+
.background(theme.colors.primary, shape)
|
|
61
|
+
.border(0.dp, Color.Unspecified, shape)
|
|
71
62
|
|
|
72
63
|
ButtonType.SECONDARY -> Modifier
|
|
73
|
-
.background(theme.colors.background.surface,
|
|
74
|
-
.border(1.dp, theme.colors.border.default,
|
|
64
|
+
.background(theme.colors.background.surface, shape)
|
|
65
|
+
.border(1.dp, theme.colors.border.default, shape)
|
|
75
66
|
|
|
76
67
|
ButtonType.OUTLINE -> Modifier
|
|
77
|
-
.background(theme.colors.background.surface,
|
|
78
|
-
.border(1.dp, color ?: theme.colors.primary,
|
|
68
|
+
.background(theme.colors.background.surface, shape)
|
|
69
|
+
.border(1.dp, color ?: theme.colors.primary, shape)
|
|
79
70
|
|
|
80
71
|
ButtonType.TONAL -> Modifier
|
|
81
|
-
.background(theme.colors.background.tonal,
|
|
82
|
-
.border(0.dp, Color.Unspecified,
|
|
72
|
+
.background(theme.colors.background.tonal, shape)
|
|
73
|
+
.border(0.dp, Color.Unspecified, shape)
|
|
83
74
|
|
|
84
75
|
ButtonType.DANGER -> Modifier
|
|
85
|
-
.background(theme.colors.error.primary,
|
|
86
|
-
.border(0.dp, Color.Unspecified,
|
|
76
|
+
.background(theme.colors.error.primary, shape)
|
|
77
|
+
.border(0.dp, Color.Unspecified, shape)
|
|
87
78
|
|
|
88
79
|
ButtonType.TEXT -> Modifier
|
|
89
80
|
}
|
|
@@ -103,38 +94,32 @@ fun IconButton(
|
|
|
103
94
|
onClick: () -> Unit,
|
|
104
95
|
type: ButtonType = ButtonType.PRIMARY,
|
|
105
96
|
size: IconSize = IconSize.SMALL,
|
|
97
|
+
shape: IconShape = IconShape.CIRCLE,
|
|
106
98
|
icon: String = "",
|
|
107
99
|
) {
|
|
108
|
-
|
|
109
|
-
val iconSize = remember(size) {
|
|
110
|
-
iconSizeMap[size] ?: 16.dp
|
|
111
|
-
}
|
|
100
|
+
val specs = size.value
|
|
112
101
|
|
|
113
|
-
// Memoize enabled state
|
|
114
102
|
val isEnabled = remember(type) {
|
|
115
103
|
type != ButtonType.DISABLED
|
|
116
104
|
}
|
|
117
105
|
|
|
118
|
-
|
|
119
|
-
val radius = remember(size) {
|
|
120
|
-
size.value.radius
|
|
121
|
-
}
|
|
106
|
+
val boxShape = remember(shape) { shape.toShape() }
|
|
122
107
|
|
|
123
108
|
Box(
|
|
124
109
|
modifier = Modifier
|
|
125
|
-
.size(
|
|
126
|
-
.then(getIconStyle(type))
|
|
110
|
+
.size(specs.box)
|
|
111
|
+
.then(getIconStyle(type, boxShape))
|
|
127
112
|
.conditional(IsShowBaseLineDebug) {
|
|
128
113
|
border(1.dp, Colors.blue_03)
|
|
129
114
|
}
|
|
130
|
-
.clip(
|
|
115
|
+
.clip(boxShape)
|
|
131
116
|
.clickable(enabled = isEnabled, onClick = onClick),
|
|
132
117
|
contentAlignment = Alignment.Center
|
|
133
118
|
) {
|
|
134
119
|
Icon(
|
|
135
120
|
source = icon,
|
|
136
121
|
color = getIconColor(type),
|
|
137
|
-
size =
|
|
122
|
+
size = specs.icon,
|
|
138
123
|
)
|
|
139
124
|
}
|
|
140
|
-
}
|
|
125
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
package vn.momo.kits.components
|
|
2
2
|
|
|
3
3
|
import androidx.compose.foundation.border
|
|
4
|
+
import androidx.compose.foundation.layout.Box
|
|
4
5
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
6
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
5
7
|
import androidx.compose.runtime.Composable
|
|
6
8
|
import androidx.compose.runtime.getValue
|
|
7
9
|
import androidx.compose.runtime.mutableStateOf
|
|
@@ -17,10 +19,12 @@ import androidx.compose.ui.semantics.contentDescription
|
|
|
17
19
|
import androidx.compose.ui.semantics.semantics
|
|
18
20
|
import androidx.compose.ui.platform.LocalDensity
|
|
19
21
|
import androidx.compose.ui.unit.dp
|
|
20
|
-
import coil3.compose.AsyncImage
|
|
22
|
+
import coil3.compose.AsyncImage as CoilAsyncImage
|
|
21
23
|
import vn.momo.kits.application.IsShowBaseLineDebug
|
|
22
24
|
import vn.momo.kits.const.AppTheme
|
|
23
25
|
import vn.momo.kits.const.Colors
|
|
26
|
+
import vn.momo.kits.gifimage.GifImage
|
|
27
|
+
import vn.momo.kits.gifimage.GifImageState
|
|
24
28
|
import vn.momo.kits.modifier.conditional
|
|
25
29
|
|
|
26
30
|
data class Options(
|
|
@@ -73,6 +77,19 @@ private fun getHostFromUrl(url: String): String? {
|
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
private fun isGifUrl(url: String): Boolean {
|
|
81
|
+
val path = url.substringBefore('#').substringBefore('?')
|
|
82
|
+
return path.endsWith(".gif", ignoreCase = true)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private fun GifImageState.toImageState(): ImageState {
|
|
86
|
+
return when (this) {
|
|
87
|
+
GifImageState.Success -> ImageState.Success
|
|
88
|
+
GifImageState.Error -> ImageState.Error
|
|
89
|
+
GifImageState.Loading -> ImageState.Loading
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
76
93
|
// Optimized query parameter appending
|
|
77
94
|
private fun appendSizeQueryParam(url: String, value: String): String {
|
|
78
95
|
val fragmentIndex = url.indexOf('#')
|
|
@@ -95,12 +112,12 @@ fun Image(
|
|
|
95
112
|
modifier: Modifier = Modifier,
|
|
96
113
|
options: Options? = null,
|
|
97
114
|
loading: Boolean = true,
|
|
115
|
+
onStateChanged: (ImageState) -> Unit = {},
|
|
98
116
|
) {
|
|
99
117
|
val imageOptions = remember(options) {
|
|
100
118
|
options ?: Options()
|
|
101
119
|
}
|
|
102
120
|
|
|
103
|
-
var imageState by remember { mutableStateOf(ImageState.Loading) }
|
|
104
121
|
val density = LocalDensity.current
|
|
105
122
|
|
|
106
123
|
BoxWithConstraints(
|
|
@@ -121,34 +138,46 @@ fun Image(
|
|
|
121
138
|
processedUrl
|
|
122
139
|
}
|
|
123
140
|
}
|
|
124
|
-
else -> source
|
|
141
|
+
else -> source.toString()
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
144
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
145
|
+
var imageState by remember(urlToLoad) { mutableStateOf(ImageState.Loading) }
|
|
146
|
+
fun updateImageState(state: ImageState) {
|
|
147
|
+
imageState = state
|
|
148
|
+
onStateChanged(state)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (isGifUrl(urlToLoad)) {
|
|
152
|
+
GifImage(
|
|
153
|
+
modifier = Modifier.matchParentSize(),
|
|
154
|
+
url = urlToLoad,
|
|
155
|
+
contentDescription = null,
|
|
156
|
+
contentScale = imageOptions.contentScale,
|
|
157
|
+
alignment = imageOptions.alignment,
|
|
158
|
+
colorFilter = imageOptions.colorFilter,
|
|
159
|
+
alpha = imageOptions.alpha,
|
|
160
|
+
onStateChanged = { updateImageState(it.toImageState()) },
|
|
161
|
+
)
|
|
162
|
+
} else {
|
|
163
|
+
CoilAsyncImage(
|
|
164
|
+
modifier = Modifier.matchParentSize(),
|
|
165
|
+
model = urlToLoad,
|
|
166
|
+
contentDescription = null,
|
|
167
|
+
contentScale = imageOptions.contentScale,
|
|
168
|
+
alignment = imageOptions.alignment,
|
|
169
|
+
colorFilter = imageOptions.colorFilter,
|
|
170
|
+
alpha = imageOptions.alpha,
|
|
171
|
+
onLoading = { updateImageState(ImageState.Loading) },
|
|
172
|
+
onSuccess = { updateImageState(ImageState.Success) },
|
|
173
|
+
onError = { updateImageState(ImageState.Error) },
|
|
174
|
+
)
|
|
175
|
+
}
|
|
140
176
|
|
|
141
177
|
when (imageState) {
|
|
142
|
-
ImageState.Loading -> if (loading) Skeleton()
|
|
143
|
-
ImageState.Error -> {
|
|
144
|
-
val theme = AppTheme.current
|
|
145
|
-
Icon(
|
|
146
|
-
source = "media_fail",
|
|
147
|
-
color = theme.colors.text.disable,
|
|
148
|
-
modifier = Modifier.align(Alignment.Center)
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
178
|
ImageState.Success -> {}
|
|
179
|
+
ImageState.Error -> ImageError()
|
|
180
|
+
ImageState.Loading -> if (loading) Skeleton()
|
|
152
181
|
}
|
|
153
182
|
}
|
|
154
183
|
}
|
|
@@ -156,7 +185,7 @@ fun Image(
|
|
|
156
185
|
// Extracted URL processing logic for better performance
|
|
157
186
|
private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp, density: androidx.compose.ui.unit.Density): String {
|
|
158
187
|
val host = getHostFromUrl(url)
|
|
159
|
-
return if (host != null && supportedDomains.contains(host)) {
|
|
188
|
+
return if (!isGifUrl(url) && host != null && supportedDomains.contains(host)) {
|
|
160
189
|
val widthPx = with(density) { maxWidth.roundToPx() }
|
|
161
190
|
val pixelRatio = density.density
|
|
162
191
|
val pixelFitForWidth = widthPx * pixelRatio
|
|
@@ -167,6 +196,20 @@ private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp,
|
|
|
167
196
|
}
|
|
168
197
|
}
|
|
169
198
|
|
|
199
|
+
@Composable
|
|
200
|
+
private fun ImageError() {
|
|
201
|
+
val theme = AppTheme.current
|
|
202
|
+
Box(
|
|
203
|
+
modifier = Modifier.fillMaxSize(),
|
|
204
|
+
contentAlignment = Alignment.Center
|
|
205
|
+
) {
|
|
206
|
+
Icon(
|
|
207
|
+
source = "media_fail",
|
|
208
|
+
color = theme.colors.text.disable,
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
170
213
|
@Composable
|
|
171
214
|
fun Image(
|
|
172
215
|
source: Painter,
|
|
@@ -185,4 +228,4 @@ fun Image(
|
|
|
185
228
|
colorFilter = colorFilter,
|
|
186
229
|
alpha = alpha,
|
|
187
230
|
)
|
|
188
|
-
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package vn.momo.kits.components
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
5
|
+
import vn.momo.kits.application.ScaleSizeMaxRate
|
|
6
|
+
|
|
7
|
+
@Composable
|
|
8
|
+
fun ScaleSizeScope(
|
|
9
|
+
scaleSizeMaxRate: Float? = null,
|
|
10
|
+
content: @Composable () -> Unit
|
|
11
|
+
) {
|
|
12
|
+
CompositionLocalProvider(
|
|
13
|
+
ScaleSizeMaxRate provides scaleSizeMaxRate,
|
|
14
|
+
) {
|
|
15
|
+
content()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -36,7 +36,6 @@ fun Text(
|
|
|
36
36
|
softWrap: Boolean = true,
|
|
37
37
|
accessibilityId: String? = null,
|
|
38
38
|
inlineContent: Map<String, InlineTextContent> = mapOf(),
|
|
39
|
-
userScaleRate: Float? = null,
|
|
40
39
|
) {
|
|
41
40
|
Text(
|
|
42
41
|
text = AnnotatedString(text),
|
|
@@ -53,8 +52,7 @@ fun Text(
|
|
|
53
52
|
letterSpacing = letterSpacing,
|
|
54
53
|
softWrap = softWrap,
|
|
55
54
|
accessibilityId = accessibilityId,
|
|
56
|
-
inlineContent = inlineContent
|
|
57
|
-
userScaleRate = userScaleRate
|
|
55
|
+
inlineContent = inlineContent
|
|
58
56
|
)
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -76,14 +74,13 @@ fun Text(
|
|
|
76
74
|
softWrap: Boolean = true,
|
|
77
75
|
accessibilityId: String? = null,
|
|
78
76
|
inlineContent: Map<String, InlineTextContent> = mapOf(),
|
|
79
|
-
userScaleRate: Float? = null,
|
|
80
77
|
) {
|
|
81
78
|
// Cache theme access to avoid repeated lookups
|
|
82
79
|
val theme = AppTheme.current
|
|
83
80
|
|
|
84
81
|
// Call @Composable functions directly in composable context
|
|
85
|
-
val scaledFontSize = scaleSize(style.fontSize
|
|
86
|
-
val scaledLineHeight = scaleSize(style.lineHeight
|
|
82
|
+
val scaledFontSize = scaleSize(style.fontSize)
|
|
83
|
+
val scaledLineHeight = scaleSize(style.lineHeight)
|
|
87
84
|
val fontFamilyResult = getFontFamily(fontFamily ?: theme.font, style.fontWeight)
|
|
88
85
|
|
|
89
86
|
// Now memoize the results
|
|
@@ -11,7 +11,7 @@ import androidx.compose.ui.unit.*
|
|
|
11
11
|
import org.jetbrains.compose.resources.Font
|
|
12
12
|
import org.jetbrains.compose.resources.FontResource
|
|
13
13
|
import org.jetbrains.compose.resources.InternalResourceApi
|
|
14
|
-
import vn.momo.kits.application.
|
|
14
|
+
import vn.momo.kits.application.ScaleSizeMaxRate
|
|
15
15
|
import vn.momo.kits.platform.getScreenDimensions
|
|
16
16
|
import vn.momo.uikits.resources.*
|
|
17
17
|
import kotlin.math.max
|
|
@@ -22,58 +22,59 @@ const val MAX_FONT_SCALE = 1.5f
|
|
|
22
22
|
const val MAX_DEVICE_SCALE = 5
|
|
23
23
|
|
|
24
24
|
@Composable
|
|
25
|
-
fun scaleSize(size: Float
|
|
26
|
-
val
|
|
27
|
-
val
|
|
28
|
-
val
|
|
25
|
+
fun scaleSize(size: Float): Float {
|
|
26
|
+
val scaleSizeMaxRate: Float = ScaleSizeMaxRate.current ?: MAX_FONT_SCALE
|
|
27
|
+
val deviceWidth = getScreenDimensions().width
|
|
28
|
+
val deviceScale = deviceWidth / DEFAULT_SCREEN_SIZE
|
|
29
29
|
|
|
30
|
-
val
|
|
31
|
-
val fontScale =
|
|
32
|
-
|
|
33
|
-
if (!useOSFontScale) {
|
|
34
|
-
return if (customRate > 1f) customRate * size else size
|
|
35
|
-
}
|
|
30
|
+
val density = LocalDensity.current
|
|
31
|
+
val fontScale = density.fontScale
|
|
36
32
|
|
|
37
33
|
var fontSizeScaleDevice = size
|
|
38
34
|
var fontSizeScaleOS = size
|
|
35
|
+
|
|
39
36
|
if (deviceScale > 1) {
|
|
40
37
|
fontSizeScaleDevice =
|
|
41
38
|
min(deviceScale * fontSizeScaleDevice, fontSizeScaleDevice + MAX_DEVICE_SCALE)
|
|
42
39
|
}
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
|
|
41
|
+
if (fontScale > 1) {
|
|
42
|
+
fontSizeScaleOS = min(fontScale * fontSizeScaleOS, fontSizeScaleOS * scaleSizeMaxRate)
|
|
45
43
|
}
|
|
46
44
|
|
|
47
|
-
return max(
|
|
45
|
+
return max(
|
|
46
|
+
fontSizeScaleDevice,
|
|
47
|
+
fontSizeScaleOS
|
|
48
|
+
)
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
@Composable
|
|
51
|
-
fun scaleSize(size: TextUnit
|
|
52
|
+
fun scaleSize(size: TextUnit): TextUnit {
|
|
52
53
|
if (!size.isSp) return size
|
|
53
54
|
|
|
54
55
|
val density = LocalDensity.current
|
|
55
56
|
|
|
56
|
-
val scaled = scaleSize(size.value
|
|
57
|
+
val scaled = scaleSize(size.value)
|
|
57
58
|
val spValue = scaled / density.fontScale
|
|
58
59
|
|
|
59
60
|
return TextUnit(value = spValue, type = TextUnitType.Sp)
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
@Composable
|
|
63
|
-
fun scaleSize(size: Dp
|
|
64
|
-
return scaleSize(size.value
|
|
64
|
+
fun scaleSize(size: Dp): Dp {
|
|
65
|
+
return scaleSize(size.value).dp
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
@Composable
|
|
68
|
-
fun scaleSize(textStyle: TextStyle
|
|
69
|
+
fun scaleSize(textStyle: TextStyle): TextStyle {
|
|
69
70
|
return textStyle.copy(
|
|
70
71
|
fontSize = if (textStyle.fontSize != TextUnit.Unspecified)
|
|
71
|
-
scaleSize(textStyle.fontSize
|
|
72
|
+
scaleSize(textStyle.fontSize)
|
|
72
73
|
else
|
|
73
74
|
TextUnit.Unspecified,
|
|
74
75
|
|
|
75
76
|
lineHeight = if (textStyle.lineHeight != TextUnit.Unspecified)
|
|
76
|
-
scaleSize(textStyle.lineHeight
|
|
77
|
+
scaleSize(textStyle.lineHeight)
|
|
77
78
|
else
|
|
78
79
|
TextUnit.Unspecified,
|
|
79
80
|
)
|