Skip to content

Commit

Permalink
Added Functionality to the BottomSheet with TestCases: Enable/Disable…
Browse files Browse the repository at this point in the history
… Swipe Down Dismiss with more intuitive accessibility controls (#490)

* BottomSheet added functionality to not get dismissed when swiped down

* added semantics check

* To run test on pipeline

* applied enableSwipeDismiss check on dismiss

* Improved semantics for talkback actions

* Added option for accesibility users to have a way to bring bottomSheet in case it's hidden

* localized some string constants

* moved string under UI labels

* typo

---------

Co-authored-by: Anubhav Agrawal <[email protected]>
  • Loading branch information
Anubhvv and Anubhav Agrawal authored Sep 1, 2023
1 parent 13fb64d commit 240ec46
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.junit.runners.Suite
V2AvatarGroupActivityUITest::class,
V2BadgeActivityUITest::class,
V2BottomDrawerUITest::class,
V2BottomSheetActivityUITest::class,
V2ButtonsActivityUITest::class,
V2CardNudgeActivityUITest::class,
V2CardUITest::class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.microsoft.fluentuidemo.demos

import androidx.compose.ui.test.onNodeWithTag
import org.junit.Before
import com.microsoft.fluentuidemo.BaseTest
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeDown
import com.microsoft.fluentui.tokenized.bottomsheet.BOTTOMSHEET_CONTENT_TAG
import com.microsoft.fluentui.tokenized.bottomsheet.BOTTOMSHEET_HANDLE_TAG
import com.microsoft.fluentui.tokenized.bottomsheet.BOTTOMSHEET_SCRIM_TAG
import org.junit.Test


class V2BottomSheetActivityUITest(): BaseTest(){
@Before
fun initialize() {
BaseTest().launchActivity(V2BottomSheetActivity::class.java)
}
//Tag use for testing
private val bottomSheetHandle = composeTestRule.onNodeWithTag(BOTTOMSHEET_HANDLE_TAG, useUnmergedTree = true)
private val bottomSheetContent = composeTestRule.onNodeWithTag(BOTTOMSHEET_CONTENT_TAG, useUnmergedTree = true)
private val bottomSheetScrim = composeTestRule.onNodeWithTag(BOTTOMSHEET_SCRIM_TAG, useUnmergedTree = true)

private fun openCheckForBottomSheet() {
composeTestRule.waitForIdle()
bottomSheetHandle.assertExists()
bottomSheetScrim.assertExists()
bottomSheetContent.assertExists()
}
@Test
fun testBottomSheetDismissDisabledSwipeDown() {
composeTestRule.onNodeWithTag(BOTTOM_SHEET_ENABLE_SWIPE_DISMISS_TEST_TAG, useUnmergedTree = true).performClick()
//SwipeDown on bottomSheetContent should close it.
bottomSheetContent.performTouchInput {
swipeDown()
}
bottomSheetHandle.performTouchInput {
swipeDown()
}
openCheckForBottomSheet()
}



}
3 changes: 2 additions & 1 deletion FluentUI.Demo/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
<activity android:name="com.microsoft.fluentuidemo.demos.V2BasicChipActivity" />
<activity android:name="com.microsoft.fluentuidemo.demos.V2BasicControlsActivity" />
<activity android:name="com.microsoft.fluentuidemo.demos.V2BottomDrawerActivity" />
<activity android:name="com.microsoft.fluentuidemo.demos.V2BottomSheetActivity" />
<activity android:name="com.microsoft.fluentuidemo.demos.V2BottomSheetActivity"
android:configChanges="orientation|keyboardHidden|screenSize"/>
<activity android:name="com.microsoft.fluentuidemo.demos.V2CardActivity" />
<activity android:name="com.microsoft.fluentuidemo.demos.V2CardNudgeActivity" />
<activity android:name="com.microsoft.fluentuidemo.demos.V2CitationActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
Expand All @@ -68,6 +70,7 @@ import com.microsoft.fluentuidemo.util.createPersonaList
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

const val BOTTOM_SHEET_ENABLE_SWIPE_DISMISS_TEST_TAG = "enableSwipeDismiss"
class V2BottomSheetActivity : V2DemoActivity() {
init {
setupActivity(this)
Expand All @@ -87,6 +90,8 @@ class V2BottomSheetActivity : V2DemoActivity() {

@Composable
private fun CreateActivityUI() {
var enableSwipeDismiss by remember { mutableStateOf(true) }

var showHandleState by remember { mutableStateOf(true) }

var expandableState by remember { mutableStateOf(true) }
Expand Down Expand Up @@ -137,7 +142,8 @@ private fun CreateActivityUI() {
peekHeight = peekHeightState,
showHandle = showHandleState,
sheetState = bottomSheetState,
slideOver = slideOverState
slideOver = slideOverState,
enableSwipeDismiss = enableSwipeDismiss
) {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
Expand Down Expand Up @@ -265,7 +271,26 @@ private fun CreateActivityUI() {
onValueChange = { slideOverState = it }
)
}

Row(
horizontalArrangement = Arrangement.spacedBy(30.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
BasicText(
text = stringResource(id =R.string.bottom_sheet_text_enable_swipe_dismiss),
modifier = Modifier.weight(1F),
style = TextStyle(
color = FluentTheme.aliasTokens.neutralForegroundColor[FluentAliasTokens.NeutralForegroundColorTokens.Foreground1].value(
themeMode = ThemeMode.Auto
)
)
)
ToggleSwitch(
modifier = Modifier.testTag(BOTTOM_SHEET_ENABLE_SWIPE_DISMISS_TEST_TAG),
checkedState = enableSwipeDismiss,
onValueChange = { enableSwipeDismiss = it }
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
Expand Down
1 change: 1 addition & 0 deletions FluentUI.Demo/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
<!--UI Labels -->
<string name="bottom_sheet">BottomSheet</string>
<string name="bottom_sheet_dialog">BottomSheetDialog</string>
<string name ="bottom_sheet_text_enable_swipe_dismiss">Enable Swipe Down to Dismiss</string>
<!-- Text for buttons -->
<string name="bottom_sheet_with_single_line_items">Show with single line items</string>
<string name="bottom_sheet_with_double_line_items">Show with double line items</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -891,4 +891,36 @@ val <T> SwipeableState<T>.PostDownNestedScrollConnection: NestedScrollConnection

private fun Offset.toFloat(): Float = this.y
}
val <T> SwipeableState<T>.NonDismissiblePostDownNestedScrollConnection: NestedScrollConnection
get() = object : NestedScrollConnection {

override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
val delta = available.toFloat()
return if (delta < 0 && source == NestedScrollSource.Drag) {
performDrag(delta).toOffset()
} else {
Offset.Zero
}
}
override fun onPostScroll(
consumed: Offset,
available: Offset,
source: NestedScrollSource
): Offset {
return if (source == NestedScrollSource.Drag && available.toFloat() < 0) {
performDrag(available.toFloat()).toOffset()
} else {
Offset.Zero
}
}

override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
performFling(velocity = Offset(available.x, available.y).toFloat())
return available
}

private fun Float.toOffset(): Offset = Offset(0f, this)

private fun Offset.toFloat(): Float = this.y
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -179,9 +180,9 @@ fun rememberBottomSheetState(
}

//Tag use for testing
private const val BOTTOMSHEET_HANDLE_TAG = "Fluent Bottom Sheet Handle"
private const val BOTTOMSHEET_CONTENT_TAG = "Fluent Bottom Sheet Content"
private const val BOTTOMSHEET_SCRIM_TAG = "Fluent Bottom Sheet Scrim"
const val BOTTOMSHEET_HANDLE_TAG = "Fluent Bottom Sheet Handle"
const val BOTTOMSHEET_CONTENT_TAG = "Fluent Bottom Sheet Content"
const val BOTTOMSHEET_SCRIM_TAG = "Fluent Bottom Sheet Scrim"

private const val BottomSheetOpenFraction = 0.5f

Expand Down Expand Up @@ -222,6 +223,7 @@ fun BottomSheet(
scrimVisible: Boolean = true,
showHandle: Boolean = true,
slideOver: Boolean = true,
enableSwipeDismiss: Boolean = false,
bottomSheetTokens: BottomSheetTokens? = null,
content: @Composable () -> Unit
) {
Expand Down Expand Up @@ -250,7 +252,20 @@ fun BottomSheet(
val sheetHeightState =
remember(sheetContent.hashCode()) { mutableStateOf<Float?>(null) }

Box(Modifier.fillMaxSize()) {
Box(
Modifier
.fillMaxSize()
.semantics {
if (!sheetState.isVisible) {
expand {
if (sheetState.confirmStateChange(BottomSheetValue.Shown)) {
scope.launch { sheetState.show() }
}
true
}
}
}
) {
content()
if (slideOver) {
Scrim(
Expand Down Expand Up @@ -284,7 +299,12 @@ fun BottomSheet(
Box(
Modifier
.fillMaxWidth()
.nestedScroll(if (slideOver) sheetState.PreUpPostDownNestedScrollConnection else sheetState.PostDownNestedScrollConnection)
.nestedScroll(
if(!enableSwipeDismiss && sheetState.offset.value != null && sheetState.offset.value!! >= (fullHeight - dpToPx(peekHeight) ) )
sheetState.NonDismissiblePostDownNestedScrollConnection
else if (slideOver) sheetState.PreUpPostDownNestedScrollConnection
else sheetState.PostDownNestedScrollConnection
)
.offset {
val y = if (sheetState.anchors.isEmpty()) {
// if we don't know our anchors yet, render the sheet as hidden
Expand Down Expand Up @@ -328,11 +348,13 @@ fun BottomSheet(
.background(sheetBackgroundColor)
.semantics(mergeDescendants = true) {
if (sheetState.isVisible) {
dismiss {
if (sheetState.confirmStateChange(BottomSheetValue.Hidden)) {
scope.launch { sheetState.hide() }
if(enableSwipeDismiss) {
dismiss {
if (sheetState.confirmStateChange(BottomSheetValue.Hidden)) {
scope.launch { sheetState.hide() }
}
true
}
true
}
if (sheetState.currentValue == BottomSheetValue.Shown) {
expand {
Expand Down Expand Up @@ -363,13 +385,23 @@ fun BottomSheet(
.draggable(
orientation = Orientation.Vertical,
state = rememberDraggableState { delta ->
sheetState.performDrag(delta)
if(!enableSwipeDismiss && sheetState.offset.value != null && sheetState.offset.value!! >= (fullHeight - dpToPx(peekHeight) ) ){
if(delta<0){
sheetState.performDrag(delta)
}
}
else sheetState.performDrag(delta)
},
onDragStopped = { velocity ->
launch {
sheetState.performFling(velocity)
if (!sheetState.isVisible) {
scope.launch { sheetState.hide() }
if(enableSwipeDismiss) {
scope.launch { sheetState.hide() }
}
else {
scope.launch { sheetState.show() }
}
}
}
},
Expand Down

0 comments on commit 240ec46

Please sign in to comment.