@lodev09/react-native-true-sheet 3.0.0-beta.9 → 3.0.1
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/README.md +16 -6
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +29 -33
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +3 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +53 -43
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +390 -89
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +42 -4
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +0 -5
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDialogObserver.kt +67 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +70 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +94 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetStateEvents.kt +56 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +37 -33
- package/android/src/main/res/anim/true_sheet_slide_in.xml +13 -0
- package/android/src/main/res/anim/true_sheet_slide_out.xml +13 -0
- package/android/src/main/res/values/styles.xml +13 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +5 -3
- package/ios/TrueSheetContainerView.mm +4 -0
- package/ios/TrueSheetContentView.h +2 -1
- package/ios/TrueSheetContentView.mm +91 -11
- package/ios/TrueSheetView.mm +94 -41
- package/ios/TrueSheetViewController.h +22 -10
- package/ios/TrueSheetViewController.mm +360 -173
- package/ios/core/TrueSheetBlurView.h +26 -0
- package/ios/{utils/ConversionUtil.mm → core/TrueSheetBlurView.mm} +64 -3
- package/ios/core/TrueSheetGrabberView.h +42 -0
- package/ios/core/TrueSheetGrabberView.mm +107 -0
- package/ios/events/TrueSheetDragEvents.h +39 -0
- package/ios/events/TrueSheetDragEvents.mm +62 -0
- package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
- package/ios/events/TrueSheetFocusEvents.mm +49 -0
- package/ios/events/TrueSheetLifecycleEvents.h +40 -0
- package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
- package/ios/events/TrueSheetStateEvents.h +35 -0
- package/ios/events/TrueSheetStateEvents.mm +49 -0
- package/ios/utils/GestureUtil.h +7 -0
- package/ios/utils/GestureUtil.mm +12 -0
- package/lib/module/TrueSheet.js +72 -12
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +28 -5
- package/lib/module/index.js +0 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/reanimated/ReanimatedTrueSheet.js +13 -7
- package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
- package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
- package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +4 -0
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +105 -6
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +25 -5
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +0 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
- package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
- package/package.json +8 -2
- package/src/TrueSheet.tsx +87 -10
- package/src/TrueSheet.types.ts +114 -6
- package/src/__mocks__/index.js +0 -5
- package/src/fabric/TrueSheetViewNativeComponent.ts +28 -5
- package/src/index.ts +0 -1
- package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
- package/src/reanimated/ReanimatedTrueSheetProvider.tsx +11 -3
- package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
- package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
- package/ios/events/OnDetentChangeEvent.h +0 -28
- package/ios/events/OnDetentChangeEvent.mm +0 -30
- package/ios/events/OnDidDismissEvent.h +0 -26
- package/ios/events/OnDidDismissEvent.mm +0 -25
- package/ios/events/OnDidPresentEvent.h +0 -28
- package/ios/events/OnDidPresentEvent.mm +0 -30
- package/ios/events/OnDragBeginEvent.h +0 -28
- package/ios/events/OnDragBeginEvent.mm +0 -30
- package/ios/events/OnDragChangeEvent.h +0 -28
- package/ios/events/OnDragChangeEvent.mm +0 -30
- package/ios/events/OnDragEndEvent.h +0 -28
- package/ios/events/OnDragEndEvent.mm +0 -30
- package/ios/events/OnMountEvent.h +0 -26
- package/ios/events/OnMountEvent.mm +0 -25
- package/ios/events/OnPositionChangeEvent.mm +0 -32
- package/ios/events/OnWillDismissEvent.h +0 -26
- package/ios/events/OnWillDismissEvent.mm +0 -25
- package/ios/events/OnWillPresentEvent.h +0 -28
- package/ios/events/OnWillPresentEvent.mm +0 -30
- package/ios/utils/ConversionUtil.h +0 -24
- package/lib/module/TrueSheetGrabber.js +0 -51
- package/lib/module/TrueSheetGrabber.js.map +0 -1
- package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
- package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
- package/src/TrueSheetGrabber.tsx +0 -82
|
@@ -2,17 +2,16 @@ package com.lodev09.truesheet
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.graphics.Color
|
|
5
|
-
import android.graphics.drawable.GradientDrawable
|
|
6
5
|
import android.graphics.drawable.ShapeDrawable
|
|
7
6
|
import android.graphics.drawable.shapes.RoundRectShape
|
|
8
7
|
import android.util.TypedValue
|
|
9
|
-
import android.view.Gravity
|
|
10
8
|
import android.view.MotionEvent
|
|
11
9
|
import android.view.View
|
|
12
10
|
import android.view.WindowManager
|
|
13
11
|
import android.view.accessibility.AccessibilityNodeInfo
|
|
14
12
|
import android.widget.FrameLayout
|
|
15
13
|
import androidx.core.view.isNotEmpty
|
|
14
|
+
import androidx.core.view.isVisible
|
|
16
15
|
import com.facebook.react.R
|
|
17
16
|
import com.facebook.react.uimanager.JSPointerDispatcher
|
|
18
17
|
import com.facebook.react.uimanager.JSTouchDispatcher
|
|
@@ -25,22 +24,28 @@ import com.facebook.react.util.RNLog
|
|
|
25
24
|
import com.facebook.react.views.view.ReactViewGroup
|
|
26
25
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
27
26
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
27
|
+
import com.lodev09.truesheet.core.GrabberOptions
|
|
28
28
|
import com.lodev09.truesheet.core.RNScreensFragmentObserver
|
|
29
|
+
import com.lodev09.truesheet.core.TrueSheetGrabberView
|
|
29
30
|
import com.lodev09.truesheet.utils.ScreenUtils
|
|
30
31
|
|
|
31
32
|
data class DetentInfo(val index: Int, val position: Float)
|
|
32
33
|
|
|
33
34
|
interface TrueSheetViewControllerDelegate {
|
|
34
|
-
fun viewControllerWillPresent(index: Int, position: Float)
|
|
35
|
-
fun viewControllerDidPresent(index: Int, position: Float)
|
|
35
|
+
fun viewControllerWillPresent(index: Int, position: Float, detent: Float)
|
|
36
|
+
fun viewControllerDidPresent(index: Int, position: Float, detent: Float)
|
|
36
37
|
fun viewControllerWillDismiss()
|
|
37
|
-
fun viewControllerDidDismiss()
|
|
38
|
-
fun viewControllerDidChangeDetent(index: Int, position: Float)
|
|
39
|
-
fun viewControllerDidDragBegin(index: Int, position: Float)
|
|
40
|
-
fun viewControllerDidDragChange(index: Int, position: Float)
|
|
41
|
-
fun viewControllerDidDragEnd(index: Int, position: Float)
|
|
42
|
-
fun viewControllerDidChangePosition(index:
|
|
38
|
+
fun viewControllerDidDismiss(hadParent: Boolean)
|
|
39
|
+
fun viewControllerDidChangeDetent(index: Int, position: Float, detent: Float)
|
|
40
|
+
fun viewControllerDidDragBegin(index: Int, position: Float, detent: Float)
|
|
41
|
+
fun viewControllerDidDragChange(index: Int, position: Float, detent: Float)
|
|
42
|
+
fun viewControllerDidDragEnd(index: Int, position: Float, detent: Float)
|
|
43
|
+
fun viewControllerDidChangePosition(index: Float, position: Float, detent: Float, realtime: Boolean)
|
|
43
44
|
fun viewControllerDidChangeSize(width: Int, height: Int)
|
|
45
|
+
fun viewControllerWillFocus()
|
|
46
|
+
fun viewControllerDidFocus()
|
|
47
|
+
fun viewControllerWillBlur()
|
|
48
|
+
fun viewControllerDidBlur()
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
/**
|
|
@@ -58,10 +63,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
58
63
|
private const val GRABBER_TAG = "TrueSheetGrabber"
|
|
59
64
|
private const val DEFAULT_MAX_WIDTH = 640 // dp
|
|
60
65
|
private const val DEFAULT_CORNER_RADIUS = 16 // dp
|
|
61
|
-
private const val GRABBER_WIDTH = 32f // dp
|
|
62
|
-
private const val GRABBER_HEIGHT = 4f // dp
|
|
63
|
-
private const val GRABBER_TOP_MARGIN = 16f // dp
|
|
64
|
-
private val GRABBER_COLOR = Color.argb((0.4 * 255).toInt(), 73, 69, 79) // #49454F @ 40%
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
68
|
* Gets the effective sheet height by subtracting headerHeight * 2.
|
|
@@ -107,15 +108,26 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
107
108
|
var isPresented = false
|
|
108
109
|
private set
|
|
109
110
|
|
|
111
|
+
var isDialogVisible = false
|
|
112
|
+
private set
|
|
113
|
+
|
|
110
114
|
var currentDetentIndex: Int = -1
|
|
111
115
|
private set
|
|
112
116
|
|
|
117
|
+
// Resolved detent positions (Y coordinate when sheet rests at each detent)
|
|
118
|
+
private val resolvedDetentPositions = mutableListOf<Int>()
|
|
119
|
+
|
|
113
120
|
private var isDragging = false
|
|
121
|
+
private var isReconfiguring = false
|
|
114
122
|
private var windowAnimation: Int = 0
|
|
123
|
+
private var lastEmittedPositionPx: Int = -1
|
|
115
124
|
|
|
116
125
|
var presentPromise: (() -> Unit)? = null
|
|
117
126
|
var dismissPromise: (() -> Unit)? = null
|
|
118
127
|
|
|
128
|
+
// Reference to parent TrueSheetView (if presented from another sheet)
|
|
129
|
+
var parentSheetView: TrueSheetView? = null
|
|
130
|
+
|
|
119
131
|
// ====================================================================
|
|
120
132
|
// MARK: - Configuration Properties
|
|
121
133
|
// ====================================================================
|
|
@@ -128,6 +140,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
128
140
|
var dimmed = true
|
|
129
141
|
var dimmedDetentIndex = 0
|
|
130
142
|
var grabber: Boolean = true
|
|
143
|
+
var grabberOptions: GrabberOptions? = null
|
|
131
144
|
var sheetCornerRadius: Float = -1f
|
|
132
145
|
var sheetBackgroundColor: Int = 0
|
|
133
146
|
var edgeToEdgeFullScreen: Boolean = false
|
|
@@ -142,6 +155,12 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
142
155
|
}
|
|
143
156
|
}
|
|
144
157
|
|
|
158
|
+
var draggable: Boolean = true
|
|
159
|
+
set(value) {
|
|
160
|
+
field = value
|
|
161
|
+
behavior?.isDraggable = value
|
|
162
|
+
}
|
|
163
|
+
|
|
145
164
|
// ====================================================================
|
|
146
165
|
// MARK: - Computed Properties
|
|
147
166
|
// ====================================================================
|
|
@@ -149,6 +168,13 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
149
168
|
val statusBarHeight: Int
|
|
150
169
|
get() = ScreenUtils.getStatusBarHeight(reactContext)
|
|
151
170
|
|
|
171
|
+
/**
|
|
172
|
+
* The bottom inset (navigation bar height) to add to sheet height.
|
|
173
|
+
* This matches iOS behavior where the system adds bottom safe area inset internally.
|
|
174
|
+
*/
|
|
175
|
+
private val bottomInset: Int
|
|
176
|
+
get() = ScreenUtils.getNavigationBarHeight(reactContext)
|
|
177
|
+
|
|
152
178
|
/**
|
|
153
179
|
* Edge-to-edge is enabled by default on API 36+, or when explicitly configured.
|
|
154
180
|
*/
|
|
@@ -186,8 +212,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
186
212
|
*/
|
|
187
213
|
private var rnScreensObserver: RNScreensFragmentObserver? = null
|
|
188
214
|
|
|
189
|
-
fun hasActiveModals(): Boolean = rnScreensObserver?.hasActiveModals() ?: false
|
|
190
|
-
|
|
191
215
|
// ====================================================================
|
|
192
216
|
// MARK: - Initialization
|
|
193
217
|
// ====================================================================
|
|
@@ -208,7 +232,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
208
232
|
val style = if (edgeToEdgeEnabled) {
|
|
209
233
|
com.lodev09.truesheet.R.style.TrueSheetEdgeToEdgeEnabledDialog
|
|
210
234
|
} else {
|
|
211
|
-
|
|
235
|
+
com.lodev09.truesheet.R.style.TrueSheetDialog
|
|
212
236
|
}
|
|
213
237
|
|
|
214
238
|
dialog = BottomSheetDialog(reactContext, style).apply {
|
|
@@ -225,6 +249,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
225
249
|
setCanceledOnTouchOutside(dismissible)
|
|
226
250
|
setCancelable(dismissible)
|
|
227
251
|
behavior.isHideable = dismissible
|
|
252
|
+
behavior.isDraggable = draggable
|
|
228
253
|
}
|
|
229
254
|
}
|
|
230
255
|
|
|
@@ -241,19 +266,31 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
241
266
|
dialog = null
|
|
242
267
|
isDragging = false
|
|
243
268
|
isPresented = false
|
|
269
|
+
isDialogVisible = false
|
|
270
|
+
lastEmittedPositionPx = -1
|
|
244
271
|
}
|
|
245
272
|
|
|
246
273
|
private fun setupDialogListeners(dialog: BottomSheetDialog) {
|
|
247
274
|
dialog.setOnShowListener {
|
|
248
275
|
isPresented = true
|
|
276
|
+
isDialogVisible = true
|
|
249
277
|
resetAnimation()
|
|
250
278
|
setupBackground()
|
|
251
279
|
setupGrabber()
|
|
252
280
|
|
|
253
281
|
sheetContainer?.post {
|
|
254
282
|
val detentInfo = getDetentInfoForIndex(currentDetentIndex)
|
|
255
|
-
|
|
256
|
-
|
|
283
|
+
val detent = getDetentValueForIndex(detentInfo.index)
|
|
284
|
+
val positionPx = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: screenHeight
|
|
285
|
+
|
|
286
|
+
delegate?.viewControllerDidPresent(detentInfo.index, detentInfo.position, detent)
|
|
287
|
+
|
|
288
|
+
// Store resolved position for initial detent
|
|
289
|
+
storeResolvedPosition(detentInfo.index)
|
|
290
|
+
emitChangePositionDelegate(detentInfo.index, positionPx, realtime = false)
|
|
291
|
+
|
|
292
|
+
// Notify parent sheet that it has lost focus (after this sheet appeared)
|
|
293
|
+
parentSheetView?.viewControllerDidBlur()
|
|
257
294
|
|
|
258
295
|
presentPromise?.invoke()
|
|
259
296
|
presentPromise = null
|
|
@@ -263,13 +300,22 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
263
300
|
}
|
|
264
301
|
|
|
265
302
|
dialog.setOnCancelListener {
|
|
303
|
+
// Notify parent sheet that it is about to regain focus
|
|
304
|
+
parentSheetView?.viewControllerWillFocus()
|
|
305
|
+
|
|
266
306
|
delegate?.viewControllerWillDismiss()
|
|
267
307
|
}
|
|
268
308
|
|
|
269
309
|
dialog.setOnDismissListener {
|
|
310
|
+
val hadParent = parentSheetView != null
|
|
311
|
+
|
|
312
|
+
// Notify parent sheet that it has regained focus
|
|
313
|
+
parentSheetView?.viewControllerDidFocus()
|
|
314
|
+
parentSheetView = null
|
|
315
|
+
|
|
270
316
|
dismissPromise?.invoke()
|
|
271
317
|
dismissPromise = null
|
|
272
|
-
delegate?.viewControllerDidDismiss()
|
|
318
|
+
delegate?.viewControllerDidDismiss(hadParent)
|
|
273
319
|
cleanupDialog()
|
|
274
320
|
}
|
|
275
321
|
}
|
|
@@ -279,8 +325,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
279
325
|
object : BottomSheetBehavior.BottomSheetCallback() {
|
|
280
326
|
override fun onSlide(sheetView: View, slideOffset: Float) {
|
|
281
327
|
val behavior = behavior ?: return
|
|
282
|
-
val
|
|
283
|
-
|
|
328
|
+
val positionPx = getCurrentPositionPx(sheetView)
|
|
329
|
+
val detentIndex = getDetentIndexForPosition(positionPx)
|
|
330
|
+
|
|
331
|
+
emitChangePositionDelegate(detentIndex, positionPx, realtime = true)
|
|
284
332
|
|
|
285
333
|
when (behavior.state) {
|
|
286
334
|
BottomSheetBehavior.STATE_DRAGGING,
|
|
@@ -305,7 +353,38 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
305
353
|
|
|
306
354
|
BottomSheetBehavior.STATE_EXPANDED,
|
|
307
355
|
BottomSheetBehavior.STATE_COLLAPSED,
|
|
308
|
-
BottomSheetBehavior.STATE_HALF_EXPANDED ->
|
|
356
|
+
BottomSheetBehavior.STATE_HALF_EXPANDED -> {
|
|
357
|
+
// Ignore state changes triggered by content size reconfiguration
|
|
358
|
+
if (isReconfiguring) return
|
|
359
|
+
|
|
360
|
+
getDetentInfoForState(newState)?.let { detentInfo ->
|
|
361
|
+
// Store resolved position when sheet settles
|
|
362
|
+
storeResolvedPosition(detentInfo.index)
|
|
363
|
+
|
|
364
|
+
if (isDragging) {
|
|
365
|
+
// Handle drag end
|
|
366
|
+
val detent = getDetentValueForIndex(detentInfo.index)
|
|
367
|
+
delegate?.viewControllerDidDragEnd(detentInfo.index, detentInfo.position, detent)
|
|
368
|
+
|
|
369
|
+
if (detentInfo.index != currentDetentIndex) {
|
|
370
|
+
presentPromise?.invoke()
|
|
371
|
+
presentPromise = null
|
|
372
|
+
currentDetentIndex = detentInfo.index
|
|
373
|
+
setupDimmedBackground(detentInfo.index)
|
|
374
|
+
delegate?.viewControllerDidChangeDetent(detentInfo.index, detentInfo.position, detent)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
isDragging = false
|
|
378
|
+
} else {
|
|
379
|
+
// Handle programmatic resize - emit detent change after sheet settles
|
|
380
|
+
if (detentInfo.index != currentDetentIndex) {
|
|
381
|
+
val detent = getDetentValueForIndex(detentInfo.index)
|
|
382
|
+
currentDetentIndex = detentInfo.index
|
|
383
|
+
delegate?.viewControllerDidChangeDetent(detentInfo.index, detentInfo.position, detent)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
309
388
|
|
|
310
389
|
else -> {}
|
|
311
390
|
}
|
|
@@ -319,12 +398,12 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
319
398
|
reactContext = reactContext,
|
|
320
399
|
onModalPresented = {
|
|
321
400
|
if (isPresented) {
|
|
322
|
-
|
|
401
|
+
hideDialog()
|
|
323
402
|
}
|
|
324
403
|
},
|
|
325
404
|
onModalDismissed = {
|
|
326
405
|
if (isPresented) {
|
|
327
|
-
|
|
406
|
+
showDialog()
|
|
328
407
|
}
|
|
329
408
|
}
|
|
330
409
|
)
|
|
@@ -336,6 +415,61 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
336
415
|
rnScreensObserver = null
|
|
337
416
|
}
|
|
338
417
|
|
|
418
|
+
// ====================================================================
|
|
419
|
+
// MARK: - Dialog Visibility (for stacking)
|
|
420
|
+
// ====================================================================
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Returns true if the sheet's top is at or above the status bar.
|
|
424
|
+
*/
|
|
425
|
+
val isExpanded: Boolean
|
|
426
|
+
get() {
|
|
427
|
+
val sheetTop = bottomSheetView?.top ?: return false
|
|
428
|
+
return sheetTop <= statusBarHeight
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Returns the current top position of the sheet (Y coordinate from screen top).
|
|
433
|
+
* Used for comparing sheet positions during stacking.
|
|
434
|
+
*/
|
|
435
|
+
val currentSheetTop: Int
|
|
436
|
+
get() = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: screenHeight
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Returns the expected top position of the sheet when presented at the given detent index.
|
|
440
|
+
* Used for comparing sheet positions before presentation.
|
|
441
|
+
*/
|
|
442
|
+
fun getExpectedSheetTop(detentIndex: Int): Int {
|
|
443
|
+
if (detentIndex < 0 || detentIndex >= detents.size) return screenHeight
|
|
444
|
+
val detentHeight = getDetentHeight(detents[detentIndex])
|
|
445
|
+
return screenHeight - detentHeight
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Hides the dialog without dismissing it.
|
|
450
|
+
* Used when another TrueSheet presents on top or when RN screen is presented.
|
|
451
|
+
*/
|
|
452
|
+
fun hideDialog() {
|
|
453
|
+
isDialogVisible = false
|
|
454
|
+
dialog?.window?.decorView?.visibility = View.INVISIBLE
|
|
455
|
+
|
|
456
|
+
// Emit off-screen position (detent = 0 since sheet is fully hidden)
|
|
457
|
+
emitChangePositionDelegate(currentDetentIndex, screenHeight, realtime = false)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Shows a previously hidden dialog.
|
|
462
|
+
* Used when the sheet on top dismisses.
|
|
463
|
+
*/
|
|
464
|
+
fun showDialog() {
|
|
465
|
+
isDialogVisible = true
|
|
466
|
+
dialog?.window?.decorView?.visibility = View.VISIBLE
|
|
467
|
+
|
|
468
|
+
// Emit current position
|
|
469
|
+
val positionPx = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: screenHeight
|
|
470
|
+
emitChangePositionDelegate(currentDetentIndex, positionPx, realtime = false)
|
|
471
|
+
}
|
|
472
|
+
|
|
339
473
|
// ====================================================================
|
|
340
474
|
// MARK: - Presentation
|
|
341
475
|
// ====================================================================
|
|
@@ -346,20 +480,25 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
346
480
|
return
|
|
347
481
|
}
|
|
348
482
|
|
|
349
|
-
currentDetentIndex = detentIndex
|
|
350
483
|
setupDimmedBackground(detentIndex)
|
|
351
484
|
|
|
352
485
|
if (isPresented) {
|
|
353
|
-
|
|
354
|
-
|
|
486
|
+
// Detent change will be emitted when sheet settles in onStateChanged
|
|
487
|
+
// Don't update currentDetentIndex here - it will be updated when sheet settles
|
|
355
488
|
setStateForDetentIndex(detentIndex)
|
|
356
489
|
} else {
|
|
490
|
+
currentDetentIndex = detentIndex
|
|
357
491
|
isDragging = false
|
|
358
492
|
setupSheetDetents()
|
|
359
493
|
setStateForDetentIndex(detentIndex)
|
|
360
494
|
|
|
361
495
|
val detentInfo = getDetentInfoForIndex(detentIndex)
|
|
362
|
-
|
|
496
|
+
val detent = getDetentValueForIndex(detentInfo.index)
|
|
497
|
+
|
|
498
|
+
// Notify parent sheet that it is about to lose focus (before this sheet appears)
|
|
499
|
+
parentSheetView?.viewControllerWillBlur()
|
|
500
|
+
|
|
501
|
+
delegate?.viewControllerWillPresent(detentInfo.index, detentInfo.position, detent)
|
|
363
502
|
|
|
364
503
|
if (!animated) {
|
|
365
504
|
dialog.window?.setWindowAnimations(0)
|
|
@@ -371,8 +510,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
371
510
|
|
|
372
511
|
fun dismiss() {
|
|
373
512
|
this.post {
|
|
374
|
-
|
|
375
|
-
|
|
513
|
+
// Emit off-screen position (detent = 0 since sheet is fully hidden)
|
|
514
|
+
emitChangePositionDelegate(currentDetentIndex, screenHeight, realtime = false)
|
|
376
515
|
}
|
|
377
516
|
dialog?.dismiss()
|
|
378
517
|
}
|
|
@@ -384,39 +523,53 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
384
523
|
fun setupSheetDetents() {
|
|
385
524
|
val behavior = this.behavior ?: return
|
|
386
525
|
|
|
526
|
+
// Reset resolved positions if detents count changed
|
|
527
|
+
if (resolvedDetentPositions.size != detents.size) {
|
|
528
|
+
resolvedDetentPositions.clear()
|
|
529
|
+
repeat(detents.size) { resolvedDetentPositions.add(0) }
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Always update auto detent positions based on current content height
|
|
533
|
+
for (i in detents.indices) {
|
|
534
|
+
if (detents[i] == -1.0) {
|
|
535
|
+
val detentHeight = getDetentHeight(detents[i])
|
|
536
|
+
resolvedDetentPositions[i] = screenHeight - detentHeight
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Flag to prevent state change callbacks from updating detent index during reconfiguration
|
|
541
|
+
isReconfiguring = true
|
|
542
|
+
|
|
387
543
|
behavior.apply {
|
|
388
544
|
skipCollapsed = false
|
|
389
|
-
isFitToContents =
|
|
545
|
+
isFitToContents = false
|
|
390
546
|
maxWidth = DEFAULT_MAX_WIDTH.dpToPx().toInt()
|
|
391
547
|
|
|
392
548
|
when (detents.size) {
|
|
393
549
|
1 -> {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (isPresented && detents[0] == -1.0) {
|
|
398
|
-
sheetContainer?.apply {
|
|
399
|
-
val params = layoutParams
|
|
400
|
-
params.height = maxHeight
|
|
401
|
-
layoutParams = params
|
|
402
|
-
}
|
|
403
|
-
}
|
|
550
|
+
setPeekHeight(getDetentHeight(detents[0]), isPresented)
|
|
551
|
+
expandedOffset = screenHeight - peekHeight
|
|
404
552
|
}
|
|
405
553
|
|
|
406
554
|
2 -> {
|
|
407
555
|
setPeekHeight(getDetentHeight(detents[0]), isPresented)
|
|
408
|
-
|
|
556
|
+
expandedOffset = screenHeight - getDetentHeight(detents[1])
|
|
409
557
|
}
|
|
410
558
|
|
|
411
559
|
3 -> {
|
|
412
|
-
isFitToContents = false
|
|
413
560
|
setPeekHeight(getDetentHeight(detents[0]), isPresented)
|
|
414
|
-
maxHeight = getDetentHeight(detents[2])
|
|
415
|
-
expandedOffset = sheetTopInset
|
|
416
561
|
halfExpandedRatio = minOf(getDetentHeight(detents[1]).toFloat() / screenHeight.toFloat(), 1.0f)
|
|
562
|
+
expandedOffset = screenHeight - getDetentHeight(detents[2])
|
|
417
563
|
}
|
|
418
564
|
}
|
|
419
565
|
}
|
|
566
|
+
|
|
567
|
+
// Re-apply current state to update position after config changes
|
|
568
|
+
if (isPresented) {
|
|
569
|
+
setStateForDetentIndex(currentDetentIndex)
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
isReconfiguring = false
|
|
420
573
|
}
|
|
421
574
|
|
|
422
575
|
fun setupGrabber() {
|
|
@@ -426,23 +579,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
426
579
|
bottomSheet.removeView(it)
|
|
427
580
|
}
|
|
428
581
|
|
|
429
|
-
if (!grabber) return
|
|
582
|
+
if (!grabber || !draggable) return
|
|
430
583
|
|
|
431
|
-
val grabberView =
|
|
584
|
+
val grabberView = TrueSheetGrabberView(reactContext, grabberOptions).apply {
|
|
432
585
|
tag = GRABBER_TAG
|
|
433
|
-
layoutParams = FrameLayout.LayoutParams(
|
|
434
|
-
GRABBER_WIDTH.dpToPx().toInt(),
|
|
435
|
-
GRABBER_HEIGHT.dpToPx().toInt()
|
|
436
|
-
).apply {
|
|
437
|
-
gravity = Gravity.CENTER_HORIZONTAL or Gravity.TOP
|
|
438
|
-
topMargin = GRABBER_TOP_MARGIN.dpToPx().toInt()
|
|
439
|
-
}
|
|
440
|
-
background = GradientDrawable().apply {
|
|
441
|
-
shape = GradientDrawable.RECTANGLE
|
|
442
|
-
cornerRadius = (GRABBER_HEIGHT / 2).dpToPx()
|
|
443
|
-
setColor(GRABBER_COLOR)
|
|
444
|
-
}
|
|
445
|
-
elevation = 1f
|
|
446
586
|
}
|
|
447
587
|
|
|
448
588
|
bottomSheet.addView(grabberView)
|
|
@@ -538,6 +678,159 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
538
678
|
}
|
|
539
679
|
}
|
|
540
680
|
|
|
681
|
+
// ====================================================================
|
|
682
|
+
// MARK: - Position Change Delegate
|
|
683
|
+
// ====================================================================
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Emits position change to the delegate if the position has changed.
|
|
687
|
+
* @param index The current detent index (discrete, used as fallback)
|
|
688
|
+
* @param positionPx The current position in pixels (screen Y coordinate)
|
|
689
|
+
* @param realtime Whether the position is a real-time value (during drag or animation tracking)
|
|
690
|
+
*/
|
|
691
|
+
private fun emitChangePositionDelegate(index: Int, positionPx: Int, realtime: Boolean) {
|
|
692
|
+
if (positionPx == lastEmittedPositionPx) return
|
|
693
|
+
|
|
694
|
+
lastEmittedPositionPx = positionPx
|
|
695
|
+
val position = positionPx.pxToDp()
|
|
696
|
+
val interpolatedIndex = getInterpolatedIndexForPosition(positionPx)
|
|
697
|
+
val detent = getInterpolatedDetentForPosition(positionPx)
|
|
698
|
+
delegate?.viewControllerDidChangePosition(interpolatedIndex, position, detent, realtime)
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Stores the current Y position as the resolved position for the given detent index.
|
|
703
|
+
* This is called when the sheet settles at a detent to capture the actual position
|
|
704
|
+
* which may differ from the calculated position due to system adjustments.
|
|
705
|
+
*/
|
|
706
|
+
private fun storeResolvedPosition(index: Int) {
|
|
707
|
+
if (index < 0 || index >= resolvedDetentPositions.size) return
|
|
708
|
+
val positionPx = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: return
|
|
709
|
+
if (positionPx in 1..<screenHeight) {
|
|
710
|
+
resolvedDetentPositions[index] = positionPx
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Stores the resolved position for the current detent.
|
|
716
|
+
* Called from TrueSheetView when content size changes.
|
|
717
|
+
*/
|
|
718
|
+
fun storeCurrentResolvedPosition() {
|
|
719
|
+
storeResolvedPosition(currentDetentIndex)
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Returns the estimated Y position for a detent index, using stored positions when available.
|
|
724
|
+
*/
|
|
725
|
+
private fun getEstimatedPositionForIndex(index: Int): Int {
|
|
726
|
+
if (index < 0 || index >= resolvedDetentPositions.size) return screenHeight
|
|
727
|
+
|
|
728
|
+
val storedPos = resolvedDetentPositions[index]
|
|
729
|
+
if (storedPos > 0) return storedPos
|
|
730
|
+
|
|
731
|
+
// Estimate based on getDetentHeight which accounts for bottomInset and maxAllowedHeight
|
|
732
|
+
if (index < detents.size) {
|
|
733
|
+
val detentHeight = getDetentHeight(detents[index])
|
|
734
|
+
return screenHeight - detentHeight
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return screenHeight
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Finds the segment index and interpolation progress for a given position.
|
|
742
|
+
* Returns a Triple of (fromIndex, toIndex, progress) where progress is 0-1 within that segment.
|
|
743
|
+
* Returns null if position count is less than 2.
|
|
744
|
+
*/
|
|
745
|
+
private fun findSegmentForPosition(positionPx: Int): Triple<Int, Int, Float>? {
|
|
746
|
+
val count = resolvedDetentPositions.size
|
|
747
|
+
if (count < 2) return null
|
|
748
|
+
|
|
749
|
+
val firstPos = getEstimatedPositionForIndex(0)
|
|
750
|
+
val lastPos = getEstimatedPositionForIndex(count - 1)
|
|
751
|
+
|
|
752
|
+
// Below first detent
|
|
753
|
+
if (positionPx > firstPos) {
|
|
754
|
+
val range = screenHeight - firstPos
|
|
755
|
+
val progress = if (range > 0) (positionPx - firstPos).toFloat() / range else 0f
|
|
756
|
+
return Triple(-1, 0, progress) // Special index -1 for below first
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Above last detent
|
|
760
|
+
if (positionPx < lastPos) {
|
|
761
|
+
return Triple(count - 1, count - 1, 0f)
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Find segment (positions decrease as index increases)
|
|
765
|
+
for (i in 0 until count - 1) {
|
|
766
|
+
val pos = getEstimatedPositionForIndex(i)
|
|
767
|
+
val nextPos = getEstimatedPositionForIndex(i + 1)
|
|
768
|
+
|
|
769
|
+
if (positionPx <= pos && positionPx >= nextPos) {
|
|
770
|
+
val range = pos - nextPos
|
|
771
|
+
val progress = if (range > 0) (pos - positionPx).toFloat() / range else 0f
|
|
772
|
+
return Triple(i, i + 1, maxOf(0f, minOf(1f, progress)))
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return Triple(count - 1, count - 1, 0f)
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Calculates the interpolated index based on position.
|
|
781
|
+
* Returns a continuous value (e.g., 0.5 means halfway between detent 0 and 1).
|
|
782
|
+
*/
|
|
783
|
+
private fun getInterpolatedIndexForPosition(positionPx: Int): Float {
|
|
784
|
+
val count = resolvedDetentPositions.size
|
|
785
|
+
if (count == 0) return -1f
|
|
786
|
+
if (count == 1) return 0f
|
|
787
|
+
|
|
788
|
+
val segment = findSegmentForPosition(positionPx) ?: return 0f
|
|
789
|
+
val (fromIndex, _, progress) = segment
|
|
790
|
+
|
|
791
|
+
// Below first detent
|
|
792
|
+
if (fromIndex == -1) return -progress
|
|
793
|
+
|
|
794
|
+
return fromIndex + progress
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Calculates the interpolated detent value based on position.
|
|
799
|
+
* Returns the actual screen fraction, clamped to valid detent range.
|
|
800
|
+
*/
|
|
801
|
+
private fun getInterpolatedDetentForPosition(positionPx: Int): Float {
|
|
802
|
+
val count = resolvedDetentPositions.size
|
|
803
|
+
if (count == 0) return 0f
|
|
804
|
+
|
|
805
|
+
val segment = findSegmentForPosition(positionPx) ?: return getDetentValueForIndex(0)
|
|
806
|
+
val (fromIndex, toIndex, progress) = segment
|
|
807
|
+
|
|
808
|
+
// Below first detent
|
|
809
|
+
if (fromIndex == -1) {
|
|
810
|
+
val firstDetent = getDetentValueForIndex(0)
|
|
811
|
+
return maxOf(0f, firstDetent * (1 - progress))
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
val fromDetent = getDetentValueForIndex(fromIndex)
|
|
815
|
+
val toDetent = getDetentValueForIndex(toIndex)
|
|
816
|
+
return fromDetent + progress * (toDetent - fromDetent)
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Gets the detent value (fraction) for a given index.
|
|
821
|
+
* Returns the raw screen fraction without bottomInset for interpolation calculations.
|
|
822
|
+
* Note: bottomInset is only added in getDetentHeight() for actual sheet sizing.
|
|
823
|
+
*/
|
|
824
|
+
private fun getDetentValueForIndex(index: Int): Float {
|
|
825
|
+
if (index < 0 || index >= detents.size) return 0f
|
|
826
|
+
val value = detents[index]
|
|
827
|
+
return if (value == -1.0) {
|
|
828
|
+
(contentHeight + headerHeight).toFloat() / screenHeight.toFloat()
|
|
829
|
+
} else {
|
|
830
|
+
value.toFloat()
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
541
834
|
// ====================================================================
|
|
542
835
|
// MARK: - Drag Handling
|
|
543
836
|
// ====================================================================
|
|
@@ -547,36 +840,40 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
547
840
|
return DetentInfo(currentDetentIndex, screenY.pxToDp())
|
|
548
841
|
}
|
|
549
842
|
|
|
843
|
+
private fun getCurrentPositionPx(sheetView: View): Int = ScreenUtils.getScreenY(sheetView)
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Returns the detent index for the current position.
|
|
847
|
+
* Only reports a higher index when the sheet has reached that detent's height.
|
|
848
|
+
*/
|
|
849
|
+
private fun getDetentIndexForPosition(positionPx: Int): Int {
|
|
850
|
+
if (detents.isEmpty()) return 0
|
|
851
|
+
|
|
852
|
+
val sheetHeight = screenHeight - positionPx
|
|
853
|
+
|
|
854
|
+
// Find the highest detent index that the sheet has reached
|
|
855
|
+
for (i in detents.indices.reversed()) {
|
|
856
|
+
val detentHeight = getDetentHeight(detents[i])
|
|
857
|
+
if (sheetHeight >= detentHeight) {
|
|
858
|
+
return i
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return 0
|
|
863
|
+
}
|
|
864
|
+
|
|
550
865
|
private fun handleDragBegin(sheetView: View) {
|
|
551
866
|
val detentInfo = getCurrentDetentInfo(sheetView)
|
|
552
|
-
|
|
867
|
+
val detent = getDetentValueForIndex(detentInfo.index)
|
|
868
|
+
delegate?.viewControllerDidDragBegin(detentInfo.index, detentInfo.position, detent)
|
|
553
869
|
isDragging = true
|
|
554
870
|
}
|
|
555
871
|
|
|
556
872
|
private fun handleDragChange(sheetView: View) {
|
|
557
873
|
if (!isDragging) return
|
|
558
874
|
val detentInfo = getCurrentDetentInfo(sheetView)
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
private fun handleDragEnd(state: Int) {
|
|
563
|
-
if (!isDragging) return
|
|
564
|
-
|
|
565
|
-
val detentInfo = getDetentInfoForState(state)
|
|
566
|
-
detentInfo?.let {
|
|
567
|
-
delegate?.viewControllerDidDragEnd(it.index, it.position)
|
|
568
|
-
|
|
569
|
-
if (it.index != currentDetentIndex) {
|
|
570
|
-
presentPromise?.invoke()
|
|
571
|
-
presentPromise = null
|
|
572
|
-
|
|
573
|
-
currentDetentIndex = it.index
|
|
574
|
-
setupDimmedBackground(it.index)
|
|
575
|
-
delegate?.viewControllerDidChangeDetent(it.index, it.position)
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
isDragging = false
|
|
875
|
+
val detent = getDetentValueForIndex(detentInfo.index)
|
|
876
|
+
delegate?.viewControllerDidDragChange(detentInfo.index, detentInfo.position, detent)
|
|
580
877
|
}
|
|
581
878
|
|
|
582
879
|
// ====================================================================
|
|
@@ -585,12 +882,15 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
585
882
|
|
|
586
883
|
private fun getDetentHeight(detent: Double): Int {
|
|
587
884
|
val height: Int = if (detent == -1.0) {
|
|
588
|
-
|
|
885
|
+
// For auto detent, add bottomInset to match iOS behavior where the system
|
|
886
|
+
// adds bottom safe area inset internally to the sheet height
|
|
887
|
+
contentHeight + headerHeight + bottomInset
|
|
589
888
|
} else {
|
|
590
889
|
if (detent <= 0.0 || detent > 1.0) {
|
|
591
890
|
throw IllegalArgumentException("TrueSheet: detent fraction ($detent) must be between 0 and 1")
|
|
592
891
|
}
|
|
593
|
-
|
|
892
|
+
// For fractional detents, add bottomInset to match iOS behavior
|
|
893
|
+
(detent * screenHeight).toInt() + bottomInset
|
|
594
894
|
}
|
|
595
895
|
|
|
596
896
|
val maxAllowedHeight = screenHeight - sheetTopInset
|
|
@@ -669,7 +969,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
669
969
|
super.onSizeChanged(w, h, oldw, oldh)
|
|
670
970
|
if (w == oldw && h == oldh) return
|
|
671
971
|
|
|
672
|
-
delegate?.viewControllerDidChangeSize(w,
|
|
972
|
+
delegate?.viewControllerDidChangeSize(w, h)
|
|
673
973
|
|
|
674
974
|
val oldScreenHeight = screenHeight
|
|
675
975
|
screenHeight = ScreenUtils.getScreenHeight(reactContext, edgeToEdgeEnabled)
|
|
@@ -678,8 +978,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
678
978
|
setupSheetDetents()
|
|
679
979
|
this.post {
|
|
680
980
|
positionFooter()
|
|
681
|
-
|
|
682
|
-
|
|
981
|
+
storeResolvedPosition(currentDetentIndex)
|
|
982
|
+
val positionPx = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: screenHeight
|
|
983
|
+
emitChangePositionDelegate(currentDetentIndex, positionPx, realtime = false)
|
|
683
984
|
}
|
|
684
985
|
}
|
|
685
986
|
}
|
|
@@ -699,7 +1000,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
699
1000
|
*/
|
|
700
1001
|
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
701
1002
|
val footer = containerView?.footerView
|
|
702
|
-
if (footer != null && footer.
|
|
1003
|
+
if (footer != null && footer.isVisible) {
|
|
703
1004
|
val footerLocation = ScreenUtils.getScreenLocation(footer)
|
|
704
1005
|
val touchScreenX = event.rawX.toInt()
|
|
705
1006
|
val touchScreenY = event.rawY.toInt()
|