Skip to content
Merged
Show file tree
Hide file tree
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
124 changes: 53 additions & 71 deletions android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
import com.swmansion.rnscreens.bottomsheet.DimmingFragment
import com.swmansion.rnscreens.bottomsheet.SheetUtils
import com.swmansion.rnscreens.bottomsheet.isSheetFitToContents
import com.swmansion.rnscreens.bottomsheet.useSingleDetent
import com.swmansion.rnscreens.bottomsheet.useThreeDetents
import com.swmansion.rnscreens.bottomsheet.useTwoDetents
import com.swmansion.rnscreens.bottomsheet.usesFormSheetPresentation
import com.swmansion.rnscreens.ext.recycle
import com.swmansion.rnscreens.utils.DeviceUtils

Expand Down Expand Up @@ -157,14 +162,15 @@ class ScreenStackFragment :
screen.notifySheetDetentChange(
SheetUtils.detentIndexFromSheetState(
lastStableState,
screen.sheetDetents.count()
), true
screen.sheetDetents.count(),
),
true,
)
} else if (newState == BottomSheetBehavior.STATE_DRAGGING) {
screen.notifySheetDetentChange(
SheetUtils.detentIndexFromSheetState(
lastStableState,
screen.sheetDetents.count()
screen.sheetDetents.count(),
),
false,
)
Expand Down Expand Up @@ -223,7 +229,7 @@ class ScreenStackFragment :
LinearLayout.LayoutParams.MATCH_PARENT,
).apply {
behavior =
if (screen.stackPresentation == Screen.StackPresentation.FORM_SHEET) {
if (screen.usesFormSheetPresentation()) {
createAndConfigureBottomSheetBehaviour()
} else if (isToolbarTranslucent) {
null
Expand All @@ -232,7 +238,7 @@ class ScreenStackFragment :
}
}

if (screen.stackPresentation == Screen.StackPresentation.FORM_SHEET) {
if (screen.usesFormSheetPresentation()) {
screen.clipToOutline = true
// TODO(@kkafar): without this line there is no drawable / outline & nothing shows...? Determine what's going on here
attachShapeToScreen(screen)
Expand All @@ -241,7 +247,7 @@ class ScreenStackFragment :

coordinatorLayout.addView(screen.recycle())

if (screen.stackPresentation != Screen.StackPresentation.FORM_SHEET) {
if (!screen.usesFormSheetPresentation()) {
appBarLayout =
context?.let { AppBarLayout(it) }?.apply {
// By default AppBarLayout will have a background color set but since we cover the whole layout
Expand Down Expand Up @@ -348,52 +354,39 @@ class ScreenStackFragment :
return when (keyboardState) {
is KeyboardNotVisible -> {
when (screen.sheetDetents.count()) {
1 -> if (screen.sheetDetents.first() == Screen.SHEET_FIT_TO_CONTENTS) {
behavior.apply {
state = BottomSheetBehavior.STATE_EXPANDED
screen.contentWrapper.get()?.let {
maxHeight = it.height
}
skipCollapsed = true
isFitToContents = true
}
} else {
1 ->
behavior.apply {
state = BottomSheetBehavior.STATE_EXPANDED
skipCollapsed = true
isFitToContents = true
maxHeight = (screen.sheetDetents.first() * containerHeight).toInt()
val height =
if (screen.isSheetFitToContents()) {
screen.contentWrapper.get()?.height
} else {
(screen.sheetDetents.first() * containerHeight).toInt()
}
useSingleDetent(height = height)
}
}

2 ->
behavior.apply {
behavior.useTwoDetents(
state =
SheetUtils.sheetStateFromDetentIndex(
screen.sheetInitialDetentIndex,
screen.sheetDetents.count(),
)
skipCollapsed = false
isFitToContents = true
peekHeight = (screen.sheetDetents[0] * containerHeight).toInt()
maxHeight = (screen.sheetDetents[1] * containerHeight).toInt()
}
),
firstHeight = (screen.sheetDetents[0] * containerHeight).toInt(),
secondHeight = (screen.sheetDetents[1] * containerHeight).toInt(),
)

3 ->
behavior.apply {
behavior.useThreeDetents(
state =
SheetUtils.sheetStateFromDetentIndex(
screen.sheetInitialDetentIndex,
screen.sheetDetents.count(),
)
skipCollapsed = false
isFitToContents = false
peekHeight = (screen.sheetDetents[0] * containerHeight).toInt()
expandedOffset =
((1 - screen.sheetDetents[2]) * containerHeight).toInt()
halfExpandedRatio =
(screen.sheetDetents[1] / screen.sheetDetents[2]).toFloat()
}
),
firstHeight = (screen.sheetDetents[0] * containerHeight).toInt(),
halfExpandedRatio = (screen.sheetDetents[1] / screen.sheetDetents[2]).toFloat(),
expandedOffsetFromTop = ((1 - screen.sheetDetents[2]) * containerHeight).toInt(),
)

else -> throw IllegalStateException(
"[RNScreens] Invalid detent count ${screen.sheetDetents.count()}. Expected at most 3.",
Expand All @@ -411,27 +404,24 @@ class ScreenStackFragment :
when (screen.sheetDetents.count()) {
1 ->
behavior.apply {
state = BottomSheetBehavior.STATE_EXPANDED
skipCollapsed = true
isFitToContents = true
maxHeight = newMaxHeight
useSingleDetent(height = newMaxHeight)
addBottomSheetCallback(keyboardSheetCallback)
}

2 ->
behavior.apply {
state = BottomSheetBehavior.STATE_EXPANDED
skipCollapsed = false
isFitToContents = true
maxHeight = newMaxHeight
useTwoDetents(
state = BottomSheetBehavior.STATE_EXPANDED,
secondHeight = newMaxHeight,
)
addBottomSheetCallback(keyboardSheetCallback)
}

3 ->
behavior.apply {
state = BottomSheetBehavior.STATE_EXPANDED
skipCollapsed = false
isFitToContents = false
useThreeDetents(
state = BottomSheetBehavior.STATE_EXPANDED,
)
maxHeight = newMaxHeight
addBottomSheetCallback(keyboardSheetCallback)
}
Expand All @@ -450,30 +440,23 @@ class ScreenStackFragment :
behavior.removeBottomSheetCallback(keyboardSheetCallback)
when (screen.sheetDetents.count()) {
1 ->
behavior.apply {
skipCollapsed = true
isFitToContents = true
maxHeight = (screen.sheetDetents.first() * containerHeight).toInt()
}
behavior.useSingleDetent(
height = (screen.sheetDetents.first() * containerHeight).toInt(),
forceExpandedState = false,
)

2 ->
behavior.apply {
skipCollapsed = false
isFitToContents = true
peekHeight = (screen.sheetDetents[0] * containerHeight).toInt()
maxHeight = (screen.sheetDetents[1] * containerHeight).toInt()
}
behavior.useTwoDetents(
firstHeight = (screen.sheetDetents[0] * containerHeight).toInt(),
secondHeight = (screen.sheetDetents[1] * containerHeight).toInt(),
)

3 ->
behavior.apply {
skipCollapsed = false
isFitToContents = false
peekHeight = (screen.sheetDetents[0] * containerHeight).toInt()
expandedOffset =
((1 - screen.sheetDetents[2]) * containerHeight).toInt()
halfExpandedRatio =
(screen.sheetDetents[1] / screen.sheetDetents[2]).toFloat()
}
behavior.useThreeDetents(
firstHeight = (screen.sheetDetents[0] * containerHeight).toInt(),
halfExpandedRatio = (screen.sheetDetents[1] / screen.sheetDetents[2]).toFloat(),
expandedOffsetFromTop = ((1 - screen.sheetDetents[2]) * containerHeight).toInt(),
)

else -> throw IllegalStateException(
"[RNScreens] Invalid detent count ${screen.sheetDetents.count()}. Expected at most 3.",
Expand Down Expand Up @@ -595,8 +578,7 @@ class ScreenStackFragment :
// ) : CoordinatorLayout(context), ReactCompoundViewGroup, ReactHitSlopView {
) : CoordinatorLayout(context),
ReactPointerEventsView {
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets =
super.onApplyWindowInsets(insets)
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets = super.onApplyWindowInsets(insets)

private val animationListener: Animation.AnimationListener =
object : Animation.AnimationListener {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.swmansion.rnscreens.bottomsheet

import android.view.View
import com.google.android.material.bottomsheet.BottomSheetBehavior

internal fun <T : View> BottomSheetBehavior<T>.useSingleDetent(height: Int? = null, forceExpandedState: Boolean = true): BottomSheetBehavior<T> {
this.skipCollapsed = true
this.isFitToContents = true
if (forceExpandedState) {
this.state = BottomSheetBehavior.STATE_EXPANDED
}
height?.let { maxHeight = height }
return this
}

internal fun <T : View> BottomSheetBehavior<T>.useTwoDetents(
@BottomSheetBehavior.StableState state: Int? = null,
firstHeight: Int? = null,
secondHeight: Int? = null
Comment on lines +18 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to stick with the original "peekHeight" and "maxHeight"?
Same applies to useSingleDetent and useThreeDetents.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was to abstract the BottomSheetBehavior properties away as much as possible, because peekHeight is not the "first detent heightandmaxHeightis notsecondHeight` in general. They serve these functions only when other properties are set appropriately.

I've yet failed to abstract it away from useThreeDetents, because situation is a little bit more complicated there & requires another refactor, which will come in the future.

): BottomSheetBehavior<T> {
skipCollapsed = false
isFitToContents = true
state?.let { this.state = state }
firstHeight?.let { peekHeight = firstHeight }
secondHeight?.let { maxHeight = secondHeight }
return this
}

internal fun <T : View> BottomSheetBehavior<T>.useThreeDetents(
@BottomSheetBehavior.StableState state: Int? = null,
firstHeight: Int? = null,
halfExpandedRatio: Float? = null,
expandedOffsetFromTop: Int? = null
): BottomSheetBehavior<T> {
skipCollapsed = false
isFitToContents = false
state?.let { this.state = state }
firstHeight?.let { this.peekHeight = firstHeight }
halfExpandedRatio?.let { this.halfExpandedRatio = halfExpandedRatio }
expandedOffsetFromTop?.let { this.expandedOffset = expandedOffsetFromTop }
return this
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPS
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HALF_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
import com.swmansion.rnscreens.Screen

object SheetUtils {
/**
Expand Down Expand Up @@ -125,3 +126,10 @@ object SheetUtils {
return false
}
}

fun Screen.isSheetFitToContents(): Boolean =
stackPresentation === Screen.StackPresentation.FORM_SHEET &&
sheetDetents.count() == 1 &&
sheetDetents.first() == Screen.SHEET_FIT_TO_CONTENTS

fun Screen.usesFormSheetPresentation(): Boolean = stackPresentation === Screen.StackPresentation.FORM_SHEET