@momo-kits/native-kits 0.151.2-test.2 → 0.151.2-test.4
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 +2 -0
- package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +1 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +3 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +35 -14
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +4 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +3 -1
- package/ios/Button/Button.swift +19 -3
- package/ios/Lottie/LottieView.swift +86 -0
- package/ios/Lottie/LottieViewController.swift +55 -0
- package/package.json +1 -1
package/compose/build.gradle.kts
CHANGED
|
@@ -47,6 +47,8 @@ kotlin {
|
|
|
47
47
|
implementation(libs.coil.multiplatform.network.ktor)
|
|
48
48
|
implementation(libs.jetbrains.serialization.json)
|
|
49
49
|
implementation(libs.kotlinx.datetime)
|
|
50
|
+
implementation(libs.compottie)
|
|
51
|
+
implementation(libs.compottie.res)
|
|
50
52
|
api(project(":NativeMaxApi"))
|
|
51
53
|
}
|
|
52
54
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"v":"5.10.2","fr":30,"ip":0,"op":50,"w":100,"h":100,"nm":"Spinner3_white","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"loading","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[0],"e":[200]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[200],"e":[360]},{"t":35}],"ix":10},"p":{"a":0,"k":[50,50,0],"ix":2,"l":2},"a":{"a":0,"k":[44.124,44.124,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[90,90],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.996078431373,0.956862745098,0.980392156863,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[44.124,44.124],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.392],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[0],"e":[100]},{"t":50}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0],"e":[100]},{"t":28}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"loading 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0],"e":[200]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[200],"e":[360]},{"t":37}],"ix":10},"p":{"a":0,"k":[50,50,0],"ix":2,"l":2},"a":{"a":0,"k":[44.124,44.124,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[90,90],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.835294117647,0.917647058824,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[44.124,44.124],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.392],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":20,"s":[0],"e":[100]},{"t":49}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0],"e":[100]},{"t":30}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":30,"op":50,"st":2,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"base","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[50,50,0],"ix":2,"l":2},"a":{"a":0,"k":[44.124,44.124,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[90,90],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.996078431373,0.956862745098,0.980392156863,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[44.124,44.124],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0}],"markers":[]}
|
|
@@ -2,6 +2,7 @@ package vn.momo.kits.application
|
|
|
2
2
|
|
|
3
3
|
import androidx.compose.runtime.Composable
|
|
4
4
|
import androidx.compose.runtime.CompositionLocalProvider
|
|
5
|
+
import androidx.compose.runtime.Immutable
|
|
5
6
|
import androidx.compose.runtime.LaunchedEffect
|
|
6
7
|
import androidx.compose.runtime.getValue
|
|
7
8
|
import androidx.compose.runtime.mutableStateOf
|
|
@@ -63,6 +64,7 @@ class Navigator {
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
@Immutable
|
|
66
68
|
data class MiniAppContext(
|
|
67
69
|
val appIcon: String = "",
|
|
68
70
|
val appName: Any? = null,
|
|
@@ -156,6 +158,7 @@ val AppLanguage = staticCompositionLocalOf<String?> {
|
|
|
156
158
|
null
|
|
157
159
|
}
|
|
158
160
|
|
|
161
|
+
@Immutable
|
|
159
162
|
data class KitConfig(
|
|
160
163
|
val trustBanner: TrustBannerData? = null,
|
|
161
164
|
val headerBar: String? = null,
|
|
@@ -11,23 +11,30 @@ import androidx.compose.foundation.layout.height
|
|
|
11
11
|
import androidx.compose.foundation.layout.padding
|
|
12
12
|
import androidx.compose.foundation.layout.size
|
|
13
13
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
14
|
-
import androidx.compose.material3.CircularProgressIndicator
|
|
15
14
|
import androidx.compose.runtime.Composable
|
|
15
|
+
import androidx.compose.runtime.getValue
|
|
16
16
|
import androidx.compose.runtime.remember
|
|
17
17
|
import androidx.compose.ui.Alignment
|
|
18
18
|
import androidx.compose.ui.Modifier
|
|
19
|
+
import androidx.compose.ui.draw.alpha
|
|
19
20
|
import androidx.compose.ui.draw.clip
|
|
20
21
|
import androidx.compose.ui.graphics.Color
|
|
21
22
|
import androidx.compose.ui.text.TextStyle
|
|
22
23
|
import androidx.compose.ui.text.style.TextOverflow
|
|
23
24
|
import androidx.compose.ui.unit.Dp
|
|
24
25
|
import androidx.compose.ui.unit.dp
|
|
26
|
+
import io.github.alexzhirkevich.compottie.Compottie
|
|
27
|
+
import io.github.alexzhirkevich.compottie.LottieCompositionSpec
|
|
28
|
+
import io.github.alexzhirkevich.compottie.animateLottieCompositionAsState
|
|
29
|
+
import io.github.alexzhirkevich.compottie.rememberLottieComposition
|
|
30
|
+
import io.github.alexzhirkevich.compottie.rememberLottiePainter
|
|
25
31
|
import vn.momo.kits.const.AppTheme
|
|
26
32
|
import vn.momo.kits.const.Colors
|
|
27
33
|
import vn.momo.kits.const.Radius
|
|
28
34
|
import vn.momo.kits.const.Spacing
|
|
29
35
|
import vn.momo.kits.const.Typography
|
|
30
36
|
import vn.momo.kits.modifier.activeOpacityClickable
|
|
37
|
+
import vn.momo.uikits.resources.Res
|
|
31
38
|
|
|
32
39
|
enum class ButtonType {
|
|
33
40
|
PRIMARY,
|
|
@@ -145,22 +152,35 @@ fun RenderLeading(
|
|
|
145
152
|
) {
|
|
146
153
|
if (loading) {
|
|
147
154
|
Box(Modifier.padding(end = marginRight)) {
|
|
148
|
-
|
|
155
|
+
val composition by rememberLottieComposition {
|
|
156
|
+
LottieCompositionSpec.JsonString(
|
|
157
|
+
Res.readBytes("files/spinner_white.json").decodeToString()
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
val progress by animateLottieCompositionAsState(
|
|
162
|
+
composition = composition,
|
|
163
|
+
iterations = Compottie.IterateForever
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
Image(
|
|
167
|
+
source = rememberLottiePainter(
|
|
168
|
+
composition = composition,
|
|
169
|
+
progress = { progress }
|
|
170
|
+
),
|
|
149
171
|
modifier = Modifier.size(iconSize - 4.dp),
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
if (iconLeft.isNotEmpty()) {
|
|
176
|
+
Icon(
|
|
177
|
+
source = iconLeft,
|
|
150
178
|
color = color,
|
|
151
|
-
|
|
152
|
-
|
|
179
|
+
size = iconSize,
|
|
180
|
+
modifier = Modifier.padding(end = marginRight)
|
|
153
181
|
)
|
|
154
182
|
}
|
|
155
183
|
}
|
|
156
|
-
if (iconLeft.isNotEmpty()) {
|
|
157
|
-
Icon(
|
|
158
|
-
source = iconLeft,
|
|
159
|
-
color = color,
|
|
160
|
-
size = iconSize,
|
|
161
|
-
modifier = Modifier.padding(end = marginRight)
|
|
162
|
-
)
|
|
163
|
-
}
|
|
164
184
|
}
|
|
165
185
|
}
|
|
166
186
|
|
|
@@ -261,7 +281,7 @@ fun Button(
|
|
|
261
281
|
}
|
|
262
282
|
}.activeOpacityClickable(
|
|
263
283
|
activeOpacity = 0.5f,
|
|
264
|
-
enabled = isEnabled,
|
|
284
|
+
enabled = isEnabled && !loading,
|
|
265
285
|
onClick = onClick
|
|
266
286
|
)
|
|
267
287
|
|
|
@@ -272,7 +292,8 @@ fun Button(
|
|
|
272
292
|
.then(getTypeStyle(type, size = size))
|
|
273
293
|
.padding(horizontal = sizeSpecs.padding)
|
|
274
294
|
.defaultMinSize(minWidth = sizeSpecs.width)
|
|
275
|
-
.height(sizeSpecs.height)
|
|
295
|
+
.height(sizeSpecs.height)
|
|
296
|
+
.alpha(if(loading) 0.75f else 1f),
|
|
276
297
|
horizontalArrangement = Arrangement.Center,
|
|
277
298
|
verticalAlignment = Alignment.CenterVertically,
|
|
278
299
|
) {
|
package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt
CHANGED
|
@@ -2,7 +2,6 @@ package vn.momo.kits.components.datetimepicker
|
|
|
2
2
|
|
|
3
3
|
import androidx.compose.runtime.Composable
|
|
4
4
|
import androidx.compose.runtime.remember
|
|
5
|
-
import kotlinx.datetime.Clock
|
|
6
5
|
import kotlinx.datetime.DatePeriod
|
|
7
6
|
import kotlinx.datetime.LocalDateTime
|
|
8
7
|
import kotlinx.datetime.TimeZone
|
|
@@ -10,6 +9,8 @@ import kotlinx.datetime.minus
|
|
|
10
9
|
import kotlinx.datetime.number
|
|
11
10
|
import kotlinx.datetime.plus
|
|
12
11
|
import kotlinx.datetime.toLocalDateTime
|
|
12
|
+
import kotlin.time.Clock.System.now
|
|
13
|
+
import kotlin.time.ExperimentalTime
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Format a LocalDateTime object into a string
|
|
@@ -149,8 +150,9 @@ val timeMode = listOf("AM", "PM")
|
|
|
149
150
|
/**
|
|
150
151
|
* Get today's date
|
|
151
152
|
*/
|
|
153
|
+
@OptIn(ExperimentalTime::class)
|
|
152
154
|
fun getCurrentDateTime(): LocalDateTime {
|
|
153
|
-
return
|
|
155
|
+
return now().toLocalDateTime(TimeZone.currentSystemDefault())
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
/**
|
|
@@ -2,6 +2,7 @@ package vn.momo.kits.navigation
|
|
|
2
2
|
|
|
3
3
|
import androidx.compose.foundation.gestures.ScrollableState
|
|
4
4
|
import androidx.compose.runtime.Composable
|
|
5
|
+
import androidx.compose.runtime.Stable
|
|
5
6
|
import androidx.compose.runtime.State
|
|
6
7
|
import androidx.compose.runtime.mutableStateOf
|
|
7
8
|
import androidx.compose.runtime.staticCompositionLocalOf
|
|
@@ -66,6 +67,7 @@ val LocalNavigation = staticCompositionLocalOf<Navigation> {
|
|
|
66
67
|
error("No NavigationStack provided")
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
@Stable
|
|
69
71
|
data class NavigationOptions(
|
|
70
72
|
val onBackHandler: (() -> Unit)? = null,
|
|
71
73
|
val hiddenBack: Boolean = false,
|
|
@@ -87,6 +89,6 @@ data class KeyboardOptions(
|
|
|
87
89
|
|
|
88
90
|
|
|
89
91
|
data class ScrollData(
|
|
90
|
-
val scrollable: Boolean =
|
|
92
|
+
val scrollable: Boolean = true,
|
|
91
93
|
val scrollState: ScrollableState? = null,
|
|
92
94
|
)
|
package/ios/Button/Button.swift
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import Foundation
|
|
3
3
|
import SwiftUI
|
|
4
|
+
import Lottie
|
|
4
5
|
|
|
5
6
|
// MARK: - ButtonType
|
|
6
7
|
|
|
@@ -27,13 +28,14 @@ public enum ButtonSize {
|
|
|
27
28
|
public struct Button: View {
|
|
28
29
|
// MARK: Lifecycle
|
|
29
30
|
|
|
30
|
-
public init(title: String = "", action: @escaping () -> Void, type: ButtonType = .primary, size: ButtonSize = .large, iconLeft: AnyView? = nil, iconRight: AnyView? = nil) {
|
|
31
|
+
public init(title: String = "", action: @escaping () -> Void, type: ButtonType = .primary, size: ButtonSize = .large, iconLeft: AnyView? = nil, iconRight: AnyView? = nil, loading: Bool = false) {
|
|
31
32
|
self.title = title
|
|
32
33
|
self.action = action
|
|
33
34
|
self.type = type
|
|
34
35
|
self.size = size
|
|
35
36
|
self.iconLeft = iconLeft
|
|
36
37
|
self.iconRight = iconRight
|
|
38
|
+
self.loading = loading
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
// MARK: Public
|
|
@@ -41,13 +43,26 @@ public struct Button: View {
|
|
|
41
43
|
public var body: some View {
|
|
42
44
|
SwiftUI.Button(action: action) {
|
|
43
45
|
HStack {
|
|
44
|
-
|
|
46
|
+
if (loading) {
|
|
47
|
+
LottieView(
|
|
48
|
+
name: "lottie_circle_loader",
|
|
49
|
+
loopMode: .loop,
|
|
50
|
+
contentMode: .center
|
|
51
|
+
)
|
|
52
|
+
.frame(width: 32, height: 32)
|
|
53
|
+
.foregroundColor(.white)
|
|
54
|
+
.colorMultiply(.white)
|
|
55
|
+
} else {
|
|
56
|
+
iconLeft
|
|
57
|
+
}
|
|
45
58
|
renderTitle(title: title, type: type, size: size).lineLimit(1).truncationMode(.tail)
|
|
46
59
|
iconRight
|
|
47
60
|
}
|
|
48
61
|
.buttonSize(size)
|
|
49
62
|
.buttonType(type)
|
|
50
|
-
|
|
63
|
+
.opacity(loading ? 0.75 : 1.0)
|
|
64
|
+
}
|
|
65
|
+
.disabled(type == .disabled && !loading)
|
|
51
66
|
.clipShape(RoundedRectangle(cornerRadius: Radius.S))
|
|
52
67
|
}
|
|
53
68
|
|
|
@@ -59,6 +74,7 @@ public struct Button: View {
|
|
|
59
74
|
var size: ButtonSize = .large
|
|
60
75
|
var iconLeft: AnyView?
|
|
61
76
|
var iconRight: AnyView?
|
|
77
|
+
var loading: Bool
|
|
62
78
|
|
|
63
79
|
func renderTitle(title: String, type: ButtonType, size: ButtonSize) -> Text {
|
|
64
80
|
switch size {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//
|
|
2
|
+
// LottieView.swift
|
|
3
|
+
// MoMoPlatform
|
|
4
|
+
//
|
|
5
|
+
// Created by thanhdat on 16/01/2023.
|
|
6
|
+
// Copyright © 2023 Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import SwiftUI
|
|
10
|
+
import Lottie
|
|
11
|
+
|
|
12
|
+
struct LottieView: UIViewRepresentable {
|
|
13
|
+
var name: String = ""
|
|
14
|
+
var url: String?
|
|
15
|
+
var loopMode: LottieLoopMode = .playOnce
|
|
16
|
+
var contentMode : UIView.ContentMode = .scaleAspectFit
|
|
17
|
+
var onDone: (() -> Void)?
|
|
18
|
+
|
|
19
|
+
// Add static cache for animations
|
|
20
|
+
private static var animationCache = NSCache<NSString, LottieAnimation>()
|
|
21
|
+
|
|
22
|
+
func makeUIView(context: UIViewRepresentableContext<LottieView>) -> UIView {
|
|
23
|
+
let view = UIView(frame: .zero)
|
|
24
|
+
|
|
25
|
+
// Configure Lottie with optimized settings
|
|
26
|
+
let configuration = LottieConfiguration(
|
|
27
|
+
renderingEngine: .coreAnimation,
|
|
28
|
+
decodingStrategy: .dictionaryBased
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
let animationView = LottieAnimationView(configuration: configuration)
|
|
32
|
+
|
|
33
|
+
if let url = url {
|
|
34
|
+
// Use cached animation if available
|
|
35
|
+
if let cachedAnimation = Self.animationCache.object(forKey: url as NSString) {
|
|
36
|
+
animationView.animation = cachedAnimation
|
|
37
|
+
setupAnimationView(animationView, view)
|
|
38
|
+
} else {
|
|
39
|
+
LottieAnimation.loadedFrom(url: URL(string: url)!, closure: { animation in
|
|
40
|
+
if let animation = animation {
|
|
41
|
+
Self.animationCache.setObject(animation, forKey: url as NSString)
|
|
42
|
+
animationView.animation = animation
|
|
43
|
+
setupAnimationView(animationView, view)
|
|
44
|
+
}
|
|
45
|
+
}, animationCache: nil)
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
// Use cached animation if available
|
|
49
|
+
if let cachedAnimation = Self.animationCache.object(forKey: name as NSString) {
|
|
50
|
+
animationView.animation = cachedAnimation
|
|
51
|
+
setupAnimationView(animationView, view)
|
|
52
|
+
} else if let animation = LottieAnimation.named(name) {
|
|
53
|
+
Self.animationCache.setObject(animation, forKey: name as NSString)
|
|
54
|
+
animationView.animation = animation
|
|
55
|
+
setupAnimationView(animationView, view)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return view
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private func setupAnimationView(_ animationView: LottieAnimationView, _ containerView: UIView) {
|
|
63
|
+
animationView.contentMode = contentMode
|
|
64
|
+
animationView.loopMode = loopMode
|
|
65
|
+
animationView.backgroundBehavior = loopMode == .loop ? .pauseAndRestore : .pause
|
|
66
|
+
|
|
67
|
+
// Optimize rendering
|
|
68
|
+
animationView.shouldRasterizeWhenIdle = true
|
|
69
|
+
|
|
70
|
+
animationView.translatesAutoresizingMaskIntoConstraints = false
|
|
71
|
+
containerView.addSubview(animationView)
|
|
72
|
+
|
|
73
|
+
NSLayoutConstraint.activate([
|
|
74
|
+
animationView.widthAnchor.constraint(equalTo: containerView.widthAnchor),
|
|
75
|
+
animationView.heightAnchor.constraint(equalTo: containerView.heightAnchor)
|
|
76
|
+
])
|
|
77
|
+
|
|
78
|
+
animationView.play { finished in
|
|
79
|
+
if finished {
|
|
80
|
+
onDone?()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieView>) {}
|
|
86
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//
|
|
2
|
+
// LottieViewController.swift
|
|
3
|
+
// MoMoPlatform
|
|
4
|
+
//
|
|
5
|
+
// Created by Đại Trịnh on 26/09/2023.
|
|
6
|
+
// Copyright © 2023 Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import Lottie
|
|
11
|
+
import SwiftUI
|
|
12
|
+
|
|
13
|
+
public class LottieViewController: UIViewController {
|
|
14
|
+
var name: String = ""
|
|
15
|
+
var url: String?
|
|
16
|
+
var loopMode: LottieLoopMode = .playOnce
|
|
17
|
+
var frame: CGRect
|
|
18
|
+
var id: String?
|
|
19
|
+
|
|
20
|
+
init(name: String, url: String? = nil, loopMode: LottieLoopMode, frame: CGRect, id: String? = nil) {
|
|
21
|
+
self.name = name
|
|
22
|
+
self.url = url
|
|
23
|
+
self.loopMode = loopMode
|
|
24
|
+
self.frame = frame
|
|
25
|
+
self.id = id
|
|
26
|
+
|
|
27
|
+
super.init(nibName: nil, bundle: nil)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
required init?(coder: NSCoder) {
|
|
31
|
+
fatalError("init(coder:) has not been implemented")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public override func viewDidLoad() {
|
|
35
|
+
super.viewDidLoad()
|
|
36
|
+
setupCustomView()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private func setupCustomView() {
|
|
40
|
+
let basicView = UIView()
|
|
41
|
+
basicView.frame = frame
|
|
42
|
+
|
|
43
|
+
let customLottieView = LottieView(name: name, url: url, loopMode: loopMode)
|
|
44
|
+
let hostViewController = UIHostingController(rootView: customLottieView)
|
|
45
|
+
hostViewController.view.frame = basicView.bounds;
|
|
46
|
+
hostViewController.view.backgroundColor = .clear
|
|
47
|
+
|
|
48
|
+
// set accessibility label
|
|
49
|
+
basicView.accessibilityLabel = id ?? "" // Set accessibility label directly to basicView
|
|
50
|
+
basicView.isAccessibilityElement = true // Ensure basicView is treated as an accessible element
|
|
51
|
+
|
|
52
|
+
basicView.addSubview(hostViewController.view)
|
|
53
|
+
view.addSubview(basicView)
|
|
54
|
+
}
|
|
55
|
+
}
|