@lodev09/react-native-true-sheet 3.5.1-beta.2 → 3.5.1-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +2 -2
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +32 -28
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +378 -253
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +0 -5
  5. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +36 -14
  6. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +150 -0
  7. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +55 -0
  8. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +18 -12
  9. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +91 -2
  10. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +21 -11
  11. package/android/src/main/java/com/lodev09/truesheet/core/{TrueSheetDialogObserver.kt → TrueSheetStackManager.kt} +7 -5
  12. package/ios/TrueSheetViewController.h +2 -3
  13. package/ios/TrueSheetViewController.mm +11 -4
  14. package/ios/core/TrueSheetDetentCalculator.h +2 -3
  15. package/ios/core/TrueSheetDetentCalculator.mm +7 -9
  16. package/lib/module/TrueSheet.js +1 -16
  17. package/lib/module/TrueSheet.js.map +1 -1
  18. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +0 -1
  19. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  20. package/lib/typescript/src/TrueSheet.types.d.ts +0 -8
  21. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  22. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +0 -1
  23. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  24. package/lib/typescript/src/navigation/types.d.ts +1 -1
  25. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/TrueSheet.tsx +1 -16
  28. package/src/TrueSheet.types.ts +0 -9
  29. package/src/fabric/TrueSheetViewNativeComponent.ts +0 -1
  30. package/src/navigation/types.ts +0 -1
  31. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetAnimator.kt +0 -145
  32. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDialogFragment.kt +0 -320
  33. package/android/src/main/res/anim/fast_fade_out.xml +0 -6
  34. package/android/src/main/res/values/styles.xml +0 -21
@@ -1,13 +1,14 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
3
  import android.annotation.SuppressLint
4
- import android.util.Log
4
+ import android.os.Build
5
5
  import android.view.MotionEvent
6
6
  import android.view.View
7
- import android.view.WindowManager
7
+ import android.view.ViewGroup
8
8
  import android.view.accessibility.AccessibilityNodeInfo
9
- import android.widget.FrameLayout
9
+ import androidx.activity.OnBackPressedCallback
10
10
  import androidx.appcompat.app.AppCompatActivity
11
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
11
12
  import androidx.core.view.isNotEmpty
12
13
  import androidx.core.view.isVisible
13
14
  import com.facebook.react.R
@@ -21,19 +22,19 @@ import com.facebook.react.uimanager.events.EventDispatcher
21
22
  import com.facebook.react.util.RNLog
22
23
  import com.facebook.react.views.view.ReactViewGroup
23
24
  import com.google.android.material.bottomsheet.BottomSheetBehavior
24
- import com.google.android.material.bottomsheet.BottomSheetDialog
25
25
  import com.lodev09.truesheet.core.GrabberOptions
26
26
  import com.lodev09.truesheet.core.RNScreensFragmentObserver
27
- import com.lodev09.truesheet.core.TrueSheetAnimator
28
- import com.lodev09.truesheet.core.TrueSheetAnimatorProvider
27
+ import com.lodev09.truesheet.core.TrueSheetBottomSheetView
28
+ import com.lodev09.truesheet.core.TrueSheetBottomSheetViewDelegate
29
+ import com.lodev09.truesheet.core.TrueSheetCoordinatorLayout
30
+ import com.lodev09.truesheet.core.TrueSheetCoordinatorLayoutDelegate
29
31
  import com.lodev09.truesheet.core.TrueSheetDetentCalculator
30
- import com.lodev09.truesheet.core.TrueSheetDetentMeasurements
31
- import com.lodev09.truesheet.core.TrueSheetDialogFragment
32
- import com.lodev09.truesheet.core.TrueSheetDialogFragmentDelegate
33
- import com.lodev09.truesheet.core.TrueSheetDialogObserver
32
+ import com.lodev09.truesheet.core.TrueSheetDetentCalculatorDelegate
34
33
  import com.lodev09.truesheet.core.TrueSheetDimView
34
+ import com.lodev09.truesheet.core.TrueSheetDimViewDelegate
35
35
  import com.lodev09.truesheet.core.TrueSheetKeyboardObserver
36
36
  import com.lodev09.truesheet.core.TrueSheetKeyboardObserverDelegate
37
+ import com.lodev09.truesheet.core.TrueSheetStackManager
37
38
  import com.lodev09.truesheet.utils.ScreenUtils
38
39
 
39
40
  // =============================================================================
@@ -65,24 +66,29 @@ interface TrueSheetViewControllerDelegate {
65
66
  // =============================================================================
66
67
 
67
68
  /**
68
- * Manages the bottom sheet dialog fragment and its presentation lifecycle.
69
- * Acts as a RootView to properly dispatch touch events to React Native.
69
+ * Manages the bottom sheet using CoordinatorLayout + BottomSheetBehavior.
70
+ *
71
+ * This approach keeps the sheet in the same activity window (no separate dialog window),
72
+ * which allows touch events to pass through to underlying views when the sheet is not
73
+ * covering them. This solves the touch lag issue when sheets are presented over
74
+ * interactive components like Maps.
70
75
  */
71
76
  @SuppressLint("ClickableViewAccessibility", "ViewConstructor")
72
77
  class TrueSheetViewController(private val reactContext: ThemedReactContext) :
73
78
  ReactViewGroup(reactContext),
74
79
  RootView,
75
- TrueSheetDetentMeasurements,
76
- TrueSheetAnimatorProvider,
77
- TrueSheetDialogFragmentDelegate {
80
+ TrueSheetDetentCalculatorDelegate,
81
+ TrueSheetDimViewDelegate,
82
+ TrueSheetCoordinatorLayoutDelegate,
83
+ TrueSheetBottomSheetViewDelegate {
78
84
 
79
85
  companion object {
80
86
  const val TAG_NAME = "TrueSheet"
81
87
 
82
- private const val FRAGMENT_TAG = "TrueSheetDialogFragment"
83
88
  private const val DEFAULT_MAX_WIDTH = 640 // dp
84
89
  private const val DEFAULT_CORNER_RADIUS = 16 // dp
85
90
  private const val TRANSLATE_ANIMATION_DURATION = 200L
91
+ private const val DISMISS_DURATION = 200L
86
92
  }
87
93
 
88
94
  // =============================================================================
@@ -101,16 +107,20 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
101
107
 
102
108
  var delegate: TrueSheetViewControllerDelegate? = null
103
109
 
104
- // Dialog Fragment
105
- private var dialogFragment: TrueSheetDialogFragment? = null
110
+ // CoordinatorLayout components (replaces DialogFragment)
111
+ internal var sheetView: TrueSheetBottomSheetView? = null
112
+ private var coordinatorLayout: TrueSheetCoordinatorLayout? = null
106
113
  private var dimView: TrueSheetDimView? = null
107
114
  private var parentDimView: TrueSheetDimView? = null
108
115
 
116
+ // Back button handling
117
+ private var backCallback: OnBackPressedCallback? = null
118
+
109
119
  // Presentation State
110
120
  var isPresented = false
111
121
  private set
112
122
 
113
- var isDialogVisible = false
123
+ var isSheetVisible = false
114
124
  private set
115
125
 
116
126
  var currentDetentIndex: Int = -1
@@ -119,7 +129,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
119
129
  private var interactionState: InteractionState = InteractionState.Idle
120
130
  private var isDismissing = false
121
131
  private var wasHiddenByModal = false
122
- private var shouldAnimatePresent = true
132
+ private var shouldAnimatePresent = false
133
+ private var isPresentAnimating = false
123
134
 
124
135
  private var lastStateWidth: Int = 0
125
136
  private var lastStateHeight: Int = 0
@@ -137,15 +148,16 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
137
148
  var parentSheetView: TrueSheetView? = null
138
149
 
139
150
  // Helper Objects
140
- private val sheetAnimator = TrueSheetAnimator(this)
141
151
  private var keyboardObserver: TrueSheetKeyboardObserver? = null
142
152
  private var rnScreensObserver: RNScreensFragmentObserver? = null
143
- private val detentCalculator = TrueSheetDetentCalculator(this)
153
+ internal val detentCalculator = TrueSheetDetentCalculator(reactContext).apply {
154
+ delegate = this@TrueSheetViewController
155
+ }
144
156
 
145
157
  // Touch Dispatchers
146
158
  internal var eventDispatcher: EventDispatcher? = null
147
- private val jSTouchDispatcher = JSTouchDispatcher(this)
148
- private var jSPointerDispatcher: JSPointerDispatcher? = null
159
+ private val jsTouchDispatcher = JSTouchDispatcher(this)
160
+ private var jsPointerDispatcher: JSPointerDispatcher? = null
149
161
 
150
162
  // Detent Configuration
151
163
  override var maxSheetHeight: Int? = null
@@ -154,47 +166,37 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
154
166
  // Appearance Configuration
155
167
  var dimmed = true
156
168
  var dimmedDetentIndex = 0
157
- var grabber: Boolean = true
158
- var grabberOptions: GrabberOptions? = null
159
- var sheetBackgroundColor: Int? = null
160
- var edgeToEdgeFullScreen: Boolean = false
169
+ override var grabber: Boolean = true
170
+ override var grabberOptions: GrabberOptions? = null
171
+ override var sheetBackgroundColor: Int? = null
161
172
  var insetAdjustment: String = "automatic"
162
173
 
163
- var sheetCornerRadius: Float = DEFAULT_CORNER_RADIUS.dpToPx()
174
+ override var sheetCornerRadius: Float = DEFAULT_CORNER_RADIUS.dpToPx()
164
175
  set(value) {
165
176
  field = if (value < 0) DEFAULT_CORNER_RADIUS.dpToPx() else value
166
- dialogFragment?.sheetCornerRadius = field
167
- if (isPresented) dialogFragment?.setupBackground()
177
+ if (isPresented) sheetView?.setupBackground()
168
178
  }
169
179
 
170
180
  var dismissible: Boolean = true
171
181
  set(value) {
172
182
  field = value
173
- dialogFragment?.dismissible = value
183
+ behavior?.isHideable = value
174
184
  }
175
185
 
176
186
  var draggable: Boolean = true
177
187
  set(value) {
178
188
  field = value
179
- dialogFragment?.updateDraggable(value)
189
+ behavior?.isDraggable = value
190
+ if (isPresented) sheetView?.setupGrabber()
180
191
  }
181
192
 
182
193
  // =============================================================================
183
194
  // MARK: - Computed Properties
184
195
  // =============================================================================
185
196
 
186
- // Dialog
187
- private val dialog: BottomSheetDialog?
188
- get() = dialogFragment?.bottomSheetDialog
189
-
190
- private val behavior: BottomSheetBehavior<FrameLayout>?
191
- get() = dialogFragment?.behavior
192
-
193
- private val sheetContainer: FrameLayout?
194
- get() = this.parent as? FrameLayout
195
-
196
- override val bottomSheetView: FrameLayout?
197
- get() = dialogFragment?.bottomSheetView
197
+ // Behavior
198
+ private val behavior: BottomSheetBehavior<TrueSheetBottomSheetView>?
199
+ get() = sheetView?.behavior
198
200
 
199
201
  private val containerView: TrueSheetContainerView?
200
202
  get() = if (this.isNotEmpty()) getChildAt(0) as? TrueSheetContainerView else null
@@ -238,126 +240,174 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
238
240
  private val edgeToEdgeEnabled: Boolean
239
241
  get() {
240
242
  val defaultEnabled = android.os.Build.VERSION.SDK_INT >= 36
241
- return BuildConfig.EDGE_TO_EDGE_ENABLED || dialog?.edgeToEdgeEnabled == true || defaultEnabled
243
+ return BuildConfig.EDGE_TO_EDGE_ENABLED || defaultEnabled
242
244
  }
243
245
 
244
246
  // Sheet State
245
247
  val isExpanded: Boolean
246
248
  get() {
247
- val sheetTop = bottomSheetView?.top ?: return false
249
+ val sheetTop = sheetView?.top ?: return false
248
250
  return sheetTop <= topInset
249
251
  }
250
252
 
251
253
  val currentTranslationY: Int
252
- get() = bottomSheetView?.translationY?.toInt() ?: 0
254
+ get() = sheetView?.translationY?.toInt() ?: 0
253
255
 
254
- private val isTopmostSheet: Boolean
256
+ override val isTopmostSheet: Boolean
255
257
  get() {
256
258
  val hostView = delegate as? TrueSheetView ?: return true
257
- return TrueSheetDialogObserver.isTopmostSheet(hostView)
259
+ return TrueSheetStackManager.isTopmostSheet(hostView)
258
260
  }
259
261
 
262
+ private val dimViews: List<TrueSheetDimView>
263
+ get() = listOfNotNull(dimView, parentDimView)
264
+
260
265
  // =============================================================================
261
266
  // MARK: - Initialization
262
267
  // =============================================================================
263
268
 
264
269
  init {
265
- jSPointerDispatcher = JSPointerDispatcher(this)
270
+ jsPointerDispatcher = JSPointerDispatcher(this)
266
271
  }
267
272
 
268
273
  // =============================================================================
269
- // MARK: - Fragment Creation & Cleanup
274
+ // MARK: - Sheet Creation & Cleanup
270
275
  // =============================================================================
271
276
 
272
- fun createDialog() {
273
- if (dialogFragment != null) return
277
+ fun createSheet() {
278
+ if (coordinatorLayout != null) return
279
+
280
+ // Create coordinator layout
281
+ coordinatorLayout = TrueSheetCoordinatorLayout(reactContext).apply {
282
+ delegate = this@TrueSheetViewController
283
+ }
274
284
 
275
- dialogFragment = TrueSheetDialogFragment.newInstance().apply {
276
- this.delegate = this@TrueSheetViewController
277
- this.contentView = this@TrueSheetViewController
278
- this.reactContext = this@TrueSheetViewController.reactContext
279
- this.sheetCornerRadius = this@TrueSheetViewController.sheetCornerRadius
280
- this.sheetBackgroundColor = this@TrueSheetViewController.sheetBackgroundColor
281
- this.edgeToEdgeFullScreen = this@TrueSheetViewController.edgeToEdgeFullScreen
282
- this.grabberEnabled = this@TrueSheetViewController.grabber
283
- this.grabberOptions = this@TrueSheetViewController.grabberOptions
284
- this.dismissible = this@TrueSheetViewController.dismissible
285
- this.draggable = this@TrueSheetViewController.draggable
285
+ sheetView = TrueSheetBottomSheetView(reactContext).apply {
286
+ delegate = this@TrueSheetViewController
286
287
  }
287
288
 
288
289
  setupModalObserver()
289
290
  }
290
291
 
291
- private fun cleanupDialog() {
292
+ private fun cleanupSheet() {
292
293
  cleanupKeyboardObserver()
293
294
  cleanupModalObserver()
294
- sheetAnimator.cancel()
295
+ cleanupBackCallback()
296
+ sheetView?.animate()?.cancel()
297
+
298
+ // Remove from activity
299
+ removeFromActivity()
300
+
301
+ // Cleanup dim views
295
302
  dimView?.detach()
296
303
  dimView = null
297
304
  parentDimView?.detach()
298
305
  parentDimView = null
299
- sheetContainer?.removeView(this)
300
306
 
301
- dialogFragment = null
307
+ // Detach content from sheet
308
+ sheetView?.removeView(this)
309
+
310
+ coordinatorLayout = null
311
+ sheetView = null
312
+
302
313
  interactionState = InteractionState.Idle
303
314
  isDismissing = false
304
315
  isPresented = false
305
- isDialogVisible = false
316
+ isSheetVisible = false
306
317
  wasHiddenByModal = false
318
+ isPresentAnimating = false
307
319
  lastEmittedPositionPx = -1
308
320
  shouldAnimatePresent = true
309
321
  }
310
322
 
323
+ private fun removeFromActivity() {
324
+ val coordinator = coordinatorLayout ?: return
325
+ val contentView = reactContext.currentActivity?.findViewById<ViewGroup>(android.R.id.content)
326
+ contentView?.removeView(coordinator)
327
+ }
328
+
311
329
  // =============================================================================
312
- // MARK: - TrueSheetDialogFragmentDelegate
330
+ // MARK: - Back Button Handling
313
331
  // =============================================================================
314
332
 
315
- override fun onDialogShow() {
316
- bottomSheetView?.visibility = VISIBLE
333
+ private fun setupBackCallback() {
334
+ val activity = reactContext.currentActivity as? AppCompatActivity ?: return
317
335
 
318
- isPresented = true
319
- isDialogVisible = true
336
+ backCallback = object : OnBackPressedCallback(true) {
337
+ override fun handleOnBackPressed() {
338
+ delegate?.viewControllerDidBackPress()
339
+ if (dismissible) {
340
+ dismiss(animated = true)
341
+ }
342
+ }
343
+ }
320
344
 
321
- emitWillPresentEvents()
345
+ activity.onBackPressedDispatcher.addCallback(backCallback!!)
346
+ }
322
347
 
323
- setupSheetDetents()
324
- setupDimmedBackground(currentDetentIndex)
325
- setupKeyboardObserver()
348
+ private fun cleanupBackCallback() {
349
+ backCallback?.remove()
350
+ backCallback = null
351
+ }
326
352
 
327
- if (shouldAnimatePresent) {
328
- val toTop = getExpectedSheetTop(currentDetentIndex)
329
- sheetAnimator.animatePresent(
330
- toTop = toTop,
331
- onUpdate = { effectiveTop ->
332
- emitChangePositionDelegate(effectiveTop)
333
- positionFooter()
334
- updateDimAmount(effectiveTop)
335
- },
336
- onEnd = { finishPresent() }
337
- )
338
- } else {
339
- val toTop = getExpectedSheetTop(currentDetentIndex)
340
- emitChangePositionDelegate(toTop)
353
+ // =============================================================================
354
+ // MARK: - TrueSheetCoordinatorLayout.Delegate
355
+ // =============================================================================
356
+
357
+ override fun coordinatorLayoutDidLayout(changed: Boolean) {
358
+ // Reposition footer when layout changes
359
+ if (isPresented && changed) {
341
360
  positionFooter()
342
- finishPresent()
343
361
  }
344
362
  }
345
363
 
346
- override fun onDialogDismiss() {
347
- emitDidDismissEvents()
348
- cleanupDialog()
364
+ // =============================================================================
365
+ // MARK: - TrueSheetDimViewDelegate
366
+ // =============================================================================
367
+
368
+ override fun dimViewDidTap() {
369
+ val hostView = delegate as? TrueSheetView
370
+ if (hostView == null) {
371
+ RNLog.e(reactContext, "TrueSheet: Expected delegate to be TrueSheetView")
372
+ return
373
+ }
374
+
375
+ // If there's a child sheet on top, handle it instead
376
+ val topmostChild = TrueSheetStackManager.getSheetsAbove(hostView).firstOrNull()
377
+ if (topmostChild != null) {
378
+ if (topmostChild.viewController.dismissible) {
379
+ topmostChild.viewController.dismiss(animated = true)
380
+ }
381
+ return
382
+ }
383
+
384
+ if (dismissible) {
385
+ dismiss(animated = true)
386
+ } else if (parentSheetView == null && currentDetentIndex > 0) {
387
+ setStateForDetentIndex(0)
388
+ }
349
389
  }
350
390
 
351
- override fun onDialogCancel() {
352
- // Cancel is called before dismiss for user-initiated cancellation
391
+ // =============================================================================
392
+ // MARK: - BottomSheetCallback
393
+ // =============================================================================
394
+
395
+ private val sheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
396
+ override fun onStateChanged(sheetView: View, newState: Int) {
397
+ handleStateChanged(sheetView, newState)
398
+ }
399
+
400
+ override fun onSlide(sheetView: View, slideOffset: Float) {
401
+ handleSlide(sheetView, slideOffset)
402
+ }
353
403
  }
354
404
 
355
- override fun onStateChanged(sheetView: View, newState: Int) {
405
+ private fun handleStateChanged(sheetView: View, newState: Int) {
356
406
  if (newState == BottomSheetBehavior.STATE_HIDDEN) {
357
407
  if (isDismissing) return
358
408
  isDismissing = true
359
409
  emitWillDismissEvents()
360
- dialogFragment?.dismiss()
410
+ finishDismiss()
361
411
  return
362
412
  }
363
413
 
@@ -374,9 +424,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
374
424
  }
375
425
  }
376
426
 
377
- override fun onSlide(sheetView: View, slideOffset: Float) {
378
- // Skip if our custom animator is handling the animation
379
- if (sheetAnimator.isAnimating) return
427
+ private fun handleSlide(sheetView: View, slideOffset: Float) {
428
+ // Skip during dismiss animation
429
+ if (isDismissing) return
380
430
 
381
431
  val behavior = behavior ?: return
382
432
 
@@ -389,23 +439,31 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
389
439
 
390
440
  emitChangePositionDelegate(sheetView.top)
391
441
 
392
- if (!isKeyboardTransitioning) {
442
+ // On older APIs, use onSlide for footer positioning during keyboard transitions
443
+ val useLegacyKeyboardHandling = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
444
+ if (!isKeyboardTransitioning || useLegacyKeyboardHandling) {
393
445
  positionFooter(slideOffset)
394
- updateDimAmount(sheetView.top)
395
446
  }
396
- }
397
447
 
398
- override fun onBackPressed() {
399
- delegate?.viewControllerDidBackPress()
448
+ if (!isKeyboardTransitioning) {
449
+ updateDimAmount(sheetView.top)
450
+ }
400
451
  }
401
452
 
402
453
  private fun handleStateSettled(sheetView: View, newState: Int) {
403
454
  if (interactionState is InteractionState.Reconfiguring) return
404
455
 
405
456
  val index = detentCalculator.getDetentIndexForState(newState) ?: return
406
- val position = detentCalculator.getPositionDp(detentCalculator.getVisibleSheetHeight(sheetView.top))
457
+ val position = getPositionDpForView(sheetView)
407
458
  val detentInfo = DetentInfo(index, position)
408
459
 
460
+ // Handle present animation completion
461
+ if (isPresentAnimating) {
462
+ isPresentAnimating = false
463
+ finishPresent()
464
+ return
465
+ }
466
+
409
467
  when (interactionState) {
410
468
  is InteractionState.Dragging -> {
411
469
  val detent = detentCalculator.getDetentValueForIndex(detentInfo.index)
@@ -442,7 +500,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
442
500
  rnScreensObserver = RNScreensFragmentObserver(
443
501
  reactContext = reactContext,
444
502
  onModalPresented = {
445
- if (isPresented && isDialogVisible && isTopmostSheet) {
503
+ if (isPresented && isSheetVisible && isTopmostSheet) {
446
504
  hideForModal()
447
505
  }
448
506
  },
@@ -469,45 +527,51 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
469
527
  rnScreensObserver = null
470
528
  }
471
529
 
530
+ private fun setSheetVisibility(visible: Boolean) {
531
+ coordinatorLayout?.visibility = if (visible) VISIBLE else GONE
532
+ dimViews.forEach { it.visibility = if (visible) VISIBLE else INVISIBLE }
533
+ }
534
+
472
535
  private fun hideForModal() {
473
- isDialogVisible = false
536
+ isSheetVisible = false
474
537
  wasHiddenByModal = true
475
-
476
- // Prepare for fast fade out
477
- dimView?.alpha = 0f
478
- parentDimView?.alpha = 0f
479
-
480
- dialog?.window?.setWindowAnimations(com.lodev09.truesheet.R.style.TrueSheetFastFadeOut)
481
- dialog?.window?.decorView?.visibility = GONE
482
- dimView?.visibility = INVISIBLE
483
- parentDimView?.visibility = INVISIBLE
484
-
538
+ dimViews.forEach { it.alpha = 0f }
539
+ setSheetVisibility(false)
485
540
  parentSheetView?.viewController?.hideForModal()
486
541
  }
487
542
 
488
543
  private fun showAfterModal() {
489
- isDialogVisible = true
490
-
491
- dialog?.window?.setWindowAnimations(0)
492
- dialog?.window?.decorView?.visibility = VISIBLE
493
- dimView?.visibility = VISIBLE
494
- parentDimView?.visibility = VISIBLE
495
-
544
+ isSheetVisible = true
545
+ setSheetVisibility(true)
496
546
  updateDimAmount(animated = true)
497
547
  }
498
548
 
549
+ /**
550
+ * Re-applies hidden state after returning from background.
551
+ * Android may restore visibility on activity resume, so we need to hide it again.
552
+ */
553
+ fun reapplyHiddenState() {
554
+ if (!wasHiddenByModal) return
555
+ setSheetVisibility(false)
556
+ }
557
+
499
558
  // =============================================================================
500
559
  // MARK: - Presentation
501
560
  // =============================================================================
502
561
 
503
562
  fun present(detentIndex: Int, animated: Boolean = true) {
504
- val fragment = this.dialogFragment ?: run {
505
- RNLog.w(reactContext, "TrueSheet: No dialog fragment available. Ensure the sheet is mounted before presenting.")
563
+ val coordinator = this.coordinatorLayout ?: run {
564
+ RNLog.w(reactContext, "TrueSheet: No coordinator layout available. Ensure the sheet is mounted before presenting.")
565
+ return
566
+ }
567
+
568
+ val sheet = this.sheetView ?: run {
569
+ RNLog.w(reactContext, "TrueSheet: No sheet view available.")
506
570
  return
507
571
  }
508
572
 
509
- val activity = reactContext.currentActivity as? AppCompatActivity ?: run {
510
- RNLog.w(reactContext, "TrueSheet: No AppCompatActivity available for fragment transaction.")
573
+ val activity = reactContext.currentActivity ?: run {
574
+ RNLog.w(reactContext, "TrueSheet: No activity available for presentation.")
511
575
  return
512
576
  }
513
577
 
@@ -519,15 +583,66 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
519
583
  currentDetentIndex = detentIndex
520
584
  interactionState = InteractionState.Idle
521
585
 
522
- // Show the fragment - detents are configured in onDialogShow
523
- if (!fragment.isAdded) {
524
- fragment.show(activity.supportFragmentManager, FRAGMENT_TAG)
525
- }
586
+ // Setup sheet in coordinator layout
587
+ setupSheetInCoordinator(coordinator, sheet)
588
+
589
+ // Add coordinator to activity
590
+ val contentView = activity.findViewById<ViewGroup>(android.R.id.content)
591
+ contentView?.addView(coordinator)
592
+
593
+ // Setup back button handling
594
+ setupBackCallback()
595
+
596
+ // Start presentation
597
+ onSheetShow()
598
+ }
599
+ }
600
+
601
+ private fun setupSheetInCoordinator(coordinator: TrueSheetCoordinatorLayout, sheet: TrueSheetBottomSheetView) {
602
+ // Add this controller as content to the sheet
603
+ (parent as? ViewGroup)?.removeView(this)
604
+ sheet.addView(this)
605
+
606
+ // Create layout params with behavior
607
+ val params = sheet.createLayoutParams()
608
+ val behavior = params.behavior as BottomSheetBehavior<TrueSheetBottomSheetView>
609
+
610
+ // Configure behavior
611
+ behavior.isHideable = true
612
+ behavior.isDraggable = draggable
613
+ behavior.state = BottomSheetBehavior.STATE_HIDDEN
614
+ behavior.addBottomSheetCallback(sheetCallback)
615
+
616
+ // Add sheet to coordinator
617
+ coordinator.addView(sheet, params)
618
+ }
619
+
620
+ private fun onSheetShow() {
621
+ val sheet = sheetView ?: run {
622
+ RNLog.e(reactContext, "TrueSheet: sheetView is null in onSheetShow")
623
+ return
624
+ }
625
+
626
+ emitWillPresentEvents()
627
+
628
+ setupSheetDetents()
629
+ setupDimmedBackground(currentDetentIndex)
630
+ setupKeyboardObserver()
631
+ sheet.setupBackground()
632
+ sheet.setupGrabber()
526
633
 
527
- // Execute pending transactions to ensure fragment is added
528
- activity.supportFragmentManager.executePendingTransactions()
529
- bottomSheetView?.visibility = INVISIBLE
634
+ if (shouldAnimatePresent) {
635
+ isPresentAnimating = true
636
+ post { setStateForDetentIndex(currentDetentIndex) }
637
+ } else {
638
+ setStateForDetentIndex(currentDetentIndex)
639
+ emitChangePositionDelegate(detentCalculator.getSheetTopForDetentIndex(currentDetentIndex))
640
+ updateDimAmount()
641
+ finishPresent()
530
642
  }
643
+
644
+ isPresented = true
645
+ isSheetVisible = true
531
646
  }
532
647
 
533
648
  fun dismiss(animated: Boolean = true) {
@@ -537,21 +652,32 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
537
652
  emitWillDismissEvents()
538
653
 
539
654
  if (animated) {
540
- sheetAnimator.animateDismiss(
541
- onUpdate = { effectiveTop ->
542
- emitChangePositionDelegate(effectiveTop)
543
- positionFooter()
544
- updateDimAmount(effectiveTop)
545
- },
546
- onEnd = { dialogFragment?.dismiss() }
547
- )
655
+ animateDismiss()
548
656
  } else {
549
657
  emitChangePositionDelegate(realScreenHeight)
550
- dialogFragment?.dismiss()
658
+ finishDismiss()
551
659
  }
552
660
  }
553
661
 
662
+ private fun animateDismiss() {
663
+ val sheet = sheetView ?: run {
664
+ finishDismiss()
665
+ return
666
+ }
667
+
668
+ sheet.animate()
669
+ .y(realScreenHeight.toFloat())
670
+ .setDuration(DISMISS_DURATION)
671
+ .setInterpolator(android.view.animation.AccelerateInterpolator())
672
+ .setUpdateListener { updateSheetVisuals(sheet.y.toInt()) }
673
+ .withEndAction { finishDismiss() }
674
+ .start()
675
+ }
676
+
554
677
  private fun finishPresent() {
678
+ // Restore isHideable to actual value after present animation
679
+ behavior?.isHideable = dismissible
680
+
555
681
  val (index, position, detent) = getDetentInfoWithValue(currentDetentIndex)
556
682
  delegate?.viewControllerDidPresent(index, position, detent)
557
683
  parentSheetView?.viewControllerDidBlur()
@@ -561,40 +687,47 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
561
687
  presentPromise = null
562
688
  }
563
689
 
690
+ private fun finishDismiss() {
691
+ emitDidDismissEvents()
692
+ cleanupSheet()
693
+ }
694
+
564
695
  // =============================================================================
565
696
  // MARK: - Sheet Configuration
566
697
  // =============================================================================
567
698
 
568
699
  fun setupSheetDetents() {
569
- val fragment = this.dialogFragment ?: return
570
- val behavior = this.behavior ?: return
700
+ val behavior = this.behavior ?: run {
701
+ RNLog.e(reactContext, "TrueSheet: behavior is null in setupSheetDetents")
702
+ return
703
+ }
571
704
 
572
705
  interactionState = InteractionState.Reconfiguring
573
- val edgeToEdgeTopInset: Int = if (!edgeToEdgeFullScreen) topInset else 0
574
706
 
575
707
  behavior.isFitToContents = false
576
708
 
577
- val maxAvailableHeight = realScreenHeight - edgeToEdgeTopInset
709
+ val maxAvailableHeight = realScreenHeight - topInset
578
710
 
579
- val peekHeight = detentCalculator.getDetentHeight(detents[0])
711
+ val peekHeight = minOf(detentCalculator.getDetentHeight(detents[0]), maxAvailableHeight)
580
712
 
581
713
  val halfExpandedDetentHeight = when (detents.size) {
582
714
  1 -> peekHeight
583
715
  else -> detentCalculator.getDetentHeight(detents[1])
584
716
  }
585
717
 
586
- val maxDetentHeight = detentCalculator.getDetentHeight(detents.last())
718
+ val maxDetentHeight = minOf(detentCalculator.getDetentHeight(detents.last()), maxAvailableHeight)
587
719
 
588
720
  val adjustedHalfExpandedHeight = minOf(halfExpandedDetentHeight, maxAvailableHeight)
589
721
  val halfExpandedRatio = (adjustedHalfExpandedHeight.toFloat() / realScreenHeight.toFloat())
590
722
  .coerceIn(0f, 0.999f)
591
723
 
592
- val expandedOffset = maxOf(edgeToEdgeTopInset, realScreenHeight - maxDetentHeight)
724
+ val expandedOffset = realScreenHeight - maxDetentHeight
593
725
 
594
726
  // fitToContents works better with <= 2 detents when no expanded offset
595
727
  val fitToContents = detents.size < 3 && expandedOffset == 0
596
728
 
597
- fragment.configureDetents(
729
+ configureDetents(
730
+ behavior = behavior,
598
731
  peekHeight = peekHeight,
599
732
  halfExpandedRatio = halfExpandedRatio,
600
733
  expandedOffset = expandedOffset,
@@ -619,93 +752,76 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
619
752
  interactionState = InteractionState.Idle
620
753
  }
621
754
 
755
+ private fun configureDetents(
756
+ behavior: BottomSheetBehavior<TrueSheetBottomSheetView>,
757
+ peekHeight: Int,
758
+ halfExpandedRatio: Float,
759
+ expandedOffset: Int,
760
+ fitToContents: Boolean,
761
+ animate: Boolean
762
+ ) {
763
+ behavior.apply {
764
+ isFitToContents = fitToContents
765
+ skipCollapsed = false
766
+ setPeekHeight(peekHeight, animate)
767
+ this.halfExpandedRatio = halfExpandedRatio.coerceIn(0f, 0.999f)
768
+ this.expandedOffset = expandedOffset
769
+ }
770
+ }
771
+
622
772
  fun setupSheetDetentsForSizeChange() {
623
773
  setupSheetDetents()
624
774
  positionFooter()
625
775
  }
626
776
 
627
777
  fun setStateForDetentIndex(index: Int) {
628
- dialogFragment?.setState(detentCalculator.getStateForDetentIndex(index))
629
- }
630
-
631
- // =============================================================================
632
- // MARK: - Grabber
633
- // =============================================================================
634
-
635
- fun setupGrabber() {
636
- dialogFragment?.apply {
637
- grabberEnabled = this@TrueSheetViewController.grabber
638
- grabberOptions = this@TrueSheetViewController.grabberOptions
639
- setupGrabber()
640
- }
778
+ behavior?.state = detentCalculator.getStateForDetentIndex(index)
641
779
  }
642
780
 
643
781
  // =============================================================================
644
- // MARK: - Background & Dimming
782
+ // MARK: - Dimmed Background
645
783
  // =============================================================================
646
784
 
647
- fun setupBackground() {
648
- dialogFragment?.apply {
649
- sheetCornerRadius = this@TrueSheetViewController.sheetCornerRadius
650
- sheetBackgroundColor = this@TrueSheetViewController.sheetBackgroundColor
651
- setupBackground()
652
- }
653
- }
654
-
655
785
  fun setupDimmedBackground(detentIndex: Int) {
656
- val dialog = this.dialog ?: return
657
-
658
- dialog.window?.apply {
659
- val touchOutside = findViewById<View>(com.google.android.material.R.id.touch_outside)
660
- clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
661
-
662
- val shouldDimAtDetent = dimmed && detentIndex >= dimmedDetentIndex
663
-
664
- if (dimmed) {
665
- val parentDimVisible = (parentSheetView?.viewController?.dimView?.alpha ?: 0f) > 0f
786
+ val coordinator = this.coordinatorLayout ?: run {
787
+ RNLog.e(reactContext, "TrueSheet: coordinatorLayout is null in setupDimmedBackground")
788
+ return
789
+ }
666
790
 
667
- if (dimView == null) dimView = TrueSheetDimView(reactContext)
668
- if (!parentDimVisible) dimView?.attach(null)
791
+ if (dimmed) {
792
+ val parentDimVisible = (parentSheetView?.viewController?.dimView?.alpha ?: 0f) > 0f
669
793
 
670
- // Attach dim view to parent sheet if stacked
671
- val parentController = parentSheetView?.viewController
672
- val parentBottomSheet = parentController?.bottomSheetView
673
- if (parentBottomSheet != null) {
674
- if (parentDimView == null) parentDimView = TrueSheetDimView(reactContext)
675
- parentDimView?.attach(parentBottomSheet, parentController.sheetCornerRadius)
794
+ if (dimView == null) {
795
+ dimView = TrueSheetDimView(reactContext).apply {
796
+ delegate = this@TrueSheetViewController
676
797
  }
677
- } else {
678
- dimView?.detach()
679
- dimView = null
680
- parentDimView?.detach()
681
- parentDimView = null
798
+ }
799
+ if (!parentDimVisible) {
800
+ dimView?.attachToCoordinator(coordinator)
682
801
  }
683
802
 
684
- if (shouldDimAtDetent) {
685
- touchOutside.setOnTouchListener { _, event ->
686
- if (event.action == MotionEvent.ACTION_UP && dismissible) {
687
- dismiss()
803
+ // Attach dim view to parent sheet if stacked
804
+ val parentController = parentSheetView?.viewController
805
+ val parentBottomSheet = parentController?.sheetView
806
+ if (parentBottomSheet != null) {
807
+ if (parentDimView == null) {
808
+ parentDimView = TrueSheetDimView(reactContext).apply {
809
+ delegate = this@TrueSheetViewController
688
810
  }
689
- true
690
- }
691
- } else {
692
- // Pass through touches to parent or activity when not dimmed
693
- touchOutside.setOnTouchListener { v, event ->
694
- event.setLocation(event.rawX - v.x, event.rawY - v.y)
695
- (
696
- parentSheetView?.viewController?.dialog?.window?.decorView
697
- ?: reactContext.currentActivity?.window?.decorView
698
- )?.dispatchTouchEvent(event)
699
- false
700
811
  }
701
- dialog.setCanceledOnTouchOutside(false)
812
+ parentDimView?.attach(parentBottomSheet, parentController.sheetCornerRadius)
702
813
  }
814
+ } else {
815
+ dimView?.detach()
816
+ dimView = null
817
+ parentDimView?.detach()
818
+ parentDimView = null
703
819
  }
704
820
  }
705
821
 
706
822
  fun updateDimAmount(sheetTop: Int? = null, animated: Boolean = false) {
707
823
  if (!dimmed) return
708
- val top = (sheetTop ?: bottomSheetView?.top ?: return) + currentKeyboardInset
824
+ val top = (sheetTop ?: sheetView?.top ?: return) + currentKeyboardInset
709
825
 
710
826
  if (animated) {
711
827
  val targetAlpha = dimView?.calculateAlpha(
@@ -713,11 +829,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
713
829
  dimmedDetentIndex,
714
830
  detentCalculator::getSheetTopForDetentIndex
715
831
  ) ?: 0f
716
- dimView?.animate()?.alpha(targetAlpha)?.setDuration(200)?.start()
717
- parentDimView?.animate()?.alpha(targetAlpha)?.setDuration(200)?.start()
832
+ dimViews.forEach { it.animate().alpha(targetAlpha).setDuration(200).start() }
718
833
  } else {
719
- dimView?.interpolateAlpha(top, dimmedDetentIndex, detentCalculator::getSheetTopForDetentIndex)
720
- parentDimView?.interpolateAlpha(top, dimmedDetentIndex, detentCalculator::getSheetTopForDetentIndex)
834
+ dimViews.forEach { it.interpolateAlpha(top, dimmedDetentIndex, detentCalculator::getSheetTopForDetentIndex) }
721
835
  }
722
836
  }
723
837
 
@@ -728,11 +842,11 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
728
842
  fun positionFooter(slideOffset: Float? = null) {
729
843
  if (!isPresented) return
730
844
  val footerView = containerView?.footerView ?: return
731
- val bottomSheet = bottomSheetView ?: return
845
+ val sheet = sheetView ?: return
732
846
 
733
847
  val footerHeight = footerView.height
734
- val sheetHeight = bottomSheet.height
735
- val sheetTop = bottomSheet.top
848
+ val sheetHeight = sheet.height
849
+ val sheetTop = sheet.top
736
850
 
737
851
  var footerY = (sheetHeight - sheetTop - footerHeight - currentKeyboardInset).toFloat()
738
852
 
@@ -756,13 +870,17 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
756
870
  }
757
871
 
758
872
  fun setupKeyboardObserver() {
759
- val bottomSheet = bottomSheetView ?: return
760
- keyboardObserver = TrueSheetKeyboardObserver(bottomSheet, reactContext).apply {
873
+ val coordinator = coordinatorLayout ?: run {
874
+ RNLog.e(reactContext, "TrueSheet: coordinatorLayout is null in setupKeyboardObserver")
875
+ return
876
+ }
877
+ cleanupKeyboardObserver()
878
+ keyboardObserver = TrueSheetKeyboardObserver(coordinator, reactContext).apply {
761
879
  delegate = object : TrueSheetKeyboardObserverDelegate {
762
880
  override fun keyboardWillShow(height: Int) {
881
+ isKeyboardTransitioning = true
763
882
  if (!shouldHandleKeyboard()) return
764
883
  detentIndexBeforeKeyboard = currentDetentIndex
765
- isKeyboardTransitioning = true
766
884
  setupSheetDetents()
767
885
  setStateForDetentIndex(detents.size - 1)
768
886
  }
@@ -777,7 +895,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
777
895
  }
778
896
 
779
897
  override fun keyboardDidHide() {
780
- if (!shouldHandleKeyboard()) return
781
898
  isKeyboardTransitioning = false
782
899
  }
783
900
 
@@ -799,8 +916,11 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
799
916
  // MARK: - Drag Handling
800
917
  // =============================================================================
801
918
 
919
+ private fun getPositionDpForView(sheetView: View): Float =
920
+ detentCalculator.getPositionDp(detentCalculator.getVisibleSheetHeight(sheetView.top))
921
+
802
922
  private fun handleDragBegin(sheetView: View) {
803
- val position = detentCalculator.getPositionDp(detentCalculator.getVisibleSheetHeight(sheetView.top))
923
+ val position = getPositionDpForView(sheetView)
804
924
  val detent = detentCalculator.getDetentValueForIndex(currentDetentIndex)
805
925
  delegate?.viewControllerDidDragBegin(currentDetentIndex, position, detent)
806
926
  interactionState = InteractionState.Dragging(startTop = sheetView.top)
@@ -808,7 +928,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
808
928
 
809
929
  private fun handleDragChange(sheetView: View) {
810
930
  if (interactionState !is InteractionState.Dragging) return
811
- val position = detentCalculator.getPositionDp(detentCalculator.getVisibleSheetHeight(sheetView.top))
931
+ val position = getPositionDpForView(sheetView)
812
932
  val detent = detentCalculator.getDetentValueForIndex(currentDetentIndex)
813
933
  delegate?.viewControllerDidDragChange(currentDetentIndex, position, detent)
814
934
  }
@@ -854,23 +974,28 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
854
974
  delegate?.viewControllerDidChangePosition(interpolatedIndex, position, detent, realtime)
855
975
  }
856
976
 
977
+ /**
978
+ * Updates position emission, footer, and dim amount together.
979
+ * This pattern is commonly used during animations and state changes.
980
+ */
981
+ private fun updateSheetVisuals(effectiveTop: Int, slideOffset: Float? = null) {
982
+ emitChangePositionDelegate(effectiveTop)
983
+ positionFooter(slideOffset)
984
+ updateDimAmount(effectiveTop)
985
+ }
986
+
857
987
  // =============================================================================
858
988
  // MARK: - Detent Helpers
859
989
  // =============================================================================
860
990
 
861
- fun getExpectedSheetTop(detentIndex: Int): Int {
862
- if (detentIndex < 0 || detentIndex >= detents.size) return screenHeight
863
- return realScreenHeight - detentCalculator.getDetentHeight(detents[detentIndex])
864
- }
865
-
866
- fun translateDialog(translationY: Int) {
867
- val bottomSheet = bottomSheetView ?: return
991
+ fun translateSheet(translationY: Int) {
992
+ val sheet = sheetView ?: return
868
993
 
869
- bottomSheet.animate()
994
+ sheet.animate()
870
995
  .translationY(translationY.toFloat())
871
996
  .setDuration(TRANSLATE_ANIMATION_DURATION)
872
997
  .setUpdateListener {
873
- val effectiveTop = bottomSheet.top + bottomSheet.translationY.toInt()
998
+ val effectiveTop = sheet.top + sheet.translationY.toInt()
874
999
  emitChangePositionDelegate(effectiveTop)
875
1000
  }
876
1001
  .start()
@@ -887,7 +1012,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
887
1012
  private fun getPositionForDetentIndex(index: Int): Float {
888
1013
  if (index < 0 || index >= detents.size) return screenHeight.pxToDp()
889
1014
 
890
- bottomSheetView?.let {
1015
+ sheetView?.let {
891
1016
  val visibleSheetHeight = detentCalculator.getVisibleSheetHeight(it.top)
892
1017
  if (visibleSheetHeight in 1..<realScreenHeight) {
893
1018
  return detentCalculator.getPositionDp(visibleSheetHeight)
@@ -919,7 +1044,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
919
1044
  post {
920
1045
  setupSheetDetents()
921
1046
  positionFooter()
922
- bottomSheetView?.let { emitChangePositionDelegate(it.top, realtime = false) }
1047
+ sheetView?.let { emitChangePositionDelegate(it.top, realtime = false) }
923
1048
  }
924
1049
  }
925
1050
 
@@ -960,41 +1085,41 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
960
1085
 
961
1086
  override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
962
1087
  eventDispatcher?.let {
963
- jSTouchDispatcher.handleTouchEvent(event, it, reactContext)
964
- jSPointerDispatcher?.handleMotionEvent(event, it, true)
1088
+ jsTouchDispatcher.handleTouchEvent(event, it, reactContext)
1089
+ jsPointerDispatcher?.handleMotionEvent(event, it, true)
965
1090
  }
966
1091
  return super.onInterceptTouchEvent(event)
967
1092
  }
968
1093
 
969
1094
  override fun onTouchEvent(event: MotionEvent): Boolean {
970
1095
  eventDispatcher?.let {
971
- jSTouchDispatcher.handleTouchEvent(event, it, reactContext)
972
- jSPointerDispatcher?.handleMotionEvent(event, it, false)
1096
+ jsTouchDispatcher.handleTouchEvent(event, it, reactContext)
1097
+ jsPointerDispatcher?.handleMotionEvent(event, it, false)
973
1098
  }
974
1099
  super.onTouchEvent(event)
975
1100
  return true
976
1101
  }
977
1102
 
978
1103
  override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
979
- eventDispatcher?.let { jSPointerDispatcher?.handleMotionEvent(event, it, true) }
1104
+ eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, true) }
980
1105
  return super.onHoverEvent(event)
981
1106
  }
982
1107
 
983
1108
  override fun onHoverEvent(event: MotionEvent): Boolean {
984
- eventDispatcher?.let { jSPointerDispatcher?.handleMotionEvent(event, it, false) }
1109
+ eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, false) }
985
1110
  return super.onHoverEvent(event)
986
1111
  }
987
1112
 
988
1113
  override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
989
1114
  eventDispatcher?.let {
990
- jSTouchDispatcher.onChildStartedNativeGesture(ev, it)
991
- jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, it)
1115
+ jsTouchDispatcher.onChildStartedNativeGesture(ev, it)
1116
+ jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, it)
992
1117
  }
993
1118
  }
994
1119
 
995
1120
  override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
996
- eventDispatcher?.let { jSTouchDispatcher.onChildEndedNativeGesture(ev, it) }
997
- jSPointerDispatcher?.onChildEndedNativeGesture()
1121
+ eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
1122
+ jsPointerDispatcher?.onChildEndedNativeGesture()
998
1123
  }
999
1124
 
1000
1125
  override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {