[go: nahoru, domu]

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/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))
+    }
 }