From 613ae1ecfe31dac7ba436ff8dc8548b9a51e960c Mon Sep 17 00:00:00 2001 From: Kristen Halper Date: Tue, 22 Nov 2022 09:33:48 -0800 Subject: [PATCH] Use JWM WindowSizeClass in WindowState (#51) * Update JWM version * Remove custom WindowSizeClass implementation * Update default width/height value to be greater than 0 * Add new window size class tests * Update dependencies * Bump version and update readme --- WindowState/README.md | 10 ++-- WindowState/dependencies.gradle | 20 ++++---- WindowState/library/build.gradle | 1 + .../dualscreen/windowstate/WindowStateTest.kt | 39 ++++++++++++++- .../dualscreen/windowstate/WindowSizeClass.kt | 30 ------------ .../dualscreen/windowstate/WindowState.kt | 21 +++++--- .../windowstate/WindowSizeClassTest.kt | 48 ------------------- WindowState/sample/build.gradle | 1 + 8 files changed, 69 insertions(+), 101 deletions(-) delete mode 100644 WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClass.kt delete mode 100644 WindowState/library/src/test/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClassTest.kt diff --git a/WindowState/README.md b/WindowState/README.md index 444d144..a8104a0 100644 --- a/WindowState/README.md +++ b/WindowState/README.md @@ -24,7 +24,7 @@ And the window size classes are measured based on Google's [Window size classes] 2. Add dependencies to the module-level **build.gradle** file (current version may be different from what's shown here). ```gradle - implementation "com.microsoft.device.dualscreen:windowstate:1.0.0-alpha06" + implementation "com.microsoft.device.dualscreen:windowstate:1.0.0-alpha07" ``` 3. Also ensure the compileSdkVersion is set to API 33 and the targetSdkVersion is set to API 32 or newer in the module-level build.gradle file. @@ -160,14 +160,14 @@ Check if the device window is in the single landscape posture, with which the de ```kotlin @Composable -fun widthSizeClass(): WindowSizeClass +fun widthSizeClass(): WindowWidthSizeClass ``` Returns the width window size class: **Compact**, **Medium**, **Expanded**, based on the width of the window. ```kotlin @Composable -fun heightSizeClass(): WindowSizeClass +fun heightSizeClass(): WindowHeightSizeClass ``` Returns the height window size class: **Compact**, **Medium**, **Expanded**, based on the height of the window. @@ -221,13 +221,13 @@ Returns whether a fold occludes content in the window. Based on the [occlusionType](https://developer.android.com/reference/androidx/window/layout/FoldingFeature#occlusionType()) field in [FoldingFeature](https://developer.android.com/reference/androidx/window/layout/FoldingFeature). ```kotlin -val windowWidthDp: Dp = 0.dp +val windowWidthDp: Dp = 1.dp ``` Returns the window width in Dp. ```kotlin -val windowHeightDp: Dp = 0.dp +val windowHeightDp: Dp = 1.dp ``` Returns the window height in Dp. diff --git a/WindowState/dependencies.gradle b/WindowState/dependencies.gradle index c1909d0..0dff7f8 100644 --- a/WindowState/dependencies.gradle +++ b/WindowState/dependencies.gradle @@ -14,11 +14,11 @@ ext { // WindowState library version code: // If you want to publish a new version, bump in one (1) the specific line(s) - windowStateVersionCode = 6 + windowStateVersionCode = 7 // WindowState library version name: // If you want to publish a new version, bump the specific line - windowStateVersionName = '1.0.0-alpha06' + windowStateVersionName = '1.0.0-alpha07' // ---------------------------------- @@ -46,15 +46,16 @@ ext { // AndroidX dependencies appCompatVersion = '1.5.1' ktxCoreVersion = '1.9.0' - windowVersion = "1.0.0" + windowVersion = "1.1.0-alpha04" androidxDependencies = [ appCompat : "androidx.appcompat:appcompat:$appCompatVersion", ktxCore : "androidx.core:core-ktx:$ktxCoreVersion", - window : "androidx.window:window:$windowVersion" + window : "androidx.window:window:$windowVersion", + windowCore : "androidx.window:window-core:$windowVersion" ] // Compose dependencies - composeVersion = "1.3.0" + composeVersion = "1.3.1" composeCompilerVersion = "1.3.2" activityComposeVersion = '1.6.1' navigationComposeVersion = "2.5.3" @@ -68,15 +69,16 @@ ext { ] // Test dependencies - androidxTestVersion = '1.4.0' - espressoVersion = "3.4.0" + androidxTestVersion = '1.5.0' + androidxTestRunnerVersion = '1.5.1' + espressoVersion = "3.5.0" junitVersion = '4.13.2' - mockitoVersion = '4.8.1' + mockitoVersion = '4.9.0' uiAutomatorVersion = "2.2.0" testDependencies = [ androidxTestCore : "androidx.test:core:$androidxTestVersion", androidxTestRules : "androidx.test:rules:$androidxTestVersion", - androidxTestRunner : "androidx.test:runner:$androidxTestVersion", + androidxTestRunner : "androidx.test:runner:$androidxTestRunnerVersion", composeUITest : "androidx.compose.ui:ui-test:$composeVersion", composeJunit : "androidx.compose.ui:ui-test-junit4:$composeVersion", composeUITestManifest : "androidx.compose.ui:ui-test-manifest:$composeVersion", diff --git a/WindowState/library/build.gradle b/WindowState/library/build.gradle index bf6b455..4e79183 100644 --- a/WindowState/library/build.gradle +++ b/WindowState/library/build.gradle @@ -67,6 +67,7 @@ dependencies { implementation androidxDependencies.ktxCore implementation androidxDependencies.appCompat implementation androidxDependencies.window + implementation androidxDependencies.windowCore implementation composeDependencies.composeUI implementation composeDependencies.composeRuntime diff --git a/WindowState/library/src/androidTest/java/com/microsoft/device/dualscreen/windowstate/WindowStateTest.kt b/WindowState/library/src/androidTest/java/com/microsoft/device/dualscreen/windowstate/WindowStateTest.kt index 63ba6b6..76d160f 100644 --- a/WindowState/library/src/androidTest/java/com/microsoft/device/dualscreen/windowstate/WindowStateTest.kt +++ b/WindowState/library/src/androidTest/java/com/microsoft/device/dualscreen/windowstate/WindowStateTest.kt @@ -11,6 +11,8 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.height import androidx.compose.ui.unit.width +import androidx.window.core.layout.WindowHeightSizeClass +import androidx.window.core.layout.WindowWidthSizeClass import org.junit.Assert.assertEquals import org.junit.Test @@ -98,8 +100,8 @@ class WindowStateTest { assertEquals(FoldState.FLAT, windowState.foldState) assertEquals(false, windowState.foldIsSeparating) assertEquals(false, windowState.foldIsOccluding) - assertEquals(0.dp, windowState.windowWidthDp) - assertEquals(0.dp, windowState.windowHeightDp) + assertEquals(1.dp, windowState.windowWidthDp) + assertEquals(1.dp, windowState.windowHeightDp) } @Test @@ -357,4 +359,37 @@ class WindowStateTest { windowState.largeScreenPane1Weight = 0.7f assertEquals(0.7f, windowState.largeScreenPane1Weight) } + + /** + * windowSizeClass tests + * ------------------------------- + */ + @Test + fun compact_window_size_class() { + // Compact width + assertEquals(WindowWidthSizeClass.COMPACT, noFoldCompact.widthSizeClass()) + + // Compact height + assertEquals(WindowHeightSizeClass.COMPACT, noFoldCompact.heightSizeClass()) + assertEquals(WindowHeightSizeClass.COMPACT, noFoldMediumWidthCompactHeight.heightSizeClass()) + } + + @Test + fun medium_window_size_class() { + // Medium width + assertEquals(WindowWidthSizeClass.MEDIUM, noFoldMediumWidthMediumHeight.widthSizeClass()) + + // Medium height + assertEquals(WindowHeightSizeClass.MEDIUM, noFoldMediumWidthMediumHeight.heightSizeClass()) + assertEquals(WindowHeightSizeClass.MEDIUM, noFoldExpandedWidthMediumHeight.heightSizeClass()) + } + + @Test + fun expanded_window_size_class() { + // Expanded width + assertEquals(WindowWidthSizeClass.EXPANDED, noFoldExpandedWidthMediumHeight.widthSizeClass()) + + // Expanded height + assertEquals(WindowHeightSizeClass.EXPANDED, noFoldLargeScreen.heightSizeClass()) + } } diff --git a/WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClass.kt b/WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClass.kt deleted file mode 100644 index c5fc19d..0000000 --- a/WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClass.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -package com.microsoft.device.dualscreen.windowstate - -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp - -enum class WindowSizeClass { COMPACT, MEDIUM, EXPANDED } - -/** - * Calculates size class for a given dimension - * - * @param dimenDp: size of dimension in Dp - * @param dimen: which dimension is being measured (width or height) - */ -fun getWindowSizeClass(dimenDp: Dp, dimen: Dimension = Dimension.WIDTH): WindowSizeClass = - when (dimen) { - Dimension.WIDTH -> getSizeClass(dimenDp, 600.dp, 840.dp) - Dimension.HEIGHT -> getSizeClass(dimenDp, 480.dp, 900.dp) - } - -private fun getSizeClass(size: Dp, medium: Dp, expanded: Dp): WindowSizeClass = when { - size < 0.dp -> throw IllegalArgumentException("Dp value cannot be negative") - size < medium -> WindowSizeClass.COMPACT - size < expanded -> WindowSizeClass.MEDIUM - else -> WindowSizeClass.EXPANDED -} diff --git a/WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowState.kt b/WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowState.kt index f81b39e..a0a7fc6 100644 --- a/WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowState.kt +++ b/WindowState/library/src/main/java/com/microsoft/device/dualscreen/windowstate/WindowState.kt @@ -17,6 +17,9 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.height import androidx.compose.ui.unit.width +import androidx.window.core.layout.WindowHeightSizeClass +import androidx.window.core.layout.WindowSizeClass +import androidx.window.core.layout.WindowWidthSizeClass /** * Data class that contains foldable and large screen information extracted from the Jetpack @@ -38,8 +41,8 @@ data class WindowState( val foldState: FoldState = FoldState.FLAT, val foldIsSeparating: Boolean = false, val foldIsOccluding: Boolean = false, - val windowWidthDp: Dp = 0.dp, - val windowHeightDp: Dp = 0.dp, + val windowWidthDp: Dp = 1.dp, + val windowHeightDp: Dp = 1.dp, ) { /** * Dp value of the width of the hinge or the folding line if it is separating, otherwise 0 @@ -143,13 +146,16 @@ data class WindowState( return windowMode == WindowMode.SINGLE_LANDSCAPE } + private val windowSizeClass + get() = WindowSizeClass.compute(dpWidth = windowWidthDp.value, dpHeight = windowHeightDp.value) + /** * Returns the size class (compact, medium, or expanded) for the window width * * @return width size class */ - fun widthSizeClass(): WindowSizeClass { - return getWindowSizeClass(windowWidthDp) + fun widthSizeClass(): WindowWidthSizeClass { + return windowSizeClass.windowWidthSizeClass } /** @@ -157,8 +163,8 @@ data class WindowState( * * @return height size class */ - fun heightSizeClass(): WindowSizeClass { - return getWindowSizeClass(windowHeightDp, Dimension.HEIGHT) + fun heightSizeClass(): WindowHeightSizeClass { + return windowSizeClass.windowHeightSizeClass } /** @@ -234,7 +240,8 @@ data class WindowState( */ private fun windowIsLarge(): Boolean { // Window is large if width size class is expanded and height size class is at least medium - val isLarge = widthSizeClass() == WindowSizeClass.EXPANDED && heightSizeClass() != WindowSizeClass.COMPACT + val isLarge = widthSizeClass() == WindowWidthSizeClass.EXPANDED && + heightSizeClass() != WindowHeightSizeClass.COMPACT // Right now we are considering large screens + foldables mutually exclusive // (which seems necessary for dualscreen apps), but we may want to think about this diff --git a/WindowState/library/src/test/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClassTest.kt b/WindowState/library/src/test/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClassTest.kt deleted file mode 100644 index 12283a8..0000000 --- a/WindowState/library/src/test/java/com/microsoft/device/dualscreen/windowstate/WindowSizeClassTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -package com.microsoft.device.dualscreen.windowstate - -import androidx.compose.ui.unit.dp -import org.junit.Assert.assertEquals -import org.junit.Test - -class WindowSizeClassTest { - @Test - fun width_returns_compact() { - assertEquals(WindowSizeClass.COMPACT, getWindowSizeClass(500.dp, Dimension.WIDTH)) - assertEquals(WindowSizeClass.COMPACT, WindowState(windowWidthDp = 500.dp).widthSizeClass()) - } - - @Test - fun width_returns_medium() { - assertEquals(WindowSizeClass.MEDIUM, getWindowSizeClass(700.dp, Dimension.WIDTH)) - assertEquals(WindowSizeClass.MEDIUM, WindowState(windowWidthDp = 700.dp).widthSizeClass()) - } - - @Test - fun width_returns_expanded() { - assertEquals(WindowSizeClass.EXPANDED, getWindowSizeClass(900.dp, Dimension.WIDTH)) - assertEquals(WindowSizeClass.EXPANDED, WindowState(windowWidthDp = 900.dp).widthSizeClass()) - } - - @Test - fun height_returns_compact() { - assertEquals(WindowSizeClass.COMPACT, getWindowSizeClass(300.dp, Dimension.HEIGHT)) - assertEquals(WindowSizeClass.COMPACT, WindowState(windowHeightDp = 300.dp).heightSizeClass()) - } - - @Test - fun height_returns_medium() { - assertEquals(WindowSizeClass.MEDIUM, getWindowSizeClass(700.dp, Dimension.HEIGHT)) - assertEquals(WindowSizeClass.MEDIUM, WindowState(windowHeightDp = 700.dp).heightSizeClass()) - } - - @Test - fun height_returns_expanded() { - assertEquals(WindowSizeClass.EXPANDED, getWindowSizeClass(1000.dp, Dimension.HEIGHT)) - assertEquals(WindowSizeClass.EXPANDED, WindowState(windowHeightDp = 1000.dp).heightSizeClass()) - } -} diff --git a/WindowState/sample/build.gradle b/WindowState/sample/build.gradle index 161134f..d0ef8cd 100644 --- a/WindowState/sample/build.gradle +++ b/WindowState/sample/build.gradle @@ -56,6 +56,7 @@ dependencies { implementation androidxDependencies.ktxCore implementation androidxDependencies.appCompat implementation androidxDependencies.window + implementation androidxDependencies.windowCore implementation composeDependencies.composeUI implementation composeDependencies.composeMaterial implementation composeDependencies.composeUITooling