@lodev09/react-native-true-sheet 3.5.0-beta.0 → 3.5.0-beta.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/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +45 -51
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +3 -3
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +16 -1
- package/android/src/main/res/anim/fast_fade_out.xml +6 -0
- package/android/src/main/res/values/styles.xml +6 -0
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|
|
4
4
|
import android.graphics.Color
|
|
5
5
|
import android.graphics.drawable.ShapeDrawable
|
|
6
6
|
import android.graphics.drawable.shapes.RoundRectShape
|
|
7
|
+
import android.util.Log
|
|
7
8
|
import android.util.TypedValue
|
|
8
9
|
import android.view.MotionEvent
|
|
9
10
|
import android.view.View
|
|
@@ -110,9 +111,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
110
111
|
override val headerHeight: Int
|
|
111
112
|
get() = containerView?.headerHeight ?: 0
|
|
112
113
|
|
|
113
|
-
override val keyboardHeight: Int
|
|
114
|
-
get() = keyboardObserver?.currentHeight ?: 0
|
|
115
|
-
|
|
116
114
|
// ====================================================================
|
|
117
115
|
// MARK: - State
|
|
118
116
|
// ====================================================================
|
|
@@ -120,7 +118,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
120
118
|
/** Interaction state for the sheet */
|
|
121
119
|
private sealed class InteractionState {
|
|
122
120
|
data object Idle : InteractionState()
|
|
123
|
-
data class Dragging(val startTop: Int
|
|
121
|
+
data class Dragging(val startTop: Int) : InteractionState()
|
|
124
122
|
data object Reconfiguring : InteractionState()
|
|
125
123
|
}
|
|
126
124
|
|
|
@@ -141,6 +139,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
141
139
|
private var lastStateWidth: Int = 0
|
|
142
140
|
private var lastStateHeight: Int = 0
|
|
143
141
|
private var lastEmittedPositionPx: Int = -1
|
|
142
|
+
private var detentIndexBeforeKeyboard: Int = -1
|
|
143
|
+
private var isKeyboardTransitioning: Boolean = false
|
|
144
144
|
|
|
145
145
|
var presentPromise: (() -> Unit)? = null
|
|
146
146
|
var dismissPromise: (() -> Unit)? = null
|
|
@@ -202,6 +202,12 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
202
202
|
// MARK: - Computed Properties
|
|
203
203
|
// ====================================================================
|
|
204
204
|
|
|
205
|
+
override val keyboardInset: Int
|
|
206
|
+
get() = keyboardObserver?.targetHeight ?: 0
|
|
207
|
+
|
|
208
|
+
private val currentKeyboardInset: Int
|
|
209
|
+
get() = keyboardObserver?.currentHeight ?: 0
|
|
210
|
+
|
|
205
211
|
val bottomInset: Int
|
|
206
212
|
get() = if (edgeToEdgeEnabled) ScreenUtils.getInsets(reactContext).bottom else 0
|
|
207
213
|
|
|
@@ -349,8 +355,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
349
355
|
else -> { }
|
|
350
356
|
}
|
|
351
357
|
|
|
352
|
-
|
|
353
|
-
|
|
358
|
+
if (!isKeyboardTransitioning) {
|
|
359
|
+
positionFooter(slideOffset)
|
|
360
|
+
updateDimAmount(sheetView.top)
|
|
361
|
+
}
|
|
354
362
|
}
|
|
355
363
|
|
|
356
364
|
override fun onStateChanged(sheetView: View, newState: Int) {
|
|
@@ -387,17 +395,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
387
395
|
|
|
388
396
|
when (interactionState) {
|
|
389
397
|
is InteractionState.Dragging -> {
|
|
390
|
-
val draggingState = interactionState as InteractionState.Dragging
|
|
391
398
|
val detent = detentCalculator.getDetentValueForIndex(detentInfo.index)
|
|
392
399
|
delegate?.viewControllerDidDragEnd(detentInfo.index, detentInfo.position, detent)
|
|
393
400
|
|
|
394
|
-
// Dismiss keyboard if dragged past threshold
|
|
395
|
-
if (draggingState.shouldDismissKeyboard) {
|
|
396
|
-
val imm = reactContext.getSystemService(android.content.Context.INPUT_METHOD_SERVICE)
|
|
397
|
-
as? android.view.inputmethod.InputMethodManager
|
|
398
|
-
imm?.hideSoftInputFromWindow((dialog?.currentFocus ?: bottomSheetView)?.windowToken, 0)
|
|
399
|
-
}
|
|
400
|
-
|
|
401
401
|
if (detentInfo.index != currentDetentIndex) {
|
|
402
402
|
presentPromise?.invoke()
|
|
403
403
|
presentPromise = null
|
|
@@ -412,8 +412,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
412
412
|
else -> {
|
|
413
413
|
if (detentInfo.index != currentDetentIndex) {
|
|
414
414
|
currentDetentIndex = detentInfo.index
|
|
415
|
-
|
|
416
|
-
|
|
415
|
+
if (!isKeyboardTransitioning) {
|
|
416
|
+
val detent = detentCalculator.getDetentValueForIndex(detentInfo.index)
|
|
417
|
+
delegate?.viewControllerDidChangeDetent(detentInfo.index, detentInfo.position, detent)
|
|
418
|
+
}
|
|
417
419
|
}
|
|
418
420
|
}
|
|
419
421
|
}
|
|
@@ -427,23 +429,18 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
427
429
|
isDialogVisible = false
|
|
428
430
|
wasHiddenByModal = true
|
|
429
431
|
|
|
430
|
-
|
|
432
|
+
dialog?.window?.setWindowAnimations(com.lodev09.truesheet.R.style.TrueSheetFastFadeOut)
|
|
433
|
+
dialog?.window?.decorView?.visibility = GONE
|
|
431
434
|
dimView?.visibility = INVISIBLE
|
|
432
435
|
parentDimView?.visibility = INVISIBLE
|
|
433
|
-
dialog?.window?.setFlags(
|
|
434
|
-
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
|
435
|
-
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
|
436
|
-
)
|
|
437
436
|
}
|
|
438
437
|
},
|
|
439
438
|
onModalWillDismiss = {
|
|
440
439
|
if (isPresented && wasHiddenByModal) {
|
|
441
440
|
isDialogVisible = true
|
|
442
441
|
|
|
443
|
-
dialog?.window?.
|
|
444
|
-
|
|
445
|
-
)
|
|
446
|
-
bottomSheetView?.alpha = 1f
|
|
442
|
+
dialog?.window?.setWindowAnimations(0)
|
|
443
|
+
dialog?.window?.decorView?.visibility = VISIBLE
|
|
447
444
|
dimView?.visibility = VISIBLE
|
|
448
445
|
parentDimView?.visibility = VISIBLE
|
|
449
446
|
}
|
|
@@ -689,15 +686,29 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
689
686
|
val bottomSheet = bottomSheetView ?: return
|
|
690
687
|
keyboardObserver = TrueSheetKeyboardObserver(bottomSheet, reactContext).apply {
|
|
691
688
|
delegate = object : TrueSheetKeyboardObserverDelegate {
|
|
692
|
-
override fun keyboardWillShow(height: Int) {
|
|
693
|
-
|
|
694
|
-
|
|
689
|
+
override fun keyboardWillShow(height: Int) {
|
|
690
|
+
if (!shouldHandleKeyboard()) return
|
|
691
|
+
detentIndexBeforeKeyboard = currentDetentIndex
|
|
692
|
+
isKeyboardTransitioning = true
|
|
693
|
+
setupSheetDetents()
|
|
694
|
+
setStateForDetentIndex(detents.size - 1)
|
|
695
|
+
}
|
|
695
696
|
|
|
696
|
-
override fun
|
|
697
|
+
override fun keyboardWillHide() {
|
|
697
698
|
if (!shouldHandleKeyboard()) return
|
|
698
699
|
setupSheetDetents()
|
|
699
|
-
|
|
700
|
+
if (detentIndexBeforeKeyboard >= 0) {
|
|
701
|
+
setStateForDetentIndex(detentIndexBeforeKeyboard)
|
|
702
|
+
detentIndexBeforeKeyboard = -1
|
|
703
|
+
}
|
|
700
704
|
}
|
|
705
|
+
|
|
706
|
+
override fun keyboardDidHide() {
|
|
707
|
+
if (!shouldHandleKeyboard()) return
|
|
708
|
+
isKeyboardTransitioning = false
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
override fun keyboardDidChangeHeight(height: Int) {}
|
|
701
712
|
}
|
|
702
713
|
start()
|
|
703
714
|
}
|
|
@@ -784,7 +795,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
784
795
|
|
|
785
796
|
fun updateDimAmount(sheetTop: Int? = null) {
|
|
786
797
|
if (!dimmed) return
|
|
787
|
-
val top = sheetTop ?: bottomSheetView?.top ?: return
|
|
798
|
+
val top = (sheetTop ?: bottomSheetView?.top ?: return) + currentKeyboardInset
|
|
788
799
|
dimView?.interpolateAlpha(top, dimmedDetentIndex, detentCalculator::getSheetTopForDetentIndex)
|
|
789
800
|
parentDimView?.interpolateAlpha(top, dimmedDetentIndex, detentCalculator::getSheetTopForDetentIndex)
|
|
790
801
|
}
|
|
@@ -797,7 +808,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
797
808
|
val sheetHeight = bottomSheet.height
|
|
798
809
|
val sheetTop = bottomSheet.top
|
|
799
810
|
|
|
800
|
-
var footerY = (sheetHeight - sheetTop - footerHeight -
|
|
811
|
+
var footerY = (sheetHeight - sheetTop - footerHeight - currentKeyboardInset).toFloat()
|
|
801
812
|
if (slideOffset != null && slideOffset < 0) {
|
|
802
813
|
footerY -= (footerHeight * slideOffset)
|
|
803
814
|
}
|
|
@@ -832,31 +843,14 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
832
843
|
val position = detentCalculator.getPositionDp(detentCalculator.getVisibleSheetHeight(sheetView.top))
|
|
833
844
|
val detent = detentCalculator.getDetentValueForIndex(currentDetentIndex)
|
|
834
845
|
delegate?.viewControllerDidDragBegin(currentDetentIndex, position, detent)
|
|
835
|
-
interactionState = InteractionState.Dragging(
|
|
836
|
-
startTop = sheetView.top,
|
|
837
|
-
startKeyboardHeight = keyboardHeight
|
|
838
|
-
)
|
|
846
|
+
interactionState = InteractionState.Dragging(startTop = sheetView.top)
|
|
839
847
|
}
|
|
840
848
|
|
|
841
849
|
private fun handleDragChange(sheetView: View) {
|
|
842
|
-
|
|
850
|
+
if (interactionState !is InteractionState.Dragging) return
|
|
843
851
|
val position = detentCalculator.getPositionDp(detentCalculator.getVisibleSheetHeight(sheetView.top))
|
|
844
852
|
val detent = detentCalculator.getDetentValueForIndex(currentDetentIndex)
|
|
845
853
|
delegate?.viewControllerDidDragChange(currentDetentIndex, position, detent)
|
|
846
|
-
|
|
847
|
-
// Dismiss keyboard if dragged below original position (without keyboard)
|
|
848
|
-
if (draggingState.startKeyboardHeight > 0) {
|
|
849
|
-
val detentTopWithoutKeyboard = getExpectedSheetTop(currentDetentIndex) + draggingState.startKeyboardHeight
|
|
850
|
-
val shouldDismiss = sheetView.top >= detentTopWithoutKeyboard
|
|
851
|
-
|
|
852
|
-
if (shouldDismiss != draggingState.shouldDismissKeyboard) {
|
|
853
|
-
android.util.Log.d(
|
|
854
|
-
TAG_NAME,
|
|
855
|
-
"shouldDismissKeyboard changed to: $shouldDismiss (currentTop: ${sheetView.top}, detentTop: $detentTopWithoutKeyboard)"
|
|
856
|
-
)
|
|
857
|
-
interactionState = draggingState.copy(shouldDismissKeyboard = shouldDismiss)
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
854
|
}
|
|
861
855
|
|
|
862
856
|
// ====================================================================
|
|
@@ -14,7 +14,7 @@ interface TrueSheetDetentMeasurements {
|
|
|
14
14
|
val headerHeight: Int
|
|
15
15
|
val contentBottomInset: Int
|
|
16
16
|
val maxSheetHeight: Int?
|
|
17
|
-
val
|
|
17
|
+
val keyboardInset: Int
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -30,7 +30,7 @@ class TrueSheetDetentCalculator(private val measurements: TrueSheetDetentMeasure
|
|
|
30
30
|
private val headerHeight: Int get() = measurements.headerHeight
|
|
31
31
|
private val contentBottomInset: Int get() = measurements.contentBottomInset
|
|
32
32
|
private val maxSheetHeight: Int? get() = measurements.maxSheetHeight
|
|
33
|
-
private val
|
|
33
|
+
private val keyboardInset: Int get() = measurements.keyboardInset
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Calculate the height in pixels for a given detent value.
|
|
@@ -46,7 +46,7 @@ class TrueSheetDetentCalculator(private val measurements: TrueSheetDetentMeasure
|
|
|
46
46
|
(detent * screenHeight).toInt() + contentBottomInset
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
val height = baseHeight +
|
|
49
|
+
val height = baseHeight + keyboardInset
|
|
50
50
|
val maxAllowedHeight = screenHeight + contentBottomInset
|
|
51
51
|
return maxSheetHeight?.let { minOf(height, it, maxAllowedHeight) } ?: minOf(height, maxAllowedHeight)
|
|
52
52
|
}
|
|
@@ -12,6 +12,7 @@ import com.facebook.react.uimanager.ThemedReactContext
|
|
|
12
12
|
interface TrueSheetKeyboardObserverDelegate {
|
|
13
13
|
fun keyboardWillShow(height: Int)
|
|
14
14
|
fun keyboardWillHide()
|
|
15
|
+
fun keyboardDidHide()
|
|
15
16
|
fun keyboardDidChangeHeight(height: Int)
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -26,6 +27,10 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
|
|
|
26
27
|
var currentHeight: Int = 0
|
|
27
28
|
private set
|
|
28
29
|
|
|
30
|
+
var targetHeight: Int = 0
|
|
31
|
+
private set
|
|
32
|
+
|
|
33
|
+
private var isHiding: Boolean = false
|
|
29
34
|
private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
|
|
30
35
|
private var activityRootView: View? = null
|
|
31
36
|
|
|
@@ -72,9 +77,11 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
|
|
|
72
77
|
bounds: WindowInsetsAnimationCompat.BoundsCompat
|
|
73
78
|
): WindowInsetsAnimationCompat.BoundsCompat {
|
|
74
79
|
endHeight = getKeyboardHeight(ViewCompat.getRootWindowInsets(targetView))
|
|
80
|
+
targetHeight = endHeight
|
|
81
|
+
isHiding = endHeight < startHeight
|
|
75
82
|
if (endHeight > startHeight) {
|
|
76
83
|
delegate?.keyboardWillShow(endHeight)
|
|
77
|
-
} else if (
|
|
84
|
+
} else if (isHiding) {
|
|
78
85
|
delegate?.keyboardWillHide()
|
|
79
86
|
}
|
|
80
87
|
return bounds
|
|
@@ -94,6 +101,10 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
|
|
|
94
101
|
override fun onEnd(animation: WindowInsetsAnimationCompat) {
|
|
95
102
|
val finalHeight = getKeyboardHeight(ViewCompat.getRootWindowInsets(targetView))
|
|
96
103
|
updateHeight(startHeight, finalHeight, 1f)
|
|
104
|
+
if (isHiding) {
|
|
105
|
+
delegate?.keyboardDidHide()
|
|
106
|
+
isHiding = false
|
|
107
|
+
}
|
|
97
108
|
}
|
|
98
109
|
}
|
|
99
110
|
)
|
|
@@ -114,12 +125,16 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
|
|
|
114
125
|
val previousHeight = currentHeight
|
|
115
126
|
|
|
116
127
|
if (previousHeight != newHeight) {
|
|
128
|
+
targetHeight = newHeight
|
|
117
129
|
if (newHeight > previousHeight) {
|
|
118
130
|
delegate?.keyboardWillShow(newHeight)
|
|
119
131
|
} else if (newHeight < previousHeight) {
|
|
120
132
|
delegate?.keyboardWillHide()
|
|
121
133
|
}
|
|
122
134
|
updateHeight(previousHeight, newHeight, 1f)
|
|
135
|
+
if (newHeight == 0 && previousHeight > 0) {
|
|
136
|
+
delegate?.keyboardDidHide()
|
|
137
|
+
}
|
|
123
138
|
}
|
|
124
139
|
}
|
|
125
140
|
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
<item name="android:windowExitAnimation">@null</item>
|
|
7
7
|
</style>
|
|
8
8
|
|
|
9
|
+
<!-- Fast fade out animation for hiding sheet when rn-screen is presented -->
|
|
10
|
+
<style name="TrueSheetFastFadeOut" parent="Animation.AppCompat.Dialog">
|
|
11
|
+
<item name="android:windowEnterAnimation">@null</item>
|
|
12
|
+
<item name="android:windowExitAnimation">@anim/fast_fade_out</item>
|
|
13
|
+
</style>
|
|
14
|
+
|
|
9
15
|
<!-- Default BottomSheetDialog style with programmatic animations -->
|
|
10
16
|
<style name="TrueSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
|
|
11
17
|
<item name="android:windowAnimationStyle">@style/TrueSheetNoAnimation</item>
|
package/package.json
CHANGED