@onekeyfe/react-native-native-overlay 3.0.162-alpha.268
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/LICENSE +21 -0
- package/NativeOverlay.podspec +30 -0
- package/README.md +35 -0
- package/android/build.gradle +82 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayAnimation.kt +176 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayEntryRootView.kt +415 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayEvents.kt +38 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayHost.kt +174 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayPackage.kt +16 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayPageHostView.kt +122 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayPageHostViewManager.kt +40 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayView.kt +465 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayViewManager.kt +156 -0
- package/android/src/main/jni/CMakeLists.txt +44 -0
- package/android/src/main/jni/RNCNativeOverlay.h +19 -0
- package/common/cpp/react/renderer/components/RNCNativeOverlay/NativeOverlayComponentDescriptor.h +12 -0
- package/common/cpp/react/renderer/components/RNCNativeOverlay/NativeOverlayShadowNode.cpp +12 -0
- package/common/cpp/react/renderer/components/RNCNativeOverlay/NativeOverlayShadowNode.h +41 -0
- package/common/cpp/react/renderer/components/RNCNativeOverlay/NativeOverlayState.h +40 -0
- package/docs/SPEC.md +693 -0
- package/ios/NativeOverlayAnimation.swift +160 -0
- package/ios/NativeOverlayContainerView.swift +688 -0
- package/ios/NativeOverlayKeyboard.swift +88 -0
- package/ios/NativeOverlayPageHostView.swift +98 -0
- package/ios/NativeOverlaySheetController.swift +391 -0
- package/ios/NativeOverlayWindowManager.swift +194 -0
- package/ios/RCTNativeOverlayComponentView.h +11 -0
- package/ios/RCTNativeOverlayComponentView.mm +193 -0
- package/ios/RCTNativeOverlayPageHostComponentView.h +11 -0
- package/ios/RCTNativeOverlayPageHostComponentView.mm +64 -0
- package/lib/module/NativeOverlayNativeComponent.ts +61 -0
- package/lib/module/NativeOverlayPageHostNativeComponent.ts +13 -0
- package/lib/module/OverlayErrors.js +6 -0
- package/lib/module/OverlayErrors.js.map +1 -0
- package/lib/module/OverlayLevelContext.js +27 -0
- package/lib/module/OverlayLevelContext.js.map +1 -0
- package/lib/module/OverlayLevels.js +33 -0
- package/lib/module/OverlayLevels.js.map +1 -0
- package/lib/module/OverlayPageHost.js +24 -0
- package/lib/module/OverlayPageHost.js.map +1 -0
- package/lib/module/OverlayPageHost.web.js +49 -0
- package/lib/module/OverlayPageHost.web.js.map +1 -0
- package/lib/module/OverlayPageScope.js +41 -0
- package/lib/module/OverlayPageScope.js.map +1 -0
- package/lib/module/OverlayStore.js +305 -0
- package/lib/module/OverlayStore.js.map +1 -0
- package/lib/module/OverlayView.js +141 -0
- package/lib/module/OverlayView.js.map +1 -0
- package/lib/module/OverlayView.web.js +290 -0
- package/lib/module/OverlayView.web.js.map +1 -0
- package/lib/module/OverlayViewTypes.js +4 -0
- package/lib/module/OverlayViewTypes.js.map +1 -0
- package/lib/module/animation/motionPresets.js +57 -0
- package/lib/module/animation/motionPresets.js.map +1 -0
- package/lib/module/animation/platformMotionPresets.js +4 -0
- package/lib/module/animation/platformMotionPresets.js.map +1 -0
- package/lib/module/animation/platformMotionPresets.web.js +4 -0
- package/lib/module/animation/platformMotionPresets.web.js.map +1 -0
- package/lib/module/animation/resolveAnimation.js +80 -0
- package/lib/module/animation/resolveAnimation.js.map +1 -0
- package/lib/module/animation/spring.js +69 -0
- package/lib/module/animation/spring.js.map +1 -0
- package/lib/module/animation/types.js +2 -0
- package/lib/module/animation/types.js.map +1 -0
- package/lib/module/index.js +16 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/useOverlayController.js +127 -0
- package/lib/module/useOverlayController.js.map +1 -0
- package/lib/module/useSuspendedPageOwners.js +16 -0
- package/lib/module/useSuspendedPageOwners.js.map +1 -0
- package/lib/module/web/animateTransition.js +115 -0
- package/lib/module/web/animateTransition.js.map +1 -0
- package/lib/module/web/overlayLayers.js +147 -0
- package/lib/module/web/overlayLayers.js.map +1 -0
- package/lib/module/web/useKeyboardShift.js +110 -0
- package/lib/module/web/useKeyboardShift.js.map +1 -0
- package/lib/module/web/useSheetDrag.js +126 -0
- package/lib/module/web/useSheetDrag.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeOverlayNativeComponent.d.ts +41 -0
- package/lib/typescript/src/NativeOverlayNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/NativeOverlayPageHostNativeComponent.d.ts +9 -0
- package/lib/typescript/src/NativeOverlayPageHostNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/OverlayErrors.d.ts +4 -0
- package/lib/typescript/src/OverlayErrors.d.ts.map +1 -0
- package/lib/typescript/src/OverlayLevelContext.d.ts +12 -0
- package/lib/typescript/src/OverlayLevelContext.d.ts.map +1 -0
- package/lib/typescript/src/OverlayLevels.d.ts +13 -0
- package/lib/typescript/src/OverlayLevels.d.ts.map +1 -0
- package/lib/typescript/src/OverlayPageHost.d.ts +9 -0
- package/lib/typescript/src/OverlayPageHost.d.ts.map +1 -0
- package/lib/typescript/src/OverlayPageHost.web.d.ts +11 -0
- package/lib/typescript/src/OverlayPageHost.web.d.ts.map +1 -0
- package/lib/typescript/src/OverlayPageScope.d.ts +17 -0
- package/lib/typescript/src/OverlayPageScope.d.ts.map +1 -0
- package/lib/typescript/src/OverlayStore.d.ts +72 -0
- package/lib/typescript/src/OverlayStore.d.ts.map +1 -0
- package/lib/typescript/src/OverlayView.d.ts +3 -0
- package/lib/typescript/src/OverlayView.d.ts.map +1 -0
- package/lib/typescript/src/OverlayView.web.d.ts +3 -0
- package/lib/typescript/src/OverlayView.web.d.ts.map +1 -0
- package/lib/typescript/src/OverlayViewTypes.d.ts +68 -0
- package/lib/typescript/src/OverlayViewTypes.d.ts.map +1 -0
- package/lib/typescript/src/animation/motionPresets.d.ts +13 -0
- package/lib/typescript/src/animation/motionPresets.d.ts.map +1 -0
- package/lib/typescript/src/animation/platformMotionPresets.d.ts +2 -0
- package/lib/typescript/src/animation/platformMotionPresets.d.ts.map +1 -0
- package/lib/typescript/src/animation/platformMotionPresets.web.d.ts +2 -0
- package/lib/typescript/src/animation/platformMotionPresets.web.d.ts.map +1 -0
- package/lib/typescript/src/animation/resolveAnimation.d.ts +23 -0
- package/lib/typescript/src/animation/resolveAnimation.d.ts.map +1 -0
- package/lib/typescript/src/animation/spring.d.ts +24 -0
- package/lib/typescript/src/animation/spring.d.ts.map +1 -0
- package/lib/typescript/src/animation/types.d.ts +56 -0
- package/lib/typescript/src/animation/types.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +18 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +59 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/useOverlayController.d.ts +29 -0
- package/lib/typescript/src/useOverlayController.d.ts.map +1 -0
- package/lib/typescript/src/useSuspendedPageOwners.d.ts +7 -0
- package/lib/typescript/src/useSuspendedPageOwners.d.ts.map +1 -0
- package/lib/typescript/src/web/animateTransition.d.ts +18 -0
- package/lib/typescript/src/web/animateTransition.d.ts.map +1 -0
- package/lib/typescript/src/web/overlayLayers.d.ts +10 -0
- package/lib/typescript/src/web/overlayLayers.d.ts.map +1 -0
- package/lib/typescript/src/web/useKeyboardShift.d.ts +29 -0
- package/lib/typescript/src/web/useKeyboardShift.d.ts.map +1 -0
- package/lib/typescript/src/web/useSheetDrag.d.ts +13 -0
- package/lib/typescript/src/web/useSheetDrag.d.ts.map +1 -0
- package/package.json +188 -0
- package/react-native.config.js +16 -0
- package/src/NativeOverlayNativeComponent.ts +61 -0
- package/src/NativeOverlayPageHostNativeComponent.ts +13 -0
- package/src/OverlayErrors.ts +3 -0
- package/src/OverlayLevelContext.tsx +32 -0
- package/src/OverlayLevels.ts +40 -0
- package/src/OverlayPageHost.tsx +21 -0
- package/src/OverlayPageHost.web.tsx +53 -0
- package/src/OverlayPageScope.tsx +42 -0
- package/src/OverlayStore.ts +401 -0
- package/src/OverlayView.tsx +165 -0
- package/src/OverlayView.web.tsx +356 -0
- package/src/OverlayViewTypes.ts +81 -0
- package/src/animation/motionPresets.ts +52 -0
- package/src/animation/platformMotionPresets.ts +1 -0
- package/src/animation/platformMotionPresets.web.ts +1 -0
- package/src/animation/resolveAnimation.ts +103 -0
- package/src/animation/spring.ts +80 -0
- package/src/animation/types.ts +71 -0
- package/src/index.ts +55 -0
- package/src/types.ts +79 -0
- package/src/useOverlayController.ts +199 -0
- package/src/useSuspendedPageOwners.ts +26 -0
- package/src/web/animateTransition.ts +137 -0
- package/src/web/overlayLayers.ts +182 -0
- package/src/web/useKeyboardShift.ts +130 -0
- package/src/web/useSheetDrag.ts +143 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
package com.onekey.nativeoverlay
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.graphics.Rect
|
|
5
|
+
import android.graphics.drawable.GradientDrawable
|
|
6
|
+
import android.view.Gravity
|
|
7
|
+
import android.view.MotionEvent
|
|
8
|
+
import android.view.View
|
|
9
|
+
import android.view.ViewGroup
|
|
10
|
+
import android.widget.FrameLayout
|
|
11
|
+
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
12
|
+
import androidx.core.view.ViewCompat
|
|
13
|
+
import androidx.core.view.WindowInsetsAnimationCompat
|
|
14
|
+
import androidx.core.view.WindowInsetsCompat
|
|
15
|
+
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
16
|
+
import com.facebook.react.common.annotations.UnstableReactNativeAPI
|
|
17
|
+
import com.facebook.react.config.ReactFeatureFlags
|
|
18
|
+
import com.facebook.react.uimanager.JSPointerDispatcher
|
|
19
|
+
import com.facebook.react.uimanager.JSTouchDispatcher
|
|
20
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
21
|
+
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
22
|
+
import com.facebook.react.uimanager.RootView
|
|
23
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
24
|
+
import com.facebook.react.uimanager.TouchTargetHelper
|
|
25
|
+
import com.facebook.react.uimanager.events.EventDispatcher
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Keeps Fabric-assigned frames: the React root inside is laid out by Yoga
|
|
29
|
+
* (window size from JS), so this container must not re-layout it.
|
|
30
|
+
*/
|
|
31
|
+
internal class NativeOverlayContentView(context: ThemedReactContext) : ViewGroup(context) {
|
|
32
|
+
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) = Unit
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Carries the keyboard avoidance lift (translationY), so it composes with the
|
|
37
|
+
* enter / exit animation on the content or sheet inside it.
|
|
38
|
+
*/
|
|
39
|
+
internal class NativeOverlayKeyboardLayer(context: ThemedReactContext) : FrameLayout(context) {
|
|
40
|
+
init {
|
|
41
|
+
clipChildren = false
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* One overlay entry. React children mounted here are outside their
|
|
47
|
+
* ReactRootView, so this root mirrors RN Modal's touch dispatch boundary
|
|
48
|
+
* (JSTouchDispatcher / JSPointerDispatcher) to keep Pressability and native
|
|
49
|
+
* gesture cancellation working after reparenting.
|
|
50
|
+
*/
|
|
51
|
+
@SuppressLint("ViewConstructor")
|
|
52
|
+
internal class NativeOverlayEntryRootView(
|
|
53
|
+
private val reactContext: ThemedReactContext,
|
|
54
|
+
) : FrameLayout(reactContext), RootView, ReactPointerEventsView {
|
|
55
|
+
var eventDispatcher: EventDispatcher? = null
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Page entries are inside the ReactRootView, whose TouchTargetHelper reads
|
|
59
|
+
* this: blocking entries stop the search (touches never reach the page
|
|
60
|
+
* below), non-blocking ones let it continue past the empty area.
|
|
61
|
+
*/
|
|
62
|
+
override val pointerEvents: PointerEvents
|
|
63
|
+
get() = if (blocking && isShownForInput) PointerEvents.AUTO else PointerEvents.BOX_NONE
|
|
64
|
+
var stackOrder = 0
|
|
65
|
+
var levelOrder = 0
|
|
66
|
+
/** Page scope: the owning page, used by the page host to hide the entry. */
|
|
67
|
+
var ownerKey = ""
|
|
68
|
+
/**
|
|
69
|
+
* False for page scope: the entry is inside the ReactRootView, which already
|
|
70
|
+
* dispatches its touches; a second dispatcher would double every event.
|
|
71
|
+
*/
|
|
72
|
+
var dispatchesJsTouches = true
|
|
73
|
+
var blocking = true
|
|
74
|
+
var dismissOnBackPress = true
|
|
75
|
+
var dismissOnBackdropPress = false
|
|
76
|
+
var isShownForInput = false
|
|
77
|
+
var onRequestDismiss: ((String) -> Unit)? = null
|
|
78
|
+
|
|
79
|
+
val backdropView = View(reactContext).apply { alpha = 0f }
|
|
80
|
+
val keyboardLayer = NativeOverlayKeyboardLayer(reactContext)
|
|
81
|
+
val contentView = NativeOverlayContentView(reactContext)
|
|
82
|
+
|
|
83
|
+
/** The lift finished changing; the owner re-reports where its content is. */
|
|
84
|
+
var onKeyboardShiftSettled: (() -> Unit)? = null
|
|
85
|
+
private var imeBottom = 0
|
|
86
|
+
private var safeTop = 0
|
|
87
|
+
private var sheetBottomPadding = 0
|
|
88
|
+
private var keyboardAnimating = false
|
|
89
|
+
|
|
90
|
+
/** `sheet` presentation: the draggable surface; otherwise null. */
|
|
91
|
+
var sheetView: FrameLayout? = null
|
|
92
|
+
private set
|
|
93
|
+
private var sheetBehavior: BottomSheetBehavior<FrameLayout>? = null
|
|
94
|
+
private var handleView: View? = null
|
|
95
|
+
var onSheetHiddenByPan: (() -> Unit)? = null
|
|
96
|
+
|
|
97
|
+
/** The view that enter / exit animations move. */
|
|
98
|
+
val animatedView: View get() = sheetView ?: contentView
|
|
99
|
+
|
|
100
|
+
private val touchDispatcher = JSTouchDispatcher(this)
|
|
101
|
+
private val pointerDispatcher = if (ReactFeatureFlags.dispatchPointerEvents) {
|
|
102
|
+
JSPointerDispatcher(this)
|
|
103
|
+
} else {
|
|
104
|
+
null
|
|
105
|
+
}
|
|
106
|
+
private var passingThrough = false
|
|
107
|
+
private val hitRect = Rect()
|
|
108
|
+
private val targetViewTag = IntArray(1)
|
|
109
|
+
|
|
110
|
+
init {
|
|
111
|
+
clipChildren = false
|
|
112
|
+
addView(backdropView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
113
|
+
addView(keyboardLayer, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
114
|
+
keyboardLayer.addView(contentView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
115
|
+
installKeyboardTracking()
|
|
116
|
+
backdropView.setOnClickListener {
|
|
117
|
+
if (dismissOnBackdropPress) onRequestDismiss?.invoke("backdrop")
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
fun updateBlocking(value: Boolean) {
|
|
122
|
+
blocking = value
|
|
123
|
+
// A clickable backdrop consumes touches that miss the content.
|
|
124
|
+
backdropView.isClickable = value
|
|
125
|
+
backdropView.importantForAccessibility =
|
|
126
|
+
if (value) IMPORTANT_FOR_ACCESSIBILITY_NO else IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Hosts the content in a bottom sheet driven by BottomSheetBehavior, the
|
|
131
|
+
* same drag / nested-scroll mechanics as the previous BottomSheetDialog,
|
|
132
|
+
* but inside this layer instead of a separate window.
|
|
133
|
+
*/
|
|
134
|
+
fun configureSheet(
|
|
135
|
+
heightPx: Int,
|
|
136
|
+
cornerRadiusPx: Float,
|
|
137
|
+
backgroundColor: Int,
|
|
138
|
+
showHandle: Boolean,
|
|
139
|
+
draggable: Boolean,
|
|
140
|
+
) {
|
|
141
|
+
val sheet = sheetView ?: createSheet()
|
|
142
|
+
(sheet.background as? GradientDrawable)?.apply {
|
|
143
|
+
setColor(backgroundColor)
|
|
144
|
+
cornerRadii = floatArrayOf(
|
|
145
|
+
cornerRadiusPx, cornerRadiusPx, cornerRadiusPx, cornerRadiusPx, 0f, 0f, 0f, 0f,
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
handleView?.visibility = if (showHandle) VISIBLE else GONE
|
|
149
|
+
sheetBehavior?.apply {
|
|
150
|
+
isDraggable = draggable
|
|
151
|
+
isHideable = draggable
|
|
152
|
+
}
|
|
153
|
+
// The content sits above the navigation bar, as UIKit sheets keep it
|
|
154
|
+
// above the home indicator; the surface still reaches the screen edge.
|
|
155
|
+
sheetBottomPadding = bottomSystemInset()
|
|
156
|
+
val targetHeight = heightPx + sheetBottomPadding
|
|
157
|
+
val params = sheet.layoutParams
|
|
158
|
+
if (params.height != targetHeight) {
|
|
159
|
+
params.height = targetHeight
|
|
160
|
+
sheet.layoutParams = params
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** The sheet's full height, navigation bar padding included. */
|
|
165
|
+
fun sheetHeightPx(): Int = sheetView?.layoutParams?.height ?: 0
|
|
166
|
+
|
|
167
|
+
// The entry may not be attached yet when the sheet is configured; the
|
|
168
|
+
// activity's decor view always carries the window insets.
|
|
169
|
+
private fun bottomSystemInset(): Int {
|
|
170
|
+
val root = reactContext.currentActivity?.window?.decorView ?: this
|
|
171
|
+
return ViewCompat.getRootWindowInsets(root)
|
|
172
|
+
?.getInsets(WindowInsetsCompat.Type.navigationBars())
|
|
173
|
+
?.bottom ?: 0
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private fun createSheet(): FrameLayout {
|
|
177
|
+
keyboardLayer.removeView(contentView)
|
|
178
|
+
val coordinator = CoordinatorLayout(reactContext)
|
|
179
|
+
keyboardLayer.addView(coordinator, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
180
|
+
val sheet = FrameLayout(reactContext).apply {
|
|
181
|
+
background = GradientDrawable().apply { shape = GradientDrawable.RECTANGLE }
|
|
182
|
+
clipToOutline = true
|
|
183
|
+
isClickable = true
|
|
184
|
+
}
|
|
185
|
+
sheet.addView(contentView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
186
|
+
val density = resources.displayMetrics.density
|
|
187
|
+
val handle = View(reactContext).apply {
|
|
188
|
+
background = GradientDrawable().apply {
|
|
189
|
+
cornerRadius = 2.5f * density
|
|
190
|
+
setColor(0x33000000)
|
|
191
|
+
}
|
|
192
|
+
importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO
|
|
193
|
+
}
|
|
194
|
+
sheet.addView(
|
|
195
|
+
handle,
|
|
196
|
+
LayoutParams((36 * density).toInt(), (5 * density).toInt()).apply {
|
|
197
|
+
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
|
198
|
+
topMargin = (8 * density).toInt()
|
|
199
|
+
},
|
|
200
|
+
)
|
|
201
|
+
val behavior = BottomSheetBehavior<FrameLayout>().apply {
|
|
202
|
+
skipCollapsed = true
|
|
203
|
+
isFitToContents = true
|
|
204
|
+
state = BottomSheetBehavior.STATE_EXPANDED
|
|
205
|
+
addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
|
206
|
+
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
|
207
|
+
if (newState == BottomSheetBehavior.STATE_HIDDEN) onSheetHiddenByPan?.invoke()
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
|
211
|
+
// slideOffset runs from 0 (expanded) to -1 (hidden) while dragging down.
|
|
212
|
+
if (slideOffset <= 0f) backdropView.alpha = (1f + slideOffset).coerceIn(0f, 1f)
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
coordinator.addView(
|
|
217
|
+
sheet,
|
|
218
|
+
CoordinatorLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply {
|
|
219
|
+
this.behavior = behavior
|
|
220
|
+
},
|
|
221
|
+
)
|
|
222
|
+
sheetView = sheet
|
|
223
|
+
sheetBehavior = behavior
|
|
224
|
+
handleView = handle
|
|
225
|
+
return sheet
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Union of the rendered React children; the React root fills the window. */
|
|
229
|
+
fun contentExtent(): Rect {
|
|
230
|
+
sheetView?.let { sheet ->
|
|
231
|
+
val top = height - sheet.layoutParams.height
|
|
232
|
+
return Rect(0, top, width, height)
|
|
233
|
+
}
|
|
234
|
+
val union = Rect()
|
|
235
|
+
for (i in 0 until contentView.childCount) {
|
|
236
|
+
val root = contentView.getChildAt(i) as? ViewGroup ?: continue
|
|
237
|
+
for (j in 0 until root.childCount) {
|
|
238
|
+
val child = root.getChildAt(j)
|
|
239
|
+
if (child.visibility != View.VISIBLE) continue
|
|
240
|
+
child.getHitRect(hitRect)
|
|
241
|
+
hitRect.offset(root.left, root.top)
|
|
242
|
+
union.union(hitRect)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (union.isEmpty) union.set(0, 0, width, height)
|
|
246
|
+
return union
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// region Keyboard
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* IME insets arrive through this entry: applied insets for the resting
|
|
253
|
+
* state, the insets animation for the frames in between. Nothing is
|
|
254
|
+
* consumed, so the React content still sees them.
|
|
255
|
+
*/
|
|
256
|
+
private fun installKeyboardTracking() {
|
|
257
|
+
ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
|
|
258
|
+
readInsets(insets)
|
|
259
|
+
if (!keyboardAnimating) {
|
|
260
|
+
updateKeyboardShift()
|
|
261
|
+
onKeyboardShiftSettled?.invoke()
|
|
262
|
+
}
|
|
263
|
+
insets
|
|
264
|
+
}
|
|
265
|
+
ViewCompat.setWindowInsetsAnimationCallback(
|
|
266
|
+
this,
|
|
267
|
+
object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
|
|
268
|
+
override fun onPrepare(animation: WindowInsetsAnimationCompat) {
|
|
269
|
+
if (animation.typeMask and WindowInsetsCompat.Type.ime() != 0) keyboardAnimating = true
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
override fun onProgress(
|
|
273
|
+
insets: WindowInsetsCompat,
|
|
274
|
+
runningAnimations: MutableList<WindowInsetsAnimationCompat>,
|
|
275
|
+
): WindowInsetsCompat {
|
|
276
|
+
if (keyboardAnimating) {
|
|
277
|
+
readInsets(insets)
|
|
278
|
+
updateKeyboardShift()
|
|
279
|
+
}
|
|
280
|
+
return insets
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
override fun onEnd(animation: WindowInsetsAnimationCompat) {
|
|
284
|
+
if (animation.typeMask and WindowInsetsCompat.Type.ime() == 0) return
|
|
285
|
+
keyboardAnimating = false
|
|
286
|
+
ViewCompat.getRootWindowInsets(this@NativeOverlayEntryRootView)?.let(::readInsets)
|
|
287
|
+
updateKeyboardShift()
|
|
288
|
+
onKeyboardShiftSettled?.invoke()
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private fun readInsets(insets: WindowInsetsCompat) {
|
|
295
|
+
imeBottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
|
|
296
|
+
safeTop = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
|
300
|
+
super.onLayout(changed, l, t, r, b)
|
|
301
|
+
if (changed) updateKeyboardShift()
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Lifts the content above the IME, the same rule as iOS: a sheet until its
|
|
306
|
+
* content bottom clears the keyboard, other content until its bottom is
|
|
307
|
+
* 16dp above it, never above the status bar; full-window content stays.
|
|
308
|
+
*/
|
|
309
|
+
fun updateKeyboardShift() {
|
|
310
|
+
val shift = if (imeBottom <= 0 || !isAttachedToWindow || height == 0) {
|
|
311
|
+
0f
|
|
312
|
+
} else {
|
|
313
|
+
val location = IntArray(2)
|
|
314
|
+
getLocationInWindow(location)
|
|
315
|
+
val keyboardTop = (rootView.height - imeBottom - location[1]).toFloat()
|
|
316
|
+
val sheet = sheetView
|
|
317
|
+
val needed: Float
|
|
318
|
+
val room: Float
|
|
319
|
+
if (sheet != null) {
|
|
320
|
+
val sheetTop = (height - sheet.layoutParams.height).toFloat()
|
|
321
|
+
needed = (height - sheetBottomPadding) - keyboardTop
|
|
322
|
+
room = sheetTop - safeTop
|
|
323
|
+
} else {
|
|
324
|
+
val extent = contentExtent()
|
|
325
|
+
needed = extent.bottom + KEYBOARD_MARGIN_DP * resources.displayMetrics.density - keyboardTop
|
|
326
|
+
room = (extent.top - safeTop).toFloat()
|
|
327
|
+
}
|
|
328
|
+
maxOf(0f, minOf(needed, room))
|
|
329
|
+
}
|
|
330
|
+
if (keyboardLayer.translationY != -shift) keyboardLayer.translationY = -shift
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// endregion
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Hit-tests the React content the way the JS touch dispatcher would, so
|
|
337
|
+
* `box-none` wrappers (a full-window toaster, say) let touches through.
|
|
338
|
+
*/
|
|
339
|
+
private fun hitsContent(event: MotionEvent): Boolean {
|
|
340
|
+
val x = event.x - keyboardLayer.translationX - contentView.left - contentView.translationX
|
|
341
|
+
val y = event.y - keyboardLayer.translationY - contentView.top - contentView.translationY
|
|
342
|
+
for (i in contentView.childCount - 1 downTo 0) {
|
|
343
|
+
val root = contentView.getChildAt(i) as? ViewGroup ?: continue
|
|
344
|
+
if (root.visibility != View.VISIBLE) continue
|
|
345
|
+
targetViewTag[0] = View.NO_ID
|
|
346
|
+
TouchTargetHelper.findTargetTagForTouch(x - root.left, y - root.top, root, targetViewTag)
|
|
347
|
+
if (targetViewTag[0] != View.NO_ID) return true
|
|
348
|
+
}
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
353
|
+
if (!isShownForInput) return false
|
|
354
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
355
|
+
// Non-blocking overlays (toasts) only take touches that land on content.
|
|
356
|
+
passingThrough = !blocking && !hitsContent(event)
|
|
357
|
+
}
|
|
358
|
+
if (passingThrough) return false
|
|
359
|
+
return super.dispatchTouchEvent(event)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
override fun handleException(t: Throwable) {
|
|
363
|
+
reactContext.reactApplicationContext.handleException(RuntimeException(t))
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
|
367
|
+
if (!dispatchesJsTouches) return super.onInterceptTouchEvent(event)
|
|
368
|
+
eventDispatcher?.let { dispatcher ->
|
|
369
|
+
touchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
370
|
+
pointerDispatcher?.handleMotionEvent(event, dispatcher, true)
|
|
371
|
+
}
|
|
372
|
+
return super.onInterceptTouchEvent(event)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
376
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
377
|
+
if (!dispatchesJsTouches) {
|
|
378
|
+
super.onTouchEvent(event)
|
|
379
|
+
return blocking
|
|
380
|
+
}
|
|
381
|
+
eventDispatcher?.let { dispatcher ->
|
|
382
|
+
touchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
383
|
+
pointerDispatcher?.handleMotionEvent(event, dispatcher, false)
|
|
384
|
+
}
|
|
385
|
+
super.onTouchEvent(event)
|
|
386
|
+
return true
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
|
|
390
|
+
eventDispatcher?.let { pointerDispatcher?.handleMotionEvent(event, it, true) }
|
|
391
|
+
return super.onInterceptHoverEvent(event)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
override fun onHoverEvent(event: MotionEvent): Boolean {
|
|
395
|
+
eventDispatcher?.let { pointerDispatcher?.handleMotionEvent(event, it, false) }
|
|
396
|
+
return super.onHoverEvent(event)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
@OptIn(UnstableReactNativeAPI::class)
|
|
400
|
+
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
|
|
401
|
+
eventDispatcher?.let { dispatcher ->
|
|
402
|
+
touchDispatcher.onChildStartedNativeGesture(ev, dispatcher, reactContext)
|
|
403
|
+
pointerDispatcher?.onChildStartedNativeGesture(childView, ev, dispatcher)
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
|
|
408
|
+
eventDispatcher?.let { touchDispatcher.onChildEndedNativeGesture(ev, it) }
|
|
409
|
+
pointerDispatcher?.onChildEndedNativeGesture()
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) = Unit
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
private const val KEYBOARD_MARGIN_DP = 16f
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
package com.onekey.nativeoverlay
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.facebook.react.uimanager.events.Event
|
|
6
|
+
|
|
7
|
+
internal class NativeOverlayPresentedEvent(
|
|
8
|
+
surfaceId: Int,
|
|
9
|
+
viewTag: Int,
|
|
10
|
+
private val stackOrder: Int,
|
|
11
|
+
) : Event<NativeOverlayPresentedEvent>(surfaceId, viewTag) {
|
|
12
|
+
override fun getEventName(): String = "topPresented"
|
|
13
|
+
|
|
14
|
+
override fun getEventData(): WritableMap = Arguments.createMap().apply {
|
|
15
|
+
putInt("stackOrder", stackOrder)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
internal class NativeOverlayReasonEvent(
|
|
20
|
+
surfaceId: Int,
|
|
21
|
+
viewTag: Int,
|
|
22
|
+
private val name: String,
|
|
23
|
+
private val reason: String,
|
|
24
|
+
) : Event<NativeOverlayReasonEvent>(surfaceId, viewTag) {
|
|
25
|
+
override fun getEventName(): String = name
|
|
26
|
+
|
|
27
|
+
// Every request / dismissal must reach JS; never coalesce them.
|
|
28
|
+
override fun canCoalesce(): Boolean = false
|
|
29
|
+
|
|
30
|
+
override fun getEventData(): WritableMap = Arguments.createMap().apply {
|
|
31
|
+
putString("reason", reason)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
companion object {
|
|
35
|
+
const val DISMISSED = "topDismissed"
|
|
36
|
+
const val REQUEST_DISMISS = "topRequestDismiss"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
package com.onekey.nativeoverlay
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.view.KeyEvent
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.ViewGroup
|
|
7
|
+
import android.view.Window
|
|
8
|
+
import android.widget.FrameLayout
|
|
9
|
+
import androidx.activity.ComponentActivity
|
|
10
|
+
import androidx.activity.OnBackPressedCallback
|
|
11
|
+
import java.util.WeakHashMap
|
|
12
|
+
|
|
13
|
+
/** Mirrors `OVERLAY_LEVEL_ORDER`. */
|
|
14
|
+
internal enum class NativeOverlayLevel(val order: Int) {
|
|
15
|
+
MODAL(100),
|
|
16
|
+
HARDWARE(200),
|
|
17
|
+
SECURE(300),
|
|
18
|
+
TOAST(400),
|
|
19
|
+
LOCK(500),
|
|
20
|
+
DEBUG(900);
|
|
21
|
+
|
|
22
|
+
companion object {
|
|
23
|
+
fun from(value: String?): NativeOverlayLevel =
|
|
24
|
+
entries.firstOrNull { it.name.equals(value, ignoreCase = true) } ?: MODAL
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private class BackInterceptingCallback(
|
|
29
|
+
private val delegate: Window.Callback,
|
|
30
|
+
private val host: NativeOverlayHost,
|
|
31
|
+
) : Window.Callback by delegate {
|
|
32
|
+
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
|
33
|
+
if (event.keyCode == KeyEvent.KEYCODE_BACK && host.handleBackKey(event)) return true
|
|
34
|
+
return delegate.dispatchKeyEvent(event)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* One per activity: a FrameLayout added after the ReactRootView inside
|
|
40
|
+
* `android.R.id.content`, with one child container per level. Overlays are
|
|
41
|
+
* views, not windows, so order between levels is plain child order and
|
|
42
|
+
* touches that nothing consumes fall through to the React root below.
|
|
43
|
+
*/
|
|
44
|
+
internal class NativeOverlayHost private constructor(
|
|
45
|
+
private val activity: Activity,
|
|
46
|
+
) : FrameLayout(activity) {
|
|
47
|
+
private val levelContainers = sortedMapOf<NativeOverlayLevel, FrameLayout>(
|
|
48
|
+
compareBy { it.order },
|
|
49
|
+
)
|
|
50
|
+
private val backCallback = object : OnBackPressedCallback(false) {
|
|
51
|
+
override fun handleOnBackPressed() {
|
|
52
|
+
topBlockingEntry()?.let { entry ->
|
|
53
|
+
if (entry.dismissOnBackPress) entry.onRequestDismiss?.invoke("back")
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
private val hiddenForAccessibility = mutableMapOf<View, Int>()
|
|
58
|
+
|
|
59
|
+
init {
|
|
60
|
+
clipChildren = false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Called for KEYCODE_BACK before the activity sees it. ReactActivity's
|
|
65
|
+
* `onBackPressed` forwards to JS BackHandler (react-navigation pops the
|
|
66
|
+
* screen) before the OnBackPressedDispatcher, and the app opts out of
|
|
67
|
+
* predictive back, so the dispatcher alone never runs first.
|
|
68
|
+
*/
|
|
69
|
+
fun handleBackKey(event: KeyEvent): Boolean {
|
|
70
|
+
val entry = topBlockingEntry() ?: return false
|
|
71
|
+
if (event.action == KeyEvent.ACTION_UP && !event.isCanceled && entry.dismissOnBackPress) {
|
|
72
|
+
entry.onRequestDismiss?.invoke("back")
|
|
73
|
+
}
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
internal fun installBackInterceptor() {
|
|
78
|
+
val window = activity.window ?: return
|
|
79
|
+
val current = window.callback ?: return
|
|
80
|
+
if (current !is BackInterceptingCallback) {
|
|
81
|
+
window.callback = BackInterceptingCallback(current, this)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fun attach(entry: NativeOverlayEntryRootView, level: NativeOverlayLevel) {
|
|
86
|
+
installBackInterceptor()
|
|
87
|
+
val content = activity.findViewById<ViewGroup>(android.R.id.content) ?: return
|
|
88
|
+
if (parent !== content) {
|
|
89
|
+
(parent as? ViewGroup)?.removeView(this)
|
|
90
|
+
content.addView(this, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
91
|
+
} else if (content.getChildAt(content.childCount - 1) !== this) {
|
|
92
|
+
// Something (e.g. a dev overlay) was added later; stay on top.
|
|
93
|
+
bringToFront()
|
|
94
|
+
}
|
|
95
|
+
val container = levelContainer(level)
|
|
96
|
+
if (entry.parent !== container) {
|
|
97
|
+
(entry.parent as? ViewGroup)?.removeView(entry)
|
|
98
|
+
val index = (0 until container.childCount).firstOrNull { i ->
|
|
99
|
+
(container.getChildAt(i) as? NativeOverlayEntryRootView)?.let { it.stackOrder > entry.stackOrder } == true
|
|
100
|
+
} ?: container.childCount
|
|
101
|
+
container.addView(entry, index, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
102
|
+
}
|
|
103
|
+
onEntriesChanged()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fun detach(entry: NativeOverlayEntryRootView) {
|
|
107
|
+
(entry.parent as? ViewGroup)?.removeView(entry)
|
|
108
|
+
onEntriesChanged()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fun onEntriesChanged() {
|
|
112
|
+
val hasBlocking = topBlockingEntry() != null
|
|
113
|
+
if (hasBlocking && !backCallback.isEnabled) {
|
|
114
|
+
// The most recently added callback wins; re-add so ours runs before
|
|
115
|
+
// ReactActivity's and react-native-screens' callbacks.
|
|
116
|
+
backCallback.remove()
|
|
117
|
+
(activity as? ComponentActivity)?.onBackPressedDispatcher?.addCallback(backCallback)
|
|
118
|
+
}
|
|
119
|
+
backCallback.isEnabled = hasBlocking
|
|
120
|
+
updateAccessibility()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private fun levelContainer(level: NativeOverlayLevel): FrameLayout =
|
|
124
|
+
levelContainers.getOrPut(level) {
|
|
125
|
+
val container = FrameLayout(activity).apply { clipChildren = false }
|
|
126
|
+
val index = levelContainers.keys.count { it.order < level.order }
|
|
127
|
+
addView(container, index, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
128
|
+
container
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private fun orderedEntries(): List<NativeOverlayEntryRootView> =
|
|
132
|
+
levelContainers.values.flatMap { container ->
|
|
133
|
+
(0 until container.childCount).mapNotNull { container.getChildAt(it) as? NativeOverlayEntryRootView }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Global overlays win; otherwise the topmost visible page overlay. */
|
|
137
|
+
private fun topBlockingEntry(): NativeOverlayEntryRootView? =
|
|
138
|
+
orderedEntries().lastOrNull { it.blocking && it.isShownForInput }
|
|
139
|
+
?: NativeOverlayPageHostView.allHosts()
|
|
140
|
+
.filter { it.isAttachedToWindow && it.isShown }
|
|
141
|
+
.flatMap { it.shownEntries() }
|
|
142
|
+
.lastOrNull { it.blocking }
|
|
143
|
+
|
|
144
|
+
/** TalkBack only reads the topmost blocking overlay and what is above it. */
|
|
145
|
+
private fun updateAccessibility() {
|
|
146
|
+
val entries = orderedEntries()
|
|
147
|
+
val topIndex = entries.indexOfLast { it.blocking && it.isShownForInput }
|
|
148
|
+
val content = parent as? ViewGroup
|
|
149
|
+
val below = mutableListOf<View>()
|
|
150
|
+
if (topIndex >= 0) {
|
|
151
|
+
content?.let { group ->
|
|
152
|
+
(0 until group.childCount).map(group::getChildAt).filter { it !== this }.forEach(below::add)
|
|
153
|
+
}
|
|
154
|
+
below.addAll(entries.subList(0, topIndex))
|
|
155
|
+
}
|
|
156
|
+
val restore = hiddenForAccessibility.keys.filter { it !in below }
|
|
157
|
+
restore.forEach { view ->
|
|
158
|
+
view.importantForAccessibility = hiddenForAccessibility.remove(view) ?: IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
|
159
|
+
}
|
|
160
|
+
below.forEach { view ->
|
|
161
|
+
if (view !in hiddenForAccessibility) {
|
|
162
|
+
hiddenForAccessibility[view] = view.importantForAccessibility
|
|
163
|
+
view.importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
companion object {
|
|
169
|
+
private val hosts = WeakHashMap<Activity, NativeOverlayHost>()
|
|
170
|
+
|
|
171
|
+
fun of(activity: Activity): NativeOverlayHost =
|
|
172
|
+
hosts.getOrPut(activity) { NativeOverlayHost(activity) }
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.onekey.nativeoverlay
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class NativeOverlayPackage : ReactPackage {
|
|
9
|
+
override fun createViewManagers(
|
|
10
|
+
reactContext: ReactApplicationContext,
|
|
11
|
+
): List<ViewManager<*, *>> = listOf(NativeOverlayViewManager(), NativeOverlayPageHostViewManager())
|
|
12
|
+
|
|
13
|
+
override fun createNativeModules(
|
|
14
|
+
reactContext: ReactApplicationContext,
|
|
15
|
+
): List<NativeModule> = emptyList()
|
|
16
|
+
}
|