Add positional thresholds to BottomDrawerLayout
This CL introduces a positional thresholds parameter in stateDraggable.
Thresholds are specified as a lambda that takes a pair of anchors and
returns a value between them. The order of the anchors matters since it
indicates the drag direction (i.e. from the first anchor to the second).
Two default threshold constructors are provided: fixed and fractional.
BottomDrawerLayout uses a fixed threshold of 56dp or an app bar height.
Bug: 158805662
Bug: 158806527
Test: Ran DrawerTest and SwitchTest
Relnote: "Added thresholds param in stateDraggable to specify thresholds
between anchors. This was used to set a 56dp threshold in bottom drawer.
Also BottomDrawerLayout now uses a separate BottomDrawerState enum."
Change-Id: I533fad3d3bf9b95f702156e321aa15a84e81819b
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerScreenshotTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerScreenshotTest.kt
index 5a21b05..57d6209 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerScreenshotTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerScreenshotTest.kt
@@ -48,7 +48,7 @@
@get:Rule
val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL)
- private fun ComposeTestRule.setBottomDrawer(drawerState: DrawerState) {
+ private fun ComposeTestRule.setBottomDrawer(drawerState: BottomDrawerState) {
setMaterialContent {
Box(Modifier.size(10.dp, 100.dp).testTag("container")) {
BottomDrawerLayout(
@@ -76,7 +76,7 @@
@Test
fun bottomDrawer_closed() {
- composeTestRule.setBottomDrawer(DrawerState.Closed)
+ composeTestRule.setBottomDrawer(BottomDrawerState.Closed)
assertScreenshotAgainstGolden("bottomDrawer_closed")
}
@@ -88,7 +88,7 @@
@Test
fun bottomDrawer_opened() {
- composeTestRule.setBottomDrawer(DrawerState.Opened)
+ composeTestRule.setBottomDrawer(BottomDrawerState.Opened)
assertScreenshotAgainstGolden("bottomDrawer_opened")
}
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt
index 510382b..1e6e627 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt
@@ -31,10 +31,12 @@
import androidx.ui.graphics.Color
import androidx.ui.layout.fillMaxSize
import androidx.ui.layout.rtl
+import androidx.ui.test.GestureScope
import androidx.ui.test.assertIsEqualTo
import androidx.ui.test.assertLeftPositionInRootIsEqualTo
import androidx.ui.test.assertTopPositionInRootIsEqualTo
import androidx.ui.test.assertWidthIsEqualTo
+import androidx.ui.test.center
import androidx.ui.test.createComposeRule
import androidx.ui.test.doGesture
import androidx.ui.test.findByTag
@@ -42,6 +44,7 @@
import androidx.ui.test.runOnIdleCompose
import androidx.ui.test.runOnUiThread
import androidx.ui.test.sendClick
+import androidx.ui.test.sendSwipe
import androidx.ui.test.sendSwipeDown
import androidx.ui.test.sendSwipeLeft
import androidx.ui.test.sendSwipeRight
@@ -110,7 +113,7 @@
@Test
fun bottomDrawer_testOffset_whenOpened() {
composeTestRule.setMaterialContent {
- BottomDrawerLayout(DrawerState.Opened, {}, drawerContent = {
+ BottomDrawerLayout(BottomDrawerState.Opened, {}, drawerContent = {
Box(Modifier.fillMaxSize().testTag("content"))
}, bodyContent = emptyContent())
}
@@ -126,7 +129,7 @@
fun bottomDrawer_testOffset_whenClosed() {
var position: Offset? = null
composeTestRule.setMaterialContent {
- BottomDrawerLayout(DrawerState.Closed, {}, drawerContent = {
+ BottomDrawerLayout(BottomDrawerState.Closed, {}, drawerContent = {
Box(Modifier.fillMaxSize().onPositioned { coords: LayoutCoordinates ->
position = coords.localToRoot(Offset.Zero)
})
@@ -240,7 +243,7 @@
var openedHeight: Int? = null
var openedLatch: CountDownLatch? = null
var closedLatch: CountDownLatch? = CountDownLatch(1)
- val drawerState = mutableStateOf(DrawerState.Closed)
+ val drawerState = mutableStateOf(BottomDrawerState.Closed)
composeTestRule.setMaterialContent {
BottomDrawerLayout(drawerState.value, { drawerState.value = it },
drawerContent = {
@@ -269,7 +272,7 @@
// When the drawer state is set to Opened
openedLatch = CountDownLatch(1)
runOnIdleCompose {
- drawerState.value = DrawerState.Opened
+ drawerState.value = BottomDrawerState.Opened
}
// Then the drawer should be opened
assertThat(openedLatch.await(5, TimeUnit.SECONDS)).isTrue()
@@ -277,7 +280,7 @@
// When the drawer state is set to Closed
closedLatch = CountDownLatch(1)
runOnIdleCompose {
- drawerState.value = DrawerState.Closed
+ drawerState.value = BottomDrawerState.Closed
}
// Then the drawer should be closed
assertThat(closedLatch.await(5, TimeUnit.SECONDS)).isTrue()
@@ -287,7 +290,7 @@
fun bottomDrawer_bodyContent_clickable() {
var drawerClicks = 0
var bodyClicks = 0
- val drawerState = mutableStateOf(DrawerState.Closed)
+ val drawerState = mutableStateOf(BottomDrawerState.Closed)
composeTestRule.setMaterialContent {
// emulate click on the screen
BottomDrawerLayout(drawerState.value, { drawerState.value = it },
@@ -314,7 +317,7 @@
}
runOnUiThread {
- drawerState.value = DrawerState.Opened
+ drawerState.value = BottomDrawerState.Opened
}
sleep(100) // TODO(147586311): remove this sleep when opening the drawer triggers a wait
@@ -394,7 +397,7 @@
@Test
fun bottomDrawer_openBySwipe() {
- val drawerState = mutableStateOf(DrawerState.Closed)
+ val drawerState = mutableStateOf(BottomDrawerState.Closed)
composeTestRule.setMaterialContent {
// emulate click on the screen
Box(Modifier.testTag("Drawer")) {
@@ -412,14 +415,96 @@
.doGesture { sendSwipeUp() }
runOnIdleCompose {
- assertThat(drawerState.value).isEqualTo(DrawerState.Opened)
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Expanded)
}
findByTag("Drawer")
.doGesture { sendSwipeDown() }
runOnIdleCompose {
- assertThat(drawerState.value).isEqualTo(DrawerState.Closed)
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Closed)
}
}
+
+ @Test
+ fun bottomDrawer_openBySwipe_thresholds() {
+ val drawerState = mutableStateOf(BottomDrawerState.Closed)
+ composeTestRule.setMaterialContent {
+ // emulate click on the screen
+ Box(Modifier.testTag("Drawer")) {
+ BottomDrawerLayout(drawerState.value, { drawerState.value = it },
+ drawerContent = {
+ Box(Modifier.fillMaxSize().drawBackground(Color.Magenta))
+ },
+ bodyContent = {
+ Box(Modifier.fillMaxSize().drawBackground(Color.Red))
+ })
+ }
+ }
+ val threshold = with (composeTestRule.density) { BottomDrawerThreshold.toPx() }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeUpBy(threshold / 2) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Closed)
+ }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeUpBy(threshold) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Opened)
+ }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeUpBy(threshold / 2) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Opened)
+ }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeUpBy(threshold) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Expanded)
+ }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeDownBy(threshold / 2) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Expanded)
+ }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeDownBy(threshold) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Opened)
+ }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeDownBy(threshold / 2) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Opened)
+ }
+
+ findByTag("Drawer")
+ .doGesture { sendSwipeDownBy(threshold) }
+
+ runOnIdleCompose {
+ assertThat(drawerState.value).isEqualTo(BottomDrawerState.Closed)
+ }
+ }
+
+ private fun GestureScope.sendSwipeUpBy(offset: Float) {
+ sendSwipe(center, center.copy(y = center.y - offset))
+ }
+
+ private fun GestureScope.sendSwipeDownBy(offset: Float) {
+ sendSwipe(center, center.copy(y = center.y + offset))
+ }
}