Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.swmansion.rnscreens.legacy.bottomsheet

import android.util.Log
import android.view.View
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED
Expand All @@ -9,6 +10,8 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
import com.swmansion.rnscreens.legacy.Screen
import com.swmansion.rnscreens.legacy.ext.asScreenStackFragment

private const val TAG = "SheetUtils"

object SheetUtils {
/**
* Verifies whether BottomSheetBehavior.State is one of stable states. As unstable states
Expand Down Expand Up @@ -75,7 +78,8 @@ object SheetUtils {
* @param state state of the bottom sheet
* @param detentCount length of array with detents fractions
*
* @throws IllegalArgumentException for invalid state / detentCount combinations
* A stable state that the current detents array cannot express is clamped to the top-most
* detent rather than throwing, see [unmappedDetentIndex].
*/
fun detentIndexFromSheetState(
@BottomSheetBehavior.State state: Int,
Expand All @@ -86,15 +90,15 @@ object SheetUtils {
when (state) {
STATE_HIDDEN -> -1
STATE_EXPANDED -> 0
else -> throw IllegalArgumentException("[RNScreens] Invalid state $state for detentCount $detentCount")
else -> unmappedDetentIndex(state, detentCount)
}

2 ->
when (state) {
STATE_HIDDEN -> -1
STATE_COLLAPSED -> 0
STATE_EXPANDED -> 1
else -> throw IllegalArgumentException("[RNScreens] Invalid state $state for detentCount $detentCount")
else -> unmappedDetentIndex(state, detentCount)
}

3 ->
Expand All @@ -103,12 +107,34 @@ object SheetUtils {
STATE_COLLAPSED -> 0
STATE_HALF_EXPANDED -> 1
STATE_EXPANDED -> 2
else -> throw IllegalArgumentException("[RNScreens] Invalid state $state for detentCount $detentCount")
else -> unmappedDetentIndex(state, detentCount)
}

else -> throw IllegalArgumentException("[RNScreens] Invalid state $state for detentCount $detentCount")
else -> unmappedDetentIndex(state, detentCount)
}

/**
* Maps a stable [BottomSheetBehavior.State] that the current detents array cannot express.
*
* This is reachable through ordinary prop updates: when `sheetAllowedDetents` shrinks while the
* sheet rests in a detent that no longer exists, Material keeps reporting the old state until
* the sheet is re-settled. Going from `[0.5, 1]` to `[1]` while collapsed, for example, delivers
* STATE_COLLAPSED with a detentCount of 1.
*
* Throwing from a state change the user cannot avoid takes down the whole app, so clamp to the
* top-most valid detent instead. The rewritten form sheet already treats an unmapped state as a
* non-fatal case (`FORM_SHEET_UNKNOWN_DETENT_INDEX`); -1 cannot be reused here because this
* mapping already spends it on STATE_HIDDEN, and reporting the sheet as dismissed would be
* worse than reporting the nearest detent.
*/
private fun unmappedDetentIndex(
state: Int,
detentCount: Int,
): Int {
Log.w(TAG, "[RNScreens] State $state has no detent in an array of $detentCount, clamping to the top detent")
return (detentCount - 1).coerceAtLeast(0)
}

fun isStateLessEqualThan(
state: Int,
otherState: Int,
Expand Down