@thelacanians/vue-native-cli 0.4.3 → 0.4.5
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/dist/cli.js +102 -32
- package/native/android/README.md +205 -0
- package/native/android/VueNativeCore/build.gradle.kts +113 -0
- package/native/android/VueNativeCore/consumer-rules.pro +12 -0
- package/native/android/VueNativeCore/proguard-rules.pro +33 -0
- package/native/android/VueNativeCore/src/main/AndroidManifest.xml +17 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/ErrorOverlayView.kt +94 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/HotReloadManager.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSPolyfills.kt +652 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSRuntime.kt +207 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +417 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/ComponentRegistry.kt +76 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActionSheetFactory.kt +78 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActivityIndicatorFactory.kt +46 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VAlertDialogFactory.kt +84 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VButtonFactory.kt +73 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VCheckboxFactory.kt +93 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VDropdownFactory.kt +125 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VImageFactory.kt +75 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VInputFactory.kt +210 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VKeyboardAvoidingFactory.kt +31 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +183 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VModalFactory.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPickerFactory.kt +57 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPressableFactory.kt +109 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VProgressBarFactory.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRadioFactory.kt +103 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRefreshControlFactory.kt +73 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRootFactory.kt +39 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSafeAreaFactory.kt +48 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSectionListFactory.kt +144 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSegmentedControlFactory.kt +77 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +74 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VStatusBarFactory.kt +52 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSwitchFactory.kt +62 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VTextFactory.kt +53 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VVideoFactory.kt +191 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +48 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VWebViewFactory.kt +90 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/NativeComponentFactory.kt +40 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/VTextNodeView.kt +23 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/GestureHelper.kt +16 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/TouchableView.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AnimationModule.kt +292 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AppStateModule.kt +41 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AsyncStorageModule.kt +59 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AudioModule.kt +331 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BackgroundTaskModule.kt +166 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BiometryModule.kt +56 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BluetoothModule.kt +302 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CalendarModule.kt +198 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CameraModule.kt +64 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ClipboardModule.kt +36 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ContactsModule.kt +288 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DatabaseModule.kt +229 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DeviceInfoModule.kt +39 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/FileSystemModule.kt +193 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeolocationModule.kt +68 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HapticsModule.kt +61 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HttpModule.kt +111 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/IAPModule.kt +302 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/KeyboardModule.kt +26 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/LinkingModule.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModule.kt +27 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +92 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NetworkModule.kt +75 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NotificationsModule.kt +181 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/OTAModule.kt +255 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PerformanceModule.kt +147 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PermissionsModule.kt +126 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SecureStorageModule.kt +51 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SensorsModule.kt +134 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ShareModule.kt +36 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SocialAuthModule.kt +163 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/WebSocketModule.kt +155 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Styling/StyleEngine.kt +802 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Tags.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/VueNativeActivity.kt +169 -0
- package/native/android/VueNativeCore/src/main/res/values/ids.xml +8 -0
- package/native/android/app/build.gradle.kts +45 -0
- package/native/android/app/proguard-rules.pro +5 -0
- package/native/android/app/src/main/AndroidManifest.xml +25 -0
- package/native/android/app/src/main/assets/.gitkeep +0 -0
- package/native/android/app/src/main/kotlin/com/vuenative/example/counter/MainActivity.kt +14 -0
- package/native/android/app/src/main/res/layout/activity_main.xml +6 -0
- package/native/android/app/src/main/res/values/strings.xml +3 -0
- package/native/android/app/src/main/res/values/themes.xml +9 -0
- package/native/android/app/src/main/res/xml/network_security_config.xml +8 -0
- package/native/android/build.gradle.kts +6 -0
- package/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/native/android/gradle.properties +4 -0
- package/native/android/gradlew +87 -0
- package/native/android/gradlew.bat +48 -0
- package/native/android/settings.gradle.kts +20 -0
- package/native/ios/VueNativeCore/Package.resolved +23 -0
- package/native/ios/VueNativeCore/Package.swift +32 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/CertificatePinning.swift +136 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +89 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/HotReloadManager.swift +147 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSPolyfills.swift +711 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSRuntime.swift +421 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +906 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/VueNativeViewController.swift +88 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/ComponentRegistry.swift +193 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActionSheetFactory.swift +90 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActivityIndicatorFactory.swift +74 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VAlertDialogFactory.swift +149 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VButtonFactory.swift +93 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VCheckboxFactory.swift +114 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VDropdownFactory.swift +112 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VImageFactory.swift +172 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VInputFactory.swift +357 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VKeyboardAvoidingFactory.swift +99 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +250 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VModalFactory.swift +109 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPickerFactory.swift +96 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPressableFactory.swift +168 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VProgressBarFactory.swift +39 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRadioFactory.swift +167 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRefreshControlFactory.swift +153 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSafeAreaFactory.swift +56 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +240 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSectionListFactory.swift +248 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSegmentedControlFactory.swift +73 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +63 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VStatusBarFactory.swift +50 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSwitchFactory.swift +108 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +290 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VVideoFactory.swift +250 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +157 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VWebViewFactory.swift +174 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/Extensions.swift +31 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +283 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +59 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +371 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +379 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +154 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +315 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +141 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +48 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +256 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
- package/package.json +3 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
/// ObjC-compatible wrapper for gesture recognizer action handlers.
|
|
5
|
+
/// Allows attaching Swift closure-based event handlers to UIGestureRecognizers
|
|
6
|
+
/// that require an @objc selector target.
|
|
7
|
+
@objc final class GestureWrapper: NSObject {
|
|
8
|
+
|
|
9
|
+
private let handler: (Any?) -> Void
|
|
10
|
+
|
|
11
|
+
init(handler: @escaping (Any?) -> Void) {
|
|
12
|
+
self.handler = handler
|
|
13
|
+
super.init()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@objc func handleGesture(_ gesture: UIGestureRecognizer) {
|
|
17
|
+
handler(nil)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@objc func handleGestureWithState(_ gesture: UIGestureRecognizer) {
|
|
21
|
+
let payload: [String: Any] = [
|
|
22
|
+
"state": gesture.state.rawValue,
|
|
23
|
+
"locationX": gesture.location(in: gesture.view).x,
|
|
24
|
+
"locationY": gesture.location(in: gesture.view).y
|
|
25
|
+
]
|
|
26
|
+
handler(payload)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// MARK: - PanWrapper
|
|
31
|
+
|
|
32
|
+
/// ObjC-compatible wrapper for UIPanGestureRecognizer action handlers.
|
|
33
|
+
@objc final class PanWrapper: NSObject {
|
|
34
|
+
private let handler: (Any?) -> Void
|
|
35
|
+
|
|
36
|
+
init(handler: @escaping (Any?) -> Void) {
|
|
37
|
+
self.handler = handler
|
|
38
|
+
super.init()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@objc func handle(_ recognizer: UIPanGestureRecognizer) {
|
|
42
|
+
guard let view = recognizer.view else { return }
|
|
43
|
+
let translation = recognizer.translation(in: view.superview)
|
|
44
|
+
let velocity = recognizer.velocity(in: view.superview)
|
|
45
|
+
let stateStr: String
|
|
46
|
+
switch recognizer.state {
|
|
47
|
+
case .began: stateStr = "began"
|
|
48
|
+
case .changed: stateStr = "changed"
|
|
49
|
+
case .ended: stateStr = "ended"
|
|
50
|
+
case .cancelled, .failed: stateStr = "cancelled"
|
|
51
|
+
default: stateStr = "unknown"
|
|
52
|
+
}
|
|
53
|
+
handler([
|
|
54
|
+
"translationX": translation.x,
|
|
55
|
+
"translationY": translation.y,
|
|
56
|
+
"velocityX": velocity.x,
|
|
57
|
+
"velocityY": velocity.y,
|
|
58
|
+
"state": stateStr
|
|
59
|
+
] as [String: Any])
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// MARK: - SwipeWrapper
|
|
64
|
+
|
|
65
|
+
/// ObjC-compatible wrapper for UISwipeGestureRecognizer action handlers.
|
|
66
|
+
@objc final class SwipeWrapper: NSObject {
|
|
67
|
+
private let handler: (Any?) -> Void
|
|
68
|
+
private let direction: String
|
|
69
|
+
|
|
70
|
+
init(handler: @escaping (Any?) -> Void, direction: String) {
|
|
71
|
+
self.handler = handler
|
|
72
|
+
self.direction = direction
|
|
73
|
+
super.init()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@objc func handle(_ recognizer: UISwipeGestureRecognizer) {
|
|
77
|
+
handler(["direction": direction] as [String: Any])
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// MARK: - PinchWrapper
|
|
82
|
+
|
|
83
|
+
/// ObjC-compatible wrapper for UIPinchGestureRecognizer action handlers.
|
|
84
|
+
@objc final class PinchWrapper: NSObject {
|
|
85
|
+
private let handler: (Any?) -> Void
|
|
86
|
+
|
|
87
|
+
init(handler: @escaping (Any?) -> Void) {
|
|
88
|
+
self.handler = handler
|
|
89
|
+
super.init()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@objc func handle(_ recognizer: UIPinchGestureRecognizer) {
|
|
93
|
+
let stateStr: String
|
|
94
|
+
switch recognizer.state {
|
|
95
|
+
case .began: stateStr = "began"
|
|
96
|
+
case .changed: stateStr = "changed"
|
|
97
|
+
case .ended: stateStr = "ended"
|
|
98
|
+
default: stateStr = "cancelled"
|
|
99
|
+
}
|
|
100
|
+
handler([
|
|
101
|
+
"scale": recognizer.scale,
|
|
102
|
+
"velocity": recognizer.velocity,
|
|
103
|
+
"state": stateStr
|
|
104
|
+
] as [String: Any])
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
#endif
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
/// Custom UIView subclass that provides button-like touch behavior
|
|
5
|
+
/// with configurable active opacity and support for press and long press events.
|
|
6
|
+
class TouchableView: UIView {
|
|
7
|
+
|
|
8
|
+
// MARK: - Public properties
|
|
9
|
+
|
|
10
|
+
/// The opacity to apply when the user is pressing the view.
|
|
11
|
+
var activeOpacity: CGFloat = 0.7
|
|
12
|
+
|
|
13
|
+
/// Called when a tap completes within the view bounds.
|
|
14
|
+
var onPress: (() -> Void)?
|
|
15
|
+
|
|
16
|
+
/// Called when a long press gesture is recognized.
|
|
17
|
+
var onLongPress: (() -> Void)?
|
|
18
|
+
|
|
19
|
+
/// Whether touch interactions are disabled.
|
|
20
|
+
var isDisabled: Bool = false {
|
|
21
|
+
didSet {
|
|
22
|
+
isUserInteractionEnabled = !isDisabled
|
|
23
|
+
alpha = isDisabled ? 0.4 : 1.0
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// MARK: - Private properties
|
|
28
|
+
|
|
29
|
+
private var longPressRecognizer: UILongPressGestureRecognizer?
|
|
30
|
+
private var isTouchInside: Bool = false
|
|
31
|
+
|
|
32
|
+
// MARK: - Initialization
|
|
33
|
+
|
|
34
|
+
override init(frame: CGRect) {
|
|
35
|
+
super.init(frame: frame)
|
|
36
|
+
setupLongPressRecognizer()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
required init?(coder: NSCoder) {
|
|
40
|
+
super.init(coder: coder)
|
|
41
|
+
setupLongPressRecognizer()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// MARK: - Touch handling
|
|
45
|
+
|
|
46
|
+
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
47
|
+
super.touchesBegan(touches, with: event)
|
|
48
|
+
guard !isDisabled else { return }
|
|
49
|
+
|
|
50
|
+
isTouchInside = true
|
|
51
|
+
UIView.animate(
|
|
52
|
+
withDuration: 0.1,
|
|
53
|
+
delay: 0,
|
|
54
|
+
options: [.beginFromCurrentState, .allowUserInteraction],
|
|
55
|
+
animations: { [weak self] in
|
|
56
|
+
guard let self = self else { return }
|
|
57
|
+
self.alpha = self.activeOpacity
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
63
|
+
super.touchesMoved(touches, with: event)
|
|
64
|
+
guard !isDisabled, let touch = touches.first else { return }
|
|
65
|
+
|
|
66
|
+
let location = touch.location(in: self)
|
|
67
|
+
let wasInside = isTouchInside
|
|
68
|
+
isTouchInside = bounds.contains(location)
|
|
69
|
+
|
|
70
|
+
if wasInside != isTouchInside {
|
|
71
|
+
UIView.animate(
|
|
72
|
+
withDuration: 0.1,
|
|
73
|
+
delay: 0,
|
|
74
|
+
options: [.beginFromCurrentState, .allowUserInteraction],
|
|
75
|
+
animations: { [weak self] in
|
|
76
|
+
guard let self = self else { return }
|
|
77
|
+
self.alpha = self.isTouchInside ? self.activeOpacity : 1.0
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
84
|
+
super.touchesEnded(touches, with: event)
|
|
85
|
+
guard !isDisabled else { return }
|
|
86
|
+
|
|
87
|
+
UIView.animate(
|
|
88
|
+
withDuration: 0.15,
|
|
89
|
+
delay: 0,
|
|
90
|
+
options: [.beginFromCurrentState, .allowUserInteraction],
|
|
91
|
+
animations: { [weak self] in
|
|
92
|
+
self?.alpha = 1.0
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if isTouchInside {
|
|
97
|
+
onPress?()
|
|
98
|
+
}
|
|
99
|
+
isTouchInside = false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
103
|
+
super.touchesCancelled(touches, with: event)
|
|
104
|
+
guard !isDisabled else { return }
|
|
105
|
+
|
|
106
|
+
UIView.animate(
|
|
107
|
+
withDuration: 0.15,
|
|
108
|
+
delay: 0,
|
|
109
|
+
options: [.beginFromCurrentState, .allowUserInteraction],
|
|
110
|
+
animations: { [weak self] in
|
|
111
|
+
self?.alpha = 1.0
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
isTouchInside = false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// MARK: - Long press
|
|
118
|
+
|
|
119
|
+
private func setupLongPressRecognizer() {
|
|
120
|
+
let recognizer = UILongPressGestureRecognizer(
|
|
121
|
+
target: self,
|
|
122
|
+
action: #selector(handleLongPress(_:))
|
|
123
|
+
)
|
|
124
|
+
recognizer.minimumPressDuration = 0.5
|
|
125
|
+
addGestureRecognizer(recognizer)
|
|
126
|
+
longPressRecognizer = recognizer
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@objc private func handleLongPress(_ recognizer: UILongPressGestureRecognizer) {
|
|
130
|
+
guard !isDisabled else { return }
|
|
131
|
+
if recognizer.state == .began {
|
|
132
|
+
onLongPress?()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
#endif
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
extension UIColor {
|
|
5
|
+
|
|
6
|
+
// MARK: - Named color lookup
|
|
7
|
+
|
|
8
|
+
private static let namedColors: [String: UIColor] = [
|
|
9
|
+
"transparent": .clear,
|
|
10
|
+
"black": .black,
|
|
11
|
+
"white": .white,
|
|
12
|
+
"red": .red,
|
|
13
|
+
"green": .green,
|
|
14
|
+
"blue": .blue,
|
|
15
|
+
"gray": .gray,
|
|
16
|
+
"grey": .gray,
|
|
17
|
+
"orange": .orange,
|
|
18
|
+
"yellow": .yellow,
|
|
19
|
+
"purple": .purple,
|
|
20
|
+
"cyan": .cyan,
|
|
21
|
+
"magenta": .magenta,
|
|
22
|
+
"brown": .brown
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
// MARK: - Hex initializer
|
|
26
|
+
|
|
27
|
+
/// Creates a UIColor from a hex string.
|
|
28
|
+
/// Supports formats: "#RGB", "#RRGGBB", "#RRGGBBAA"
|
|
29
|
+
/// Also supports named colors: "transparent", "black", "white", "red", "green", "blue", "gray"
|
|
30
|
+
/// Returns .clear for invalid input.
|
|
31
|
+
static func fromHex(_ hex: String) -> UIColor {
|
|
32
|
+
let trimmed = hex.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
33
|
+
|
|
34
|
+
// Check named colors first
|
|
35
|
+
if let named = namedColors[trimmed] {
|
|
36
|
+
return named
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Must start with '#'
|
|
40
|
+
guard trimmed.hasPrefix("#") else {
|
|
41
|
+
return .clear
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let hexString = String(trimmed.dropFirst())
|
|
45
|
+
let scanner = Scanner(string: hexString)
|
|
46
|
+
var hexNumber: UInt64 = 0
|
|
47
|
+
|
|
48
|
+
guard scanner.scanHexInt64(&hexNumber) else {
|
|
49
|
+
return .clear
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
switch hexString.count {
|
|
53
|
+
case 3:
|
|
54
|
+
// #RGB -> #RRGGBB
|
|
55
|
+
let r = CGFloat((hexNumber & 0xF00) >> 8) / 15.0
|
|
56
|
+
let g = CGFloat((hexNumber & 0x0F0) >> 4) / 15.0
|
|
57
|
+
let b = CGFloat(hexNumber & 0x00F) / 15.0
|
|
58
|
+
return UIColor(red: r, green: g, blue: b, alpha: 1.0)
|
|
59
|
+
|
|
60
|
+
case 6:
|
|
61
|
+
// #RRGGBB
|
|
62
|
+
let r = CGFloat((hexNumber & 0xFF0000) >> 16) / 255.0
|
|
63
|
+
let g = CGFloat((hexNumber & 0x00FF00) >> 8) / 255.0
|
|
64
|
+
let b = CGFloat(hexNumber & 0x0000FF) / 255.0
|
|
65
|
+
return UIColor(red: r, green: g, blue: b, alpha: 1.0)
|
|
66
|
+
|
|
67
|
+
case 8:
|
|
68
|
+
// #RRGGBBAA
|
|
69
|
+
let r = CGFloat((hexNumber & 0xFF000000) >> 24) / 255.0
|
|
70
|
+
let g = CGFloat((hexNumber & 0x00FF0000) >> 16) / 255.0
|
|
71
|
+
let b = CGFloat((hexNumber & 0x0000FF00) >> 8) / 255.0
|
|
72
|
+
let a = CGFloat(hexNumber & 0x000000FF) / 255.0
|
|
73
|
+
return UIColor(red: r, green: g, blue: b, alpha: a)
|
|
74
|
+
|
|
75
|
+
default:
|
|
76
|
+
return .clear
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
#endif
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
/// Native module for UIView animations.
|
|
5
|
+
/// Exposes timing, spring, keyframe, sequence, and parallel animations to JS composables.
|
|
6
|
+
final class AnimationModule: NativeModule {
|
|
7
|
+
|
|
8
|
+
let moduleName = "Animation"
|
|
9
|
+
|
|
10
|
+
func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
11
|
+
switch method {
|
|
12
|
+
case "timing":
|
|
13
|
+
handleTiming(args: args, callback: callback)
|
|
14
|
+
case "spring":
|
|
15
|
+
handleSpring(args: args, callback: callback)
|
|
16
|
+
case "keyframe":
|
|
17
|
+
guard let viewId = args[safe: 0] as? Int,
|
|
18
|
+
let keyframesData = args[safe: 1] as? [[String: Any]],
|
|
19
|
+
let options = args[safe: 2] as? [String: Any] else {
|
|
20
|
+
callback(nil, "Invalid args"); return
|
|
21
|
+
}
|
|
22
|
+
let duration = options["duration"] as? Double ?? 300
|
|
23
|
+
animateKeyframes(viewId: viewId, keyframes: keyframesData, duration: duration / 1000.0, callback: callback)
|
|
24
|
+
case "sequence":
|
|
25
|
+
guard let animationsData = args[safe: 0] as? [[String: Any]] else {
|
|
26
|
+
callback(nil, "Invalid args"); return
|
|
27
|
+
}
|
|
28
|
+
runSequence(animationsData: animationsData, index: 0, callback: callback)
|
|
29
|
+
case "parallel":
|
|
30
|
+
guard let animationsData = args[safe: 0] as? [[String: Any]] else {
|
|
31
|
+
callback(nil, "Invalid args"); return
|
|
32
|
+
}
|
|
33
|
+
runParallel(animationsData: animationsData, callback: callback)
|
|
34
|
+
default:
|
|
35
|
+
callback(nil, "AnimationModule: unknown method '\(method)'")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func invokeSync(method: String, args: [Any]) -> Any? {
|
|
40
|
+
return nil
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// MARK: - timing(viewId, styles, options)
|
|
44
|
+
// args[0]: Int (viewId)
|
|
45
|
+
// args[1]: [String: Any] (target styles, only numeric values like opacity, transform offsets)
|
|
46
|
+
// args[2]: [String: Any] (options: duration, delay, easing)
|
|
47
|
+
|
|
48
|
+
private func handleTiming(args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
49
|
+
guard let viewId = args.first.flatMap({ $0 as? Int ?? ($0 as? Double).map(Int.init) }),
|
|
50
|
+
let styles = args.count > 1 ? args[1] as? [String: Any] : [:] else {
|
|
51
|
+
callback(nil, "timing: invalid arguments")
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let options = args.count > 2 ? (args[2] as? [String: Any] ?? [:]) : [:]
|
|
56
|
+
let duration = (options["duration"] as? Double ?? 300) / 1000.0
|
|
57
|
+
let delay = (options["delay"] as? Double ?? 0) / 1000.0
|
|
58
|
+
let easing = options["easing"] as? String ?? "ease"
|
|
59
|
+
|
|
60
|
+
let curve: UIView.AnimationOptions
|
|
61
|
+
switch easing {
|
|
62
|
+
case "linear": curve = .curveLinear
|
|
63
|
+
case "ease-in", "easeIn": curve = .curveEaseIn
|
|
64
|
+
case "ease-out", "easeOut": curve = .curveEaseOut
|
|
65
|
+
default: curve = .curveEaseInOut
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
DispatchQueue.main.async {
|
|
69
|
+
MainActor.assumeIsolated {
|
|
70
|
+
guard let view = NativeBridge.shared.view(forId: viewId) else {
|
|
71
|
+
callback(nil, "timing: view \(viewId) not found")
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
UIView.animate(
|
|
76
|
+
withDuration: duration,
|
|
77
|
+
delay: delay,
|
|
78
|
+
options: [curve],
|
|
79
|
+
animations: { [styles] in
|
|
80
|
+
MainActor.assumeIsolated {
|
|
81
|
+
for (key, value) in styles {
|
|
82
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
completion: { _ in
|
|
87
|
+
callback(true, nil)
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// MARK: - spring(viewId, styles, options)
|
|
95
|
+
// args[0]: Int (viewId)
|
|
96
|
+
// args[1]: [String: Any] (target styles)
|
|
97
|
+
// args[2]: [String: Any] (options: damping, stiffness/duration, mass)
|
|
98
|
+
|
|
99
|
+
private func handleSpring(args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
100
|
+
guard let viewId = args.first.flatMap({ $0 as? Int ?? ($0 as? Double).map(Int.init) }),
|
|
101
|
+
let styles = args.count > 1 ? args[1] as? [String: Any] : [:] else {
|
|
102
|
+
callback(nil, "spring: invalid arguments")
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let options = args.count > 2 ? (args[2] as? [String: Any] ?? [:]) : [:]
|
|
107
|
+
let damping = CGFloat(options["damping"] as? Double ?? 0.7)
|
|
108
|
+
let duration = (options["duration"] as? Double ?? 500) / 1000.0
|
|
109
|
+
let delay = (options["delay"] as? Double ?? 0) / 1000.0
|
|
110
|
+
|
|
111
|
+
DispatchQueue.main.async {
|
|
112
|
+
MainActor.assumeIsolated {
|
|
113
|
+
guard let view = NativeBridge.shared.view(forId: viewId) else {
|
|
114
|
+
callback(nil, "spring: view \(viewId) not found")
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
UIView.animate(
|
|
119
|
+
withDuration: duration,
|
|
120
|
+
delay: delay,
|
|
121
|
+
usingSpringWithDamping: damping,
|
|
122
|
+
initialSpringVelocity: 0,
|
|
123
|
+
options: [],
|
|
124
|
+
animations: { [styles] in
|
|
125
|
+
MainActor.assumeIsolated {
|
|
126
|
+
for (key, value) in styles {
|
|
127
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
completion: { _ in
|
|
132
|
+
callback(true, nil)
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// MARK: - keyframe(viewId, keyframes, options)
|
|
140
|
+
|
|
141
|
+
private func animateKeyframes(viewId: Int, keyframes: [[String: Any]], duration: TimeInterval, callback: @escaping (Any?, String?) -> Void) {
|
|
142
|
+
DispatchQueue.main.async {
|
|
143
|
+
guard let view = NativeBridge.shared.view(forId: viewId) else {
|
|
144
|
+
callback(nil, "View not found for id \(viewId)"); return
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Build CAKeyframeAnimation for each animated property
|
|
148
|
+
// Group them with CAAnimationGroup
|
|
149
|
+
let group = CAAnimationGroup()
|
|
150
|
+
group.duration = duration
|
|
151
|
+
group.fillMode = .forwards
|
|
152
|
+
group.isRemovedOnCompletion = false
|
|
153
|
+
|
|
154
|
+
var animations: [CAAnimation] = []
|
|
155
|
+
|
|
156
|
+
// Collect all property names from keyframes
|
|
157
|
+
var propertyKeys = Set<String>()
|
|
158
|
+
for kf in keyframes { propertyKeys.formUnion(kf.keys.filter { $0 != "offset" }) }
|
|
159
|
+
|
|
160
|
+
for propKey in propertyKeys {
|
|
161
|
+
let keyPath: String
|
|
162
|
+
var values: [Any] = []
|
|
163
|
+
var keyTimes: [NSNumber] = []
|
|
164
|
+
|
|
165
|
+
switch propKey {
|
|
166
|
+
case "opacity":
|
|
167
|
+
keyPath = "opacity"
|
|
168
|
+
for kf in keyframes {
|
|
169
|
+
if let v = kf[propKey] as? Double {
|
|
170
|
+
values.append(v)
|
|
171
|
+
keyTimes.append(NSNumber(value: kf["offset"] as? Double ?? 0))
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
case "translateX":
|
|
175
|
+
keyPath = "transform.translation.x"
|
|
176
|
+
for kf in keyframes {
|
|
177
|
+
if let v = kf[propKey] as? Double {
|
|
178
|
+
values.append(v)
|
|
179
|
+
keyTimes.append(NSNumber(value: kf["offset"] as? Double ?? 0))
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
case "translateY":
|
|
183
|
+
keyPath = "transform.translation.y"
|
|
184
|
+
for kf in keyframes {
|
|
185
|
+
if let v = kf[propKey] as? Double {
|
|
186
|
+
values.append(v)
|
|
187
|
+
keyTimes.append(NSNumber(value: kf["offset"] as? Double ?? 0))
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
case "scale", "scaleX":
|
|
191
|
+
keyPath = "transform.scale.x"
|
|
192
|
+
for kf in keyframes {
|
|
193
|
+
if let v = kf[propKey] as? Double {
|
|
194
|
+
values.append(v)
|
|
195
|
+
keyTimes.append(NSNumber(value: kf["offset"] as? Double ?? 0))
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
case "scaleY":
|
|
199
|
+
keyPath = "transform.scale.y"
|
|
200
|
+
for kf in keyframes {
|
|
201
|
+
if let v = kf[propKey] as? Double {
|
|
202
|
+
values.append(v)
|
|
203
|
+
keyTimes.append(NSNumber(value: kf["offset"] as? Double ?? 0))
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
default:
|
|
207
|
+
continue
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if !values.isEmpty {
|
|
211
|
+
let anim = CAKeyframeAnimation(keyPath: keyPath)
|
|
212
|
+
anim.values = values
|
|
213
|
+
anim.keyTimes = keyTimes
|
|
214
|
+
anim.duration = duration
|
|
215
|
+
animations.append(anim)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if animations.isEmpty { callback(nil, nil); return }
|
|
220
|
+
group.animations = animations
|
|
221
|
+
|
|
222
|
+
CATransaction.begin()
|
|
223
|
+
CATransaction.setCompletionBlock { callback(nil, nil) }
|
|
224
|
+
view.layer.add(group, forKey: "keyframeAnimation")
|
|
225
|
+
CATransaction.commit()
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// MARK: - sequence([animData])
|
|
230
|
+
|
|
231
|
+
private func runSequence(animationsData: [[String: Any]], index: Int, callback: @escaping (Any?, String?) -> Void) {
|
|
232
|
+
guard index < animationsData.count else { callback(nil, nil); return }
|
|
233
|
+
let animData = animationsData[index]
|
|
234
|
+
let method = animData["type"] as? String ?? "timing"
|
|
235
|
+
let viewId = animData["viewId"] as? Int ?? 0
|
|
236
|
+
let toStyles = animData["toStyles"] as? [String: Any] ?? [:]
|
|
237
|
+
let options = animData["options"] as? [String: Any] ?? [:]
|
|
238
|
+
|
|
239
|
+
runSingleAnimation(method: method, viewId: viewId, toStyles: toStyles, options: options) { [weak self] _, error in
|
|
240
|
+
if let error = error { callback(nil, error); return }
|
|
241
|
+
self?.runSequence(animationsData: animationsData, index: index + 1, callback: callback)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private func runSingleAnimation(method: String, viewId: Int, toStyles: [String: Any], options: [String: Any], callback: @escaping (Any?, String?) -> Void) {
|
|
246
|
+
switch method {
|
|
247
|
+
case "timing":
|
|
248
|
+
let argsArr: [Any] = [viewId, toStyles, options]
|
|
249
|
+
invoke(method: "timing", args: argsArr, callback: callback)
|
|
250
|
+
case "spring":
|
|
251
|
+
let argsArr: [Any] = [viewId, toStyles, options]
|
|
252
|
+
invoke(method: "spring", args: argsArr, callback: callback)
|
|
253
|
+
default:
|
|
254
|
+
callback(nil, "Unknown animation type: \(method)")
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// MARK: - parallel([animData])
|
|
259
|
+
|
|
260
|
+
private func runParallel(animationsData: [[String: Any]], callback: @escaping (Any?, String?) -> Void) {
|
|
261
|
+
guard !animationsData.isEmpty else { callback(nil, nil); return }
|
|
262
|
+
let total = animationsData.count
|
|
263
|
+
var completed = 0
|
|
264
|
+
let lock = NSLock()
|
|
265
|
+
|
|
266
|
+
for animData in animationsData {
|
|
267
|
+
let method = animData["type"] as? String ?? "timing"
|
|
268
|
+
let viewId = animData["viewId"] as? Int ?? 0
|
|
269
|
+
let toStyles = animData["toStyles"] as? [String: Any] ?? [:]
|
|
270
|
+
let options = animData["options"] as? [String: Any] ?? [:]
|
|
271
|
+
|
|
272
|
+
runSingleAnimation(method: method, viewId: viewId, toStyles: toStyles, options: options) { _, _ in
|
|
273
|
+
lock.lock()
|
|
274
|
+
completed += 1
|
|
275
|
+
let allDone = completed == total
|
|
276
|
+
lock.unlock()
|
|
277
|
+
if allDone { callback(nil, nil) }
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
#endif
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
final class AppStateModule: NSObject, NativeModule {
|
|
5
|
+
var moduleName: String { "AppState" }
|
|
6
|
+
private weak var bridge: NativeBridge?
|
|
7
|
+
private var observers: [NSObjectProtocol] = []
|
|
8
|
+
|
|
9
|
+
init(bridge: NativeBridge) {
|
|
10
|
+
self.bridge = bridge
|
|
11
|
+
super.init()
|
|
12
|
+
setupObservers()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private func setupObservers() {
|
|
16
|
+
observers.append(NotificationCenter.default.addObserver(
|
|
17
|
+
forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main
|
|
18
|
+
) { [weak self] _ in
|
|
19
|
+
self?.bridge?.dispatchGlobalEvent("appState:change", payload: ["state": "active"])
|
|
20
|
+
})
|
|
21
|
+
observers.append(NotificationCenter.default.addObserver(
|
|
22
|
+
forName: UIApplication.willResignActiveNotification, object: nil, queue: .main
|
|
23
|
+
) { [weak self] _ in
|
|
24
|
+
self?.bridge?.dispatchGlobalEvent("appState:change", payload: ["state": "inactive"])
|
|
25
|
+
})
|
|
26
|
+
observers.append(NotificationCenter.default.addObserver(
|
|
27
|
+
forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main
|
|
28
|
+
) { [weak self] _ in
|
|
29
|
+
self?.bridge?.dispatchGlobalEvent("appState:change", payload: ["state": "background"])
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
deinit {
|
|
34
|
+
observers.forEach { NotificationCenter.default.removeObserver($0) }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
38
|
+
switch method {
|
|
39
|
+
case "getState":
|
|
40
|
+
let bridge = bridge
|
|
41
|
+
DispatchQueue.main.async {
|
|
42
|
+
let state: String
|
|
43
|
+
switch UIApplication.shared.applicationState {
|
|
44
|
+
case .active: state = "active"
|
|
45
|
+
case .inactive: state = "inactive"
|
|
46
|
+
case .background: state = "background"
|
|
47
|
+
@unknown default: state = "unknown"
|
|
48
|
+
}
|
|
49
|
+
bridge?.dispatchGlobalEvent("appState:change", payload: ["state": state])
|
|
50
|
+
callback(state, nil)
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
callback(nil, "Unknown method: \(method)")
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func invokeSync(method: String, args: [Any]) -> Any? { nil }
|
|
58
|
+
}
|
|
59
|
+
#endif
|