@thelacanians/vue-native-cli 0.4.14 → 0.6.0
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 +789 -200
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +156 -5
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +33 -13
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +27 -6
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +9 -2
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +178 -1
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/EventThrottle.kt +57 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeneratedModuleRegistry.kt +28 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +3 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ComponentFactoryTest.kt +674 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ErrorOverlayViewTest.kt +183 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/EventThrottleTest.kt +203 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/HotReloadManagerTest.kt +162 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/JSPolyfillsTest.kt +153 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeBridgeTest.kt +6 -3
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeModuleTest.kt +475 -0
- package/native/android/gradle.properties +1 -0
- package/native/android/gradlew +1 -1
- package/native/ios/VueNativeCore/Package.swift +1 -1
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/EventThrottle.swift +80 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +244 -112
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +19 -2
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +9 -4
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +8 -3
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +43 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +116 -4
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +100 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeneratedModuleRegistry.swift +28 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +3 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/CertificatePinningTests.swift +190 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/ComponentFactoryTests.swift +585 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/EventThrottleTests.swift +161 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/HotReloadManagerTests.swift +88 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSPolyfillsTests.swift +319 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/NativeModuleTests.swift +400 -0
- package/native/macos/VueNativeMacOS/Package.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/ErrorOverlayView.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/EventThrottle.swift +58 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/HotReloadManager.swift +153 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSPolyfills.swift +696 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSRuntime.swift +347 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/NativeBridge.swift +877 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/VueNativeWindowController.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/ComponentRegistry.swift +209 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActionSheetFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActivityIndicatorFactory.swift +85 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VAlertDialogFactory.swift +132 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VButtonFactory.swift +83 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VCheckboxFactory.swift +108 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VDropdownFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VImageFactory.swift +270 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VInputFactory.swift +257 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VKeyboardAvoidingFactory.swift +22 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VListFactory.swift +324 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VModalFactory.swift +231 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VOutlineViewFactory.swift +276 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPickerFactory.swift +134 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPressableFactory.swift +120 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VProgressBarFactory.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRadioFactory.swift +193 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRefreshControlFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSafeAreaFactory.swift +46 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VScrollViewFactory.swift +190 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSectionListFactory.swift +374 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSegmentedControlFactory.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSliderFactory.swift +131 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSplitViewFactory.swift +215 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VStatusBarFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSwitchFactory.swift +92 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VTextFactory.swift +336 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VToolbarFactory.swift +212 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VVideoFactory.swift +245 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VViewFactory.swift +314 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VWebViewFactory.swift +162 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/NativeComponentFactory.swift +54 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/ClickableView.swift +100 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/Extensions.swift +23 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/GestureWrapper.swift +183 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/NSColor+Hex.swift +78 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/FlippedView.swift +19 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/LayoutNode.swift +493 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AnimationModule.swift +354 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AppStateModule.swift +62 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/BiometryModule.swift +60 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/CameraModule.swift +167 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ClipboardModule.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DeviceInfoModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DragDropModule.swift +50 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/FileDialogModule.swift +86 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/HapticsModule.swift +42 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/KeyboardModule.swift +28 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/LinkingModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/MenuModule.swift +95 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NativeModuleRegistry.swift +63 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NotificationsModule.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/PermissionsModule.swift +149 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ShareModule.swift +37 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/WindowModule.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Resources/vue-native-placeholder.js +2 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Styling/StyleEngine.swift +885 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/ComponentFactoryTests.swift +80 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/VueNativeMacOSTests.swift +149 -0
- package/native/shared/VueNativeShared/AGENTS.md +129 -0
- package/native/shared/VueNativeShared/Package.swift +14 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/CertificatePinning.swift +134 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/EventThrottle.swift +78 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/HotReloadManager.swift +162 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/JSRuntime.swift +412 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AsyncStorageModule.swift +68 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AudioModule.swift +359 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/DatabaseModule.swift +259 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/FileSystemModule.swift +233 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/GeolocationModule.swift +156 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/NetworkModule.swift +59 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/PerformanceModule.swift +113 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/SecureStorageModule.swift +119 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/WebSocketModule.swift +212 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeEventDispatcher.swift +6 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModule.swift +26 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModuleRegistry.swift +37 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/SharedJSPolyfills.swift +673 -0
- package/native/shared/VueNativeShared/Tests/VueNativeSharedTests/VueNativeSharedTests.swift +44 -0
- package/package.json +8 -2
package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt
CHANGED
|
@@ -6,6 +6,7 @@ import android.os.Looper
|
|
|
6
6
|
import android.util.Log
|
|
7
7
|
import android.view.View
|
|
8
8
|
import android.view.ViewGroup
|
|
9
|
+
import android.widget.FrameLayout
|
|
9
10
|
import org.json.JSONArray
|
|
10
11
|
import org.json.JSONObject
|
|
11
12
|
|
|
@@ -23,6 +24,20 @@ class NativeBridge(private val context: Context) {
|
|
|
23
24
|
"create", "createText", "appendChild", "insertBefore", "removeChild",
|
|
24
25
|
"setRootView", "setText", "setElementText"
|
|
25
26
|
)
|
|
27
|
+
|
|
28
|
+
/** Style properties that affect layout and require a layout pass when changed. */
|
|
29
|
+
private val layoutAffectingStyles = setOf(
|
|
30
|
+
"width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight",
|
|
31
|
+
"flex", "flexGrow", "flexShrink", "flexBasis", "flexDirection",
|
|
32
|
+
"flexWrap", "alignItems", "alignSelf", "alignContent", "justifyContent",
|
|
33
|
+
"padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft",
|
|
34
|
+
"paddingHorizontal", "paddingVertical", "paddingStart", "paddingEnd",
|
|
35
|
+
"margin", "marginTop", "marginRight", "marginBottom", "marginLeft",
|
|
36
|
+
"marginHorizontal", "marginVertical", "marginStart", "marginEnd",
|
|
37
|
+
"gap", "rowGap", "columnGap",
|
|
38
|
+
"position", "top", "right", "bottom", "left", "start", "end",
|
|
39
|
+
"aspectRatio", "display", "overflow", "direction",
|
|
40
|
+
)
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
private val mainHandler = Handler(Looper.getMainLooper())
|
|
@@ -53,6 +68,26 @@ class NativeBridge(private val context: Context) {
|
|
|
53
68
|
/** The container view from the host Activity — where the root view is attached. */
|
|
54
69
|
var hostContainer: ViewGroup? = null
|
|
55
70
|
|
|
71
|
+
// -- Teleport support --
|
|
72
|
+
/** Maps teleport marker IDs for cleanup */
|
|
73
|
+
private val teleportMarkers = mutableMapOf<Int, Pair<Int, Int>>()
|
|
74
|
+
|
|
75
|
+
/** Maps parent node IDs to their teleport containers */
|
|
76
|
+
private val teleportContainers = mutableMapOf<Int, ViewGroup>()
|
|
77
|
+
|
|
78
|
+
/** Modal container for teleporting modals */
|
|
79
|
+
private val modalContainer: FrameLayout by lazy {
|
|
80
|
+
FrameLayout(context).apply {
|
|
81
|
+
layoutParams = FrameLayout.LayoutParams(
|
|
82
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
83
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
84
|
+
)
|
|
85
|
+
setBackgroundColor(android.graphics.Color.TRANSPARENT)
|
|
86
|
+
isClickable = true
|
|
87
|
+
isFocusable = false
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
56
91
|
/** Called when native fires an event to JS (nodeId, eventName, payloadJson). */
|
|
57
92
|
var onFireEvent: ((nodeId: Int, eventName: String, payloadJson: String) -> Unit)? = null
|
|
58
93
|
|
|
@@ -81,20 +116,34 @@ class NativeBridge(private val context: Context) {
|
|
|
81
116
|
}
|
|
82
117
|
|
|
83
118
|
mainHandler.post {
|
|
84
|
-
var
|
|
119
|
+
var needsLayout = false
|
|
85
120
|
for (op in ops) {
|
|
86
121
|
try {
|
|
87
122
|
val opName = op.optString("op")
|
|
88
|
-
if (!
|
|
89
|
-
|
|
123
|
+
if (!needsLayout && opName in treeMutationOps) {
|
|
124
|
+
needsLayout = true
|
|
125
|
+
}
|
|
126
|
+
// Check if updateStyle changes any layout-affecting property
|
|
127
|
+
if (!needsLayout && opName == "updateStyle") {
|
|
128
|
+
val args = op.optJSONArray("args")
|
|
129
|
+
val styleObj = args?.optJSONObject(1)
|
|
130
|
+
if (styleObj != null) {
|
|
131
|
+
val keys = styleObj.keys()
|
|
132
|
+
while (keys.hasNext()) {
|
|
133
|
+
if (keys.next() in layoutAffectingStyles) {
|
|
134
|
+
needsLayout = true
|
|
135
|
+
break
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
90
139
|
}
|
|
91
140
|
handleOperation(op)
|
|
92
141
|
} catch (e: Exception) {
|
|
93
142
|
Log.e(TAG, "Error handling op '${op.optString("op")}': ${e.message}")
|
|
94
143
|
}
|
|
95
144
|
}
|
|
96
|
-
//
|
|
97
|
-
if (
|
|
145
|
+
// Trigger layout when tree was mutated or layout-affecting styles changed
|
|
146
|
+
if (needsLayout) {
|
|
98
147
|
triggerLayout()
|
|
99
148
|
}
|
|
100
149
|
}
|
|
@@ -115,6 +164,9 @@ class NativeBridge(private val context: Context) {
|
|
|
115
164
|
"insertBefore" -> handleInsertBefore(args)
|
|
116
165
|
"removeChild" -> handleRemoveChild(args)
|
|
117
166
|
"setRootView" -> handleSetRootView(args)
|
|
167
|
+
"createTeleport" -> handleCreateTeleport(args)
|
|
168
|
+
"removeTeleport" -> handleRemoveTeleport(args)
|
|
169
|
+
"teleportTo" -> handleTeleportTo(args)
|
|
118
170
|
"addEventListener" -> handleAddEventListener(args)
|
|
119
171
|
"removeEventListener" -> handleRemoveEventListener(args)
|
|
120
172
|
"invokeNativeModule" -> handleInvokeNativeModule(args)
|
|
@@ -283,6 +335,100 @@ class NativeBridge(private val context: Context) {
|
|
|
283
335
|
ViewGroup.LayoutParams.MATCH_PARENT
|
|
284
336
|
)
|
|
285
337
|
)
|
|
338
|
+
|
|
339
|
+
// Add modal container for teleport
|
|
340
|
+
container.addView(
|
|
341
|
+
modalContainer,
|
|
342
|
+
ViewGroup.LayoutParams(
|
|
343
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
344
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// -- Teleport handlers --
|
|
350
|
+
|
|
351
|
+
private fun handleCreateTeleport(args: JSONArray) {
|
|
352
|
+
val parentId = args.getInt(0)
|
|
353
|
+
val startId = args.getInt(1)
|
|
354
|
+
val endId = args.getInt(2)
|
|
355
|
+
|
|
356
|
+
val parentView = nodeViews[parentId] ?: run {
|
|
357
|
+
Log.w(TAG, "Parent view not found for teleport (id: $parentId)")
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Store teleport marker IDs
|
|
362
|
+
teleportMarkers[parentId] = Pair(startId, endId)
|
|
363
|
+
|
|
364
|
+
// Create container for teleported content
|
|
365
|
+
val container = FrameLayout(context).apply {
|
|
366
|
+
id = View.generateViewId()
|
|
367
|
+
setBackgroundColor(android.graphics.Color.TRANSPARENT)
|
|
368
|
+
isClickable = true
|
|
369
|
+
isFocusable = false
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (parentView is ViewGroup) {
|
|
373
|
+
parentView.addView(container)
|
|
374
|
+
teleportContainers[parentId] = container
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
Log.d(TAG, "Created teleport container for parent $parentId")
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private fun handleRemoveTeleport(args: JSONArray) {
|
|
381
|
+
val parentId = args.getInt(0)
|
|
382
|
+
|
|
383
|
+
// Remove teleport container
|
|
384
|
+
teleportContainers.remove(parentId)?.let { container ->
|
|
385
|
+
mainHandler.post {
|
|
386
|
+
(container.parent as? ViewGroup)?.removeView(container)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Clean up markers
|
|
391
|
+
teleportMarkers.remove(parentId)
|
|
392
|
+
|
|
393
|
+
Log.d(TAG, "Removed teleport container for parent $parentId")
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private fun handleTeleportTo(args: JSONArray) {
|
|
397
|
+
val target = args.getString(0)
|
|
398
|
+
val nodeId = args.getInt(1)
|
|
399
|
+
|
|
400
|
+
val targetView = getTeleportTarget(target) ?: run {
|
|
401
|
+
Log.w(TAG, "Teleport target '$target' not found")
|
|
402
|
+
return
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
val childView = nodeViews[nodeId] ?: run {
|
|
406
|
+
Log.w(TAG, "Node view not found for teleport (id: $nodeId)")
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Move view to teleport target
|
|
411
|
+
mainHandler.post {
|
|
412
|
+
(childView.parent as? ViewGroup)?.removeView(childView)
|
|
413
|
+
targetView.addView(childView)
|
|
414
|
+
childView.requestLayout()
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
Log.d(TAG, "Teleported node $nodeId to target '$target'")
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private fun getTeleportTarget(target: String): ViewGroup? {
|
|
421
|
+
return when (target) {
|
|
422
|
+
"root" -> rootView as? ViewGroup
|
|
423
|
+
"modal" -> {
|
|
424
|
+
// Ensure modal container is added to root if not already
|
|
425
|
+
if (modalContainer.parent == null && rootView != null) {
|
|
426
|
+
(rootView as? ViewGroup)?.addView(modalContainer)
|
|
427
|
+
}
|
|
428
|
+
modalContainer
|
|
429
|
+
}
|
|
430
|
+
else -> null
|
|
431
|
+
}
|
|
286
432
|
}
|
|
287
433
|
|
|
288
434
|
private fun handleAddEventListener(args: JSONArray) {
|
|
@@ -380,6 +526,11 @@ class NativeBridge(private val context: Context) {
|
|
|
380
526
|
|
|
381
527
|
/** Clear all registries. Called during hot reload after JS teardown. Must run on main thread. */
|
|
382
528
|
fun clearAllRegistries() {
|
|
529
|
+
// Destroy all views via their factories before clearing maps
|
|
530
|
+
for ((_, view) in nodeViews) {
|
|
531
|
+
val factory = componentRegistry.factoryForView(view)
|
|
532
|
+
factory?.destroyView(view)
|
|
533
|
+
}
|
|
383
534
|
nodeViews.clear()
|
|
384
535
|
nodeTypes.clear()
|
|
385
536
|
eventHandlers.clear()
|
|
@@ -98,9 +98,16 @@ class VListFactory : NativeComponentFactory {
|
|
|
98
98
|
cumulativeX += dx
|
|
99
99
|
cumulativeY += dy
|
|
100
100
|
|
|
101
|
-
// Dispatch scroll event with cumulative position
|
|
101
|
+
// Dispatch scroll event with cumulative position and dimensions
|
|
102
102
|
scrollHandlers[recyclerView]?.invoke(
|
|
103
|
-
mapOf(
|
|
103
|
+
mapOf(
|
|
104
|
+
"x" to cumulativeX,
|
|
105
|
+
"y" to cumulativeY,
|
|
106
|
+
"contentWidth" to (recyclerView.computeHorizontalScrollRange()),
|
|
107
|
+
"contentHeight" to (recyclerView.computeVerticalScrollRange()),
|
|
108
|
+
"layoutWidth" to recyclerView.width,
|
|
109
|
+
"layoutHeight" to recyclerView.height,
|
|
110
|
+
)
|
|
104
111
|
)
|
|
105
112
|
|
|
106
113
|
// endReached detection (threshold = 20% from bottom)
|
|
@@ -167,20 +174,33 @@ class VListFactory : NativeComponentFactory {
|
|
|
167
174
|
}
|
|
168
175
|
|
|
169
176
|
class VListAdapter(private val items: List<View>) : RecyclerView.Adapter<VListAdapter.VH>() {
|
|
170
|
-
class VH(
|
|
177
|
+
class VH(itemView: View) : RecyclerView.ViewHolder(itemView)
|
|
171
178
|
|
|
172
179
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
|
|
173
|
-
val
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
)
|
|
180
|
-
|
|
180
|
+
val container = android.widget.FrameLayout(parent.context).apply {
|
|
181
|
+
layoutParams = RecyclerView.LayoutParams(
|
|
182
|
+
RecyclerView.LayoutParams.MATCH_PARENT,
|
|
183
|
+
RecyclerView.LayoutParams.WRAP_CONTENT
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
return VH(container)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
override fun onBindViewHolder(holder: VH, position: Int) {
|
|
190
|
+
val container = holder.itemView as android.widget.FrameLayout
|
|
191
|
+
// Remove the previous item view from this recycled container
|
|
192
|
+
container.removeAllViews()
|
|
193
|
+
val itemView = items.getOrNull(position) ?: return
|
|
194
|
+
// Remove from any existing parent (previous container or direct parent)
|
|
195
|
+
(itemView.parent as? ViewGroup)?.removeView(itemView)
|
|
196
|
+
container.addView(itemView, ViewGroup.LayoutParams(
|
|
197
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
198
|
+
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
199
|
+
))
|
|
181
200
|
}
|
|
182
201
|
|
|
183
|
-
override fun onBindViewHolder(holder: VH, position: Int) {}
|
|
184
202
|
override fun getItemCount(): Int = items.size
|
|
185
|
-
|
|
203
|
+
|
|
204
|
+
// Use a single view type so RecyclerView can reuse all ViewHolders
|
|
205
|
+
override fun getItemViewType(position: Int): Int = 0
|
|
186
206
|
}
|
|
@@ -64,6 +64,9 @@ class VScrollViewFactory : NativeComponentFactory {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
private val scrollThrottles = mutableMapOf<SwipeRefreshLayout, EventThrottle>()
|
|
68
|
+
private val scrollListeners = mutableMapOf<SwipeRefreshLayout, android.view.ViewTreeObserver.OnScrollChangedListener>()
|
|
69
|
+
|
|
67
70
|
override fun addEventListener(view: View, event: String, handler: (Any?) -> Unit) {
|
|
68
71
|
val srf = view as? SwipeRefreshLayout ?: return
|
|
69
72
|
val scroll = states[srf]?.scrollView
|
|
@@ -73,20 +76,38 @@ class VScrollViewFactory : NativeComponentFactory {
|
|
|
73
76
|
srf.setOnRefreshListener { handler(null) }
|
|
74
77
|
}
|
|
75
78
|
"scroll" -> {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
val throttle = EventThrottle(intervalMs = 16L, handler = handler)
|
|
80
|
+
scrollThrottles[srf] = throttle
|
|
81
|
+
val listener = android.view.ViewTreeObserver.OnScrollChangedListener {
|
|
82
|
+
val child = if (scroll != null && scroll.childCount > 0) scroll.getChildAt(0) else null
|
|
83
|
+
throttle.fire(mapOf(
|
|
84
|
+
"x" to (scroll?.scrollX ?: 0),
|
|
85
|
+
"y" to (scroll?.scrollY ?: 0),
|
|
86
|
+
"contentWidth" to (child?.width ?: scroll?.width ?: 0),
|
|
87
|
+
"contentHeight" to (child?.height ?: scroll?.height ?: 0),
|
|
88
|
+
"layoutWidth" to (scroll?.width ?: 0),
|
|
89
|
+
"layoutHeight" to (scroll?.height ?: 0),
|
|
79
90
|
))
|
|
80
91
|
}
|
|
92
|
+
scrollListeners[srf] = listener
|
|
93
|
+
scroll?.viewTreeObserver?.addOnScrollChangedListener(listener)
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
}
|
|
84
97
|
|
|
85
98
|
override fun removeEventListener(view: View, event: String) {
|
|
86
99
|
val srf = view as? SwipeRefreshLayout ?: return
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
100
|
+
when (event) {
|
|
101
|
+
"refresh" -> {
|
|
102
|
+
srf.setOnRefreshListener(null)
|
|
103
|
+
srf.isEnabled = false
|
|
104
|
+
}
|
|
105
|
+
"scroll" -> {
|
|
106
|
+
scrollListeners.remove(srf)?.let { listener ->
|
|
107
|
+
states[srf]?.scrollView?.viewTreeObserver?.removeOnScrollChangedListener(listener)
|
|
108
|
+
}
|
|
109
|
+
scrollThrottles.remove(srf)?.cancel()
|
|
110
|
+
}
|
|
90
111
|
}
|
|
91
112
|
}
|
|
92
113
|
|
|
@@ -48,18 +48,24 @@ class VSliderFactory : NativeComponentFactory {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
private val throttles = mutableMapOf<SeekBar, EventThrottle>()
|
|
52
|
+
|
|
51
53
|
override fun addEventListener(view: View, event: String, handler: (Any?) -> Unit) {
|
|
52
54
|
val sb = view as? SeekBar ?: return
|
|
53
55
|
when (event) {
|
|
54
56
|
"change", "valueChange" -> {
|
|
55
57
|
changeHandlers[sb] = handler
|
|
58
|
+
val throttle = EventThrottle(intervalMs = 16L, handler = handler)
|
|
59
|
+
throttles[sb] = throttle
|
|
56
60
|
sb.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
|
57
61
|
override fun onProgressChanged(s: SeekBar, progress: Int, fromUser: Boolean) {
|
|
58
|
-
if (fromUser)
|
|
62
|
+
if (fromUser) throttle.fire(mapOf("value" to progress.toFloat() / s.max.toFloat()))
|
|
59
63
|
}
|
|
60
64
|
override fun onStartTrackingTouch(s: SeekBar) {}
|
|
61
65
|
override fun onStopTrackingTouch(s: SeekBar) {
|
|
62
|
-
|
|
66
|
+
// Always deliver the final value immediately on release
|
|
67
|
+
throttle.cancel()
|
|
68
|
+
changeHandlers[s]?.invoke(mapOf("value" to s.progress.toFloat() / s.max.toFloat()))
|
|
63
69
|
}
|
|
64
70
|
})
|
|
65
71
|
}
|
|
@@ -69,6 +75,7 @@ class VSliderFactory : NativeComponentFactory {
|
|
|
69
75
|
override fun removeEventListener(view: View, event: String) {
|
|
70
76
|
val sb = view as? SeekBar ?: return
|
|
71
77
|
changeHandlers.remove(sb)
|
|
78
|
+
throttles.remove(sb)?.cancel()
|
|
72
79
|
sb.setOnSeekBarChangeListener(null)
|
|
73
80
|
}
|
|
74
81
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
package com.vuenative.core
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.view.GestureDetector
|
|
5
|
+
import android.view.MotionEvent
|
|
6
|
+
import android.view.ScaleGestureDetector
|
|
4
7
|
import android.view.View
|
|
5
8
|
import android.view.ViewGroup
|
|
6
9
|
import com.google.android.flexbox.FlexDirection
|
|
7
10
|
import com.google.android.flexbox.FlexboxLayout
|
|
11
|
+
import kotlin.math.abs
|
|
12
|
+
import kotlin.math.atan2
|
|
13
|
+
import kotlin.math.sqrt
|
|
8
14
|
|
|
9
15
|
class VViewFactory : NativeComponentFactory {
|
|
10
16
|
override fun createView(context: Context): View {
|
|
@@ -28,6 +34,125 @@ class VViewFactory : NativeComponentFactory {
|
|
|
28
34
|
handler(null)
|
|
29
35
|
true
|
|
30
36
|
}
|
|
37
|
+
"pan", "swipeLeft", "swipeRight", "swipeUp", "swipeDown", "pinch", "rotate" -> {
|
|
38
|
+
setupGestureListener(view, event, handler)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private fun setupGestureListener(view: View, event: String, handler: (Any?) -> Unit) {
|
|
44
|
+
val context = view.context
|
|
45
|
+
|
|
46
|
+
when (event) {
|
|
47
|
+
"pan" -> {
|
|
48
|
+
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
|
49
|
+
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
|
|
50
|
+
val payload = mapOf(
|
|
51
|
+
"translationX" to -distanceX,
|
|
52
|
+
"translationY" to -distanceY,
|
|
53
|
+
"velocityX" to 0f,
|
|
54
|
+
"velocityY" to 0f,
|
|
55
|
+
"state" to "changed"
|
|
56
|
+
)
|
|
57
|
+
handler(payload)
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
view.setOnTouchListener { _, motionEvent ->
|
|
62
|
+
gestureDetector.onTouchEvent(motionEvent)
|
|
63
|
+
false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
"swipeLeft" -> {
|
|
67
|
+
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
|
68
|
+
override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
|
|
69
|
+
if (abs(velocityX) > abs(velocityY) && velocityX < 0) {
|
|
70
|
+
val payload = mapOf("direction" to "left")
|
|
71
|
+
handler(payload)
|
|
72
|
+
}
|
|
73
|
+
return true
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
view.setOnTouchListener { _, motionEvent ->
|
|
77
|
+
gestureDetector.onTouchEvent(motionEvent)
|
|
78
|
+
false
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
"swipeRight" -> {
|
|
82
|
+
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
|
83
|
+
override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
|
|
84
|
+
if (abs(velocityX) > abs(velocityY) && velocityX > 0) {
|
|
85
|
+
val payload = mapOf("direction" to "right")
|
|
86
|
+
handler(payload)
|
|
87
|
+
}
|
|
88
|
+
return true
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
view.setOnTouchListener { _, motionEvent ->
|
|
92
|
+
gestureDetector.onTouchEvent(motionEvent)
|
|
93
|
+
false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
"swipeUp" -> {
|
|
97
|
+
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
|
98
|
+
override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
|
|
99
|
+
if (abs(velocityY) > abs(velocityX) && velocityY < 0) {
|
|
100
|
+
val payload = mapOf("direction" to "up")
|
|
101
|
+
handler(payload)
|
|
102
|
+
}
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
view.setOnTouchListener { _, motionEvent ->
|
|
107
|
+
gestureDetector.onTouchEvent(motionEvent)
|
|
108
|
+
false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
"swipeDown" -> {
|
|
112
|
+
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
|
113
|
+
override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
|
|
114
|
+
if (abs(velocityY) > abs(velocityX) && velocityY > 0) {
|
|
115
|
+
val payload = mapOf("direction" to "down")
|
|
116
|
+
handler(payload)
|
|
117
|
+
}
|
|
118
|
+
return true
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
view.setOnTouchListener { _, motionEvent ->
|
|
122
|
+
gestureDetector.onTouchEvent(motionEvent)
|
|
123
|
+
false
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
"pinch" -> {
|
|
127
|
+
val scaleGestureDetector = ScaleGestureDetector(context, object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
|
128
|
+
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
|
129
|
+
val payload = mapOf(
|
|
130
|
+
"scale" to detector.scaleFactor,
|
|
131
|
+
"velocity" to detector.currentSpan,
|
|
132
|
+
"state" to "changed"
|
|
133
|
+
)
|
|
134
|
+
handler(payload)
|
|
135
|
+
return true
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
view.setOnTouchListener { _, motionEvent ->
|
|
139
|
+
scaleGestureDetector.onTouchEvent(motionEvent)
|
|
140
|
+
false
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
"rotate" -> {
|
|
144
|
+
val rotationDetector = RotationGestureDetector { rotation ->
|
|
145
|
+
val payload = mapOf(
|
|
146
|
+
"rotation" to rotation,
|
|
147
|
+
"state" to "changed"
|
|
148
|
+
)
|
|
149
|
+
handler(payload)
|
|
150
|
+
}
|
|
151
|
+
view.setOnTouchListener { _, motionEvent ->
|
|
152
|
+
rotationDetector.onTouchEvent(motionEvent)
|
|
153
|
+
false
|
|
154
|
+
}
|
|
155
|
+
}
|
|
31
156
|
}
|
|
32
157
|
}
|
|
33
158
|
|
|
@@ -35,6 +160,7 @@ class VViewFactory : NativeComponentFactory {
|
|
|
35
160
|
when (event) {
|
|
36
161
|
"press" -> view.setOnClickListener(null)
|
|
37
162
|
"longPress" -> view.setOnLongClickListener(null)
|
|
163
|
+
else -> view.setOnTouchListener(null)
|
|
38
164
|
}
|
|
39
165
|
}
|
|
40
166
|
|
|
@@ -51,4 +177,55 @@ class VViewFactory : NativeComponentFactory {
|
|
|
51
177
|
override fun removeChild(parent: View, child: View) {
|
|
52
178
|
(parent as? ViewGroup)?.removeView(child)
|
|
53
179
|
}
|
|
54
|
-
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* RotationGestureDetector detectsstwo-finger rotation gestures.
|
|
183
|
+
* Calculates rotation angle between two touch points.
|
|
184
|
+
*/
|
|
185
|
+
private class RotationGestureDetector(
|
|
186
|
+
private val onRotation: (Float) -> Unit
|
|
187
|
+
) {
|
|
188
|
+
private var previousAngle: Float = 0f
|
|
189
|
+
private var isTracking = false
|
|
190
|
+
|
|
191
|
+
fun onTouchEvent(event: MotionEvent): Boolean {
|
|
192
|
+
when (event.actionMasked) {
|
|
193
|
+
MotionEvent.ACTION_POINTER_DOWN -> {
|
|
194
|
+
if (event.pointerCount == 2) {
|
|
195
|
+
previousAngle = calculateAngle(event)
|
|
196
|
+
isTracking = true
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
MotionEvent.ACTION_MOVE -> {
|
|
200
|
+
if (isTracking && event.pointerCount == 2) {
|
|
201
|
+
val currentAngle = calculateAngle(event)
|
|
202
|
+
val deltaAngle = currentAngle - previousAngle
|
|
203
|
+
|
|
204
|
+
// Normalize angle to -PI to PI range
|
|
205
|
+
val normalizedDelta = when {
|
|
206
|
+
deltaAngle > Math.PI -> deltaAngle - (2 * Math.PI).toFloat()
|
|
207
|
+
deltaAngle < -Math.PI -> deltaAngle + (2 * Math.PI).toFloat()
|
|
208
|
+
else -> deltaAngle
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
onRotation(normalizedDelta)
|
|
212
|
+
previousAngle = currentAngle
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
|
216
|
+
isTracking = false
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return true
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private fun calculateAngle(event: MotionEvent): Float {
|
|
223
|
+
if (event.pointerCount < 2) return 0f
|
|
224
|
+
|
|
225
|
+
val dx = event.getX(1) - event.getX(0)
|
|
226
|
+
val dy = event.getY(1) - event.getY(0)
|
|
227
|
+
|
|
228
|
+
return atan2(dy, dx)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/EventThrottle.kt
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
package com.vuenative.core
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import android.os.SystemClock
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Throttles high-frequency event handlers to avoid flooding the JS bridge.
|
|
9
|
+
*
|
|
10
|
+
* When a high-frequency event (scroll, slider drag) fires many times per frame,
|
|
11
|
+
* each invocation becomes a bridge round-trip. This utility ensures at most one
|
|
12
|
+
* call per [intervalMs] milliseconds, with a trailing call to deliver the latest value.
|
|
13
|
+
*
|
|
14
|
+
* Default interval: 16ms (~60 FPS).
|
|
15
|
+
*/
|
|
16
|
+
class EventThrottle(
|
|
17
|
+
private val intervalMs: Long = 16L,
|
|
18
|
+
private val handler: (Any?) -> Unit
|
|
19
|
+
) {
|
|
20
|
+
private var lastFireTime: Long = 0
|
|
21
|
+
private var pendingTrailing = false
|
|
22
|
+
private var latestPayload: Any? = null
|
|
23
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
24
|
+
|
|
25
|
+
private val trailingRunnable = Runnable {
|
|
26
|
+
lastFireTime = SystemClock.uptimeMillis()
|
|
27
|
+
pendingTrailing = false
|
|
28
|
+
handler(latestPayload)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Call this from the native event callback instead of the original handler.
|
|
33
|
+
* Fires immediately if enough time has elapsed, otherwise schedules a trailing call.
|
|
34
|
+
*/
|
|
35
|
+
fun fire(payload: Any?) {
|
|
36
|
+
val now = SystemClock.uptimeMillis()
|
|
37
|
+
val elapsed = now - lastFireTime
|
|
38
|
+
latestPayload = payload
|
|
39
|
+
|
|
40
|
+
if (elapsed >= intervalMs) {
|
|
41
|
+
lastFireTime = now
|
|
42
|
+
pendingTrailing = false
|
|
43
|
+
mainHandler.removeCallbacks(trailingRunnable)
|
|
44
|
+
handler(payload)
|
|
45
|
+
} else if (!pendingTrailing) {
|
|
46
|
+
pendingTrailing = true
|
|
47
|
+
mainHandler.postDelayed(trailingRunnable, intervalMs - elapsed)
|
|
48
|
+
}
|
|
49
|
+
// If trailing is already pending, latestPayload is updated above
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Cancel any pending trailing call. */
|
|
53
|
+
fun cancel() {
|
|
54
|
+
mainHandler.removeCallbacks(trailingRunnable)
|
|
55
|
+
pendingTrailing = false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Auto-Generated Module Registration
|
|
3
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// ⚠️ WARNING: This file is auto-generated. DO NOT EDIT MANUALLY.
|
|
6
|
+
// Changes will be overwritten by the vue-native-codegen tool.
|
|
7
|
+
//
|
|
8
|
+
// Generated: {{GENERATED_DATE}}
|
|
9
|
+
//
|
|
10
|
+
// This file registers all native modules generated from <native> blocks
|
|
11
|
+
// in Vue SFC files.
|
|
12
|
+
//
|
|
13
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
package com.vuenative.core
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Register all generated native modules from <native> blocks
|
|
19
|
+
* This function is called automatically after registerDefaults()
|
|
20
|
+
*/
|
|
21
|
+
fun NativeModuleRegistry.registerGeneratedModules() {
|
|
22
|
+
// Generated modules will be registered here
|
|
23
|
+
// Example:
|
|
24
|
+
// register(HapticsModule())
|
|
25
|
+
// register(CameraModule())
|
|
26
|
+
|
|
27
|
+
// This function is called automatically after registerDefaults()
|
|
28
|
+
}
|
|
@@ -58,6 +58,9 @@ class NativeModuleRegistry private constructor(private val context: Context) {
|
|
|
58
58
|
register(m)
|
|
59
59
|
m.initialize(ctx, bridge)
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
// Register generated modules from <native> blocks
|
|
63
|
+
registerGeneratedModules()
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
fun getModule(name: String): NativeModule? = modules[name]
|