From 98139d1250ba6a8def7a37b122cb8b3c0411fe90 Mon Sep 17 00:00:00 2001 From: Alex Vanyo Date: Fri, 5 Aug 2022 16:05:24 -0700 Subject: [PATCH] Expose fold-aware entry points only --- adaptive/api/current.api | 16 +- .../google/accompanist/adaptive/TwoPane.kt | 233 ++++++++++--- .../accompanist/adaptive/TwoPaneTest.kt | 309 ++++++++++-------- .../sample/adaptive/BasicTwoPaneSample.kt | 14 +- 4 files changed, 373 insertions(+), 199 deletions(-) diff --git a/adaptive/api/current.api b/adaptive/api/current.api index 8bfbffcb0..9a14c8afd 100644 --- a/adaptive/api/current.api +++ b/adaptive/api/current.api @@ -10,17 +10,17 @@ package com.google.accompanist.adaptive { } public final class TwoPaneKt { - method public static com.google.accompanist.adaptive.TwoPaneStrategy FixedOffsetHorizontalTwoPaneStrategy(float splitOffset, boolean offsetFromStart, optional float gapWidth); - method public static com.google.accompanist.adaptive.TwoPaneStrategy FixedOffsetVerticalTwoPaneStrategy(float splitOffset, boolean offsetFromTop, optional float gapHeight); - method public static com.google.accompanist.adaptive.TwoPaneStrategy FractionHorizontalTwoPaneStrategy(float splitFraction, optional float gapWidth); - method public static com.google.accompanist.adaptive.TwoPaneStrategy FractionVerticalTwoPaneStrategy(float splitFraction, optional float gapHeight); - method public static com.google.accompanist.adaptive.TwoPaneStrategy HorizontalTwoPaneStrategy(com.google.accompanist.adaptive.TwoPaneStrategy fallbackStrategy, com.google.accompanist.adaptive.WindowGeometry windowGeometry); + method public static com.google.accompanist.adaptive.TwoPaneStrategy HorizontalTwoPaneStrategy(com.google.accompanist.adaptive.WindowGeometry windowGeometry, com.google.accompanist.adaptive.TwoPaneStrategy defaultStrategy); + method public static com.google.accompanist.adaptive.TwoPaneStrategy HorizontalTwoPaneStrategy(com.google.accompanist.adaptive.WindowGeometry windowGeometry, float splitFraction, optional float gapWidth); + method public static com.google.accompanist.adaptive.TwoPaneStrategy HorizontalTwoPaneStrategy(com.google.accompanist.adaptive.WindowGeometry windowGeometry, float splitOffset, boolean offsetFromStart, optional float gapWidth); method @androidx.compose.runtime.Composable public static void TwoPane(kotlin.jvm.functions.Function0 first, kotlin.jvm.functions.Function0 second, com.google.accompanist.adaptive.TwoPaneStrategy strategy, optional androidx.compose.ui.Modifier modifier); - method public static com.google.accompanist.adaptive.TwoPaneStrategy TwoPaneStrategy(com.google.accompanist.adaptive.TwoPaneStrategy fallbackStrategy, com.google.accompanist.adaptive.WindowGeometry windowGeometry); - method public static com.google.accompanist.adaptive.TwoPaneStrategy VerticalTwoPaneStrategy(com.google.accompanist.adaptive.TwoPaneStrategy fallbackStrategy, com.google.accompanist.adaptive.WindowGeometry windowGeometry); + method public static com.google.accompanist.adaptive.TwoPaneStrategy TwoPaneStrategy(com.google.accompanist.adaptive.WindowGeometry windowGeometry, com.google.accompanist.adaptive.TwoPaneStrategy defaultStrategy); + method public static com.google.accompanist.adaptive.TwoPaneStrategy VerticalTwoPaneStrategy(com.google.accompanist.adaptive.WindowGeometry windowGeometry, com.google.accompanist.adaptive.TwoPaneStrategy defaultStrategy); + method public static com.google.accompanist.adaptive.TwoPaneStrategy VerticalTwoPaneStrategy(com.google.accompanist.adaptive.WindowGeometry windowGeometry, float splitFraction, optional float gapHeight); + method public static com.google.accompanist.adaptive.TwoPaneStrategy VerticalTwoPaneStrategy(com.google.accompanist.adaptive.WindowGeometry windowGeometry, float splitOffset, boolean offsetFromTop, optional float gapHeight); } - @androidx.compose.runtime.Stable public fun interface TwoPaneStrategy { + public fun interface TwoPaneStrategy { method public com.google.accompanist.adaptive.SplitResult calculateSplitResult(androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.layout.LayoutCoordinates layoutCoordinates); } diff --git a/adaptive/src/main/java/com/google/accompanist/adaptive/TwoPane.kt b/adaptive/src/main/java/com/google/accompanist/adaptive/TwoPane.kt index c80abd505..c049a0100 100644 --- a/adaptive/src/main/java/com/google/accompanist/adaptive/TwoPane.kt +++ b/adaptive/src/main/java/com/google/accompanist/adaptive/TwoPane.kt @@ -19,7 +19,6 @@ package com.google.accompanist.adaptive import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.runtime.Composable -import androidx.compose.runtime.Stable import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect @@ -64,7 +63,7 @@ import kotlin.math.roundToInt */ @OptIn(ExperimentalComposeUiApi::class) @Composable -fun TwoPane( +public fun TwoPane( first: @Composable () -> Unit, second: @Composable () -> Unit, strategy: TwoPaneStrategy, @@ -144,12 +143,32 @@ fun TwoPane( } } +/** + * Returns the specification for where to place a split in [TwoPane] as a result of + * [TwoPaneStrategy.calculateSplitResult] + */ +public class SplitResult( + + /** + * Whether the split is vertical or horizontal + */ + public val isHorizontalSplit: Boolean, + + /** + * The bounds that are nether a `start` pane or an `end` pane, but a separation between those + * two. In case width or height is 0 - it means that the gap itself is a 0 width/height, but the + * place within the layout is still defined. + * + * The [gapBounds] should be defined in local bounds to the [TwoPane]. + */ + public val gapBounds: Rect, +) + /** * A strategy for configuring the [TwoPane] component, that is responsible for the meta-data * corresponding to the arrangement of the two panes of the layout. */ -@Stable -fun interface TwoPaneStrategy { +public fun interface TwoPaneStrategy { /** * Calculates the split result in local bounds of the [TwoPane]. * @@ -157,7 +176,7 @@ fun interface TwoPaneStrategy { * @param layoutDirection the [LayoutDirection] for measuring and laying out * @param layoutCoordinates the [LayoutCoordinates] of the [TwoPane] */ - fun calculateSplitResult( + public fun calculateSplitResult( density: Density, layoutDirection: LayoutDirection, layoutCoordinates: LayoutCoordinates @@ -165,52 +184,184 @@ fun interface TwoPaneStrategy { } /** - * Returns the specification for where to place a split in [TwoPane] as a result of - * [TwoPaneStrategy.calculateSplitResult] + * A strategy for configuring the [TwoPane] component, that is responsible for the meta-data + * corresponding to the arrangement of the two panes of the layout. + * + * This strategy can be conditional: If `null` is returned from [calculateSplitResult], then this + * strategy did not produce a split result to use, and a different strategy should be used. */ -class SplitResult( - +private fun interface ConditionalTwoPaneStrategy { /** - * Whether the split is vertical or horizontal - */ - val isHorizontalSplit: Boolean, - - /** - * The bounds that are nether a `start` pane or an `end` pane, but a separation between those - * two. In case width or height is 0 - it means that the gap itself is a 0 width/height, but the - * place within the layout is still defined. + * Calculates the split result in local bounds of the [TwoPane], or `null` if this strategy + * does not apply. * - * The [gapBounds] should be defined in local bounds to the [TwoPane]. + * @param density the [Density] for measuring and laying out + * @param layoutDirection the [LayoutDirection] for measuring and laying out + * @param layoutCoordinates the [LayoutCoordinates] of the [TwoPane] */ - val gapBounds: Rect, -) + public fun calculateSplitResult( + density: Density, + layoutDirection: LayoutDirection, + layoutCoordinates: LayoutCoordinates + ): SplitResult? +} /** * Returns a [TwoPaneStrategy] that will place the slots vertically or horizontally if there is a * horizontal or vertical fold respectively. * - * If there is no fold, then the [fallbackStrategy] will be used instead. + * If there is no fold, then the [defaultStrategy] will be used instead. */ public fun TwoPaneStrategy( - fallbackStrategy: TwoPaneStrategy, windowGeometry: WindowGeometry, -): TwoPaneStrategy = HorizontalTwoPaneStrategy( - fallbackStrategy = VerticalTwoPaneStrategy( - fallbackStrategy = fallbackStrategy, - windowGeometry = windowGeometry, - ), - windowGeometry = windowGeometry + defaultStrategy: TwoPaneStrategy, +): TwoPaneStrategy = TwoPaneStrategy( + FoldAwareHorizontalTwoPaneStrategy(windowGeometry), + FoldAwareVerticalTwoPaneStrategy(windowGeometry), + defaultStrategy = defaultStrategy ) /** * Returns a [TwoPaneStrategy] that will place the slots horizontally if there is a vertical fold. * - * If there is no horizontal fold, then the [fallbackStrategy] will be used instead. + * If there is no fold, then the [defaultStrategy] will be used instead. + */ +public fun HorizontalTwoPaneStrategy( + windowGeometry: WindowGeometry, + defaultStrategy: TwoPaneStrategy, +): TwoPaneStrategy = TwoPaneStrategy( + FoldAwareHorizontalTwoPaneStrategy(windowGeometry), + defaultStrategy = defaultStrategy +) + +/** + * Returns a [TwoPaneStrategy] that will place the slots horizontally. + * + * If there is a vertical fold, then the gap will be placed along the fold. + * + * Otherwise, the gap will be placed at the given [splitFraction] from start, with the given + * [gapWidth]. + */ +public fun HorizontalTwoPaneStrategy( + windowGeometry: WindowGeometry, + splitFraction: Float, + gapWidth: Dp = 0.dp, +): TwoPaneStrategy = TwoPaneStrategy( + FoldAwareHorizontalTwoPaneStrategy(windowGeometry), + defaultStrategy = FractionHorizontalTwoPaneStrategy( + splitFraction = splitFraction, + gapWidth = gapWidth + ) +) + +/** + * Returns a [TwoPaneStrategy] that will place the slots horizontally. + * + * If there is a vertical fold, then the gap will be placed along the fold. + * + * Otherwise, the gap will be placed at [splitOffset] either from the start or end based on + * [offsetFromStart], with the given [gapWidth]. */ public fun HorizontalTwoPaneStrategy( - fallbackStrategy: TwoPaneStrategy, windowGeometry: WindowGeometry, + splitOffset: Dp, + offsetFromStart: Boolean, + gapWidth: Dp = 0.dp, +): TwoPaneStrategy = TwoPaneStrategy( + FoldAwareHorizontalTwoPaneStrategy(windowGeometry), + defaultStrategy = FixedOffsetHorizontalTwoPaneStrategy( + splitOffset = splitOffset, + offsetFromStart = offsetFromStart, + gapWidth = gapWidth + ) +) + +/** + * Returns a [TwoPaneStrategy] that will place the slots vertically if there is a horizontal fold. + * + * If there is no fold, then the [defaultStrategy] will be used instead. + */ +public fun VerticalTwoPaneStrategy( + windowGeometry: WindowGeometry, + defaultStrategy: TwoPaneStrategy, +): TwoPaneStrategy = TwoPaneStrategy( + FoldAwareVerticalTwoPaneStrategy(windowGeometry), + defaultStrategy = defaultStrategy +) + +/** + * Returns a [TwoPaneStrategy] that will place the slots horizontally. + * + * If there is a vertical fold, then the gap will be placed along the fold. + * + * Otherwise, the gap will be placed at the given [splitFraction] from top, with the given + * [gapHeight]. + */ +public fun VerticalTwoPaneStrategy( + windowGeometry: WindowGeometry, + splitFraction: Float, + gapHeight: Dp = 0.dp, +): TwoPaneStrategy = TwoPaneStrategy( + FoldAwareHorizontalTwoPaneStrategy(windowGeometry), + defaultStrategy = FractionVerticalTwoPaneStrategy( + splitFraction = splitFraction, + gapHeight = gapHeight + ) +) + +/** + * Returns a [TwoPaneStrategy] that will place the slots horizontally. + * + * If there is a vertical fold, then the gap will be placed along the fold. + * + * Otherwise, the gap will be placed at [splitOffset] either from the top or bottom based on + * [offsetFromTop], with the given [gapHeight]. + */ +public fun VerticalTwoPaneStrategy( + windowGeometry: WindowGeometry, + splitOffset: Dp, + offsetFromTop: Boolean, + gapHeight: Dp = 0.dp, +): TwoPaneStrategy = TwoPaneStrategy( + FoldAwareHorizontalTwoPaneStrategy(windowGeometry), + defaultStrategy = FixedOffsetVerticalTwoPaneStrategy( + splitOffset = splitOffset, + offsetFromTop = offsetFromTop, + gapHeight = gapHeight + ) +) + +/** + * Returns a composite [TwoPaneStrategy]. + * + * The conditional strategies (if any) will be attempted in order, and their split result used + * if they return one. If none return a split result, then the [defaultStrategy] will be used, + * which guarantees returning a [SplitResult]. + */ +private fun TwoPaneStrategy( + vararg conditionalStrategies: ConditionalTwoPaneStrategy, + defaultStrategy: TwoPaneStrategy ): TwoPaneStrategy = TwoPaneStrategy { density, layoutDirection, layoutCoordinates -> + conditionalStrategies.firstNotNullOfOrNull { conditionalTwoPaneStrategy -> + conditionalTwoPaneStrategy.calculateSplitResult( + density = density, + layoutDirection = layoutDirection, + layoutCoordinates = layoutCoordinates + ) + } ?: defaultStrategy.calculateSplitResult( + density = density, + layoutDirection = layoutDirection, + layoutCoordinates = layoutCoordinates + ) +} + +/** + * Returns a [ConditionalTwoPaneStrategy] that will place the slots horizontally if there is a + * vertical fold, or `null` if there is no fold. + */ +private fun FoldAwareHorizontalTwoPaneStrategy( + windowGeometry: WindowGeometry, +): ConditionalTwoPaneStrategy = ConditionalTwoPaneStrategy { _, _, layoutCoordinates -> val verticalFold = windowGeometry.displayFeatures.find { it is FoldingFeature && it.orientation == FoldingFeature.Orientation.VERTICAL } as FoldingFeature? @@ -231,19 +382,17 @@ public fun HorizontalTwoPaneStrategy( ) ) } else { - fallbackStrategy.calculateSplitResult(density, layoutDirection, layoutCoordinates) + null } } /** - * Returns a [TwoPaneStrategy] that will place the slots vertically if there is a horizontal fold. - * - * If there is no vertical fold, then the [fallbackStrategy] will be used instead. + * Returns a [ConditionalTwoPaneStrategy] that will place the slots vertically if there is a + * horizontal fold, or `null` if there is no fold. */ -public fun VerticalTwoPaneStrategy( - fallbackStrategy: TwoPaneStrategy, +private fun FoldAwareVerticalTwoPaneStrategy( windowGeometry: WindowGeometry, -): TwoPaneStrategy = TwoPaneStrategy { density, layoutDirection, layoutCoordinates -> +): ConditionalTwoPaneStrategy = ConditionalTwoPaneStrategy { _, _, layoutCoordinates -> val horizontalFold = windowGeometry.displayFeatures.find { it is FoldingFeature && it.orientation == FoldingFeature.Orientation.HORIZONTAL } as FoldingFeature? @@ -264,7 +413,7 @@ public fun VerticalTwoPaneStrategy( ) ) } else { - fallbackStrategy.calculateSplitResult(density, layoutDirection, layoutCoordinates) + null } } @@ -275,7 +424,7 @@ public fun VerticalTwoPaneStrategy( * * This strategy is _not_ fold aware. */ -public fun FractionHorizontalTwoPaneStrategy( +internal fun FractionHorizontalTwoPaneStrategy( splitFraction: Float, gapWidth: Dp = 0.dp, ): TwoPaneStrategy = TwoPaneStrategy { density, layoutDirection, layoutCoordinates -> @@ -304,7 +453,7 @@ public fun FractionHorizontalTwoPaneStrategy( * * This strategy is _not_ fold aware. */ -public fun FixedOffsetHorizontalTwoPaneStrategy( +internal fun FixedOffsetHorizontalTwoPaneStrategy( splitOffset: Dp, offsetFromStart: Boolean, gapWidth: Dp = 0.dp, @@ -344,7 +493,7 @@ public fun FixedOffsetHorizontalTwoPaneStrategy( * * This strategy is _not_ fold aware. */ -public fun FractionVerticalTwoPaneStrategy( +internal fun FractionVerticalTwoPaneStrategy( splitFraction: Float, gapHeight: Dp = 0.dp, ): TwoPaneStrategy = TwoPaneStrategy { density, _, layoutCoordinates -> @@ -370,7 +519,7 @@ public fun FractionVerticalTwoPaneStrategy( * * This strategy is _not_ fold aware. */ -public fun FixedOffsetVerticalTwoPaneStrategy( +internal fun FixedOffsetVerticalTwoPaneStrategy( splitOffset: Dp, offsetFromTop: Boolean, gapHeight: Dp = 0.dp, diff --git a/adaptive/src/sharedTest/kotlin/com/google/accompanist/adaptive/TwoPaneTest.kt b/adaptive/src/sharedTest/kotlin/com/google/accompanist/adaptive/TwoPaneTest.kt index d460bf002..63aa5192b 100644 --- a/adaptive/src/sharedTest/kotlin/com/google/accompanist/adaptive/TwoPaneTest.kt +++ b/adaptive/src/sharedTest/kotlin/com/google/accompanist/adaptive/TwoPaneTest.kt @@ -911,6 +911,20 @@ class TwoPaneTest { lateinit var twoPaneCoordinates: LayoutCoordinates lateinit var firstCoordinates: LayoutCoordinates lateinit var secondCoordinates: LayoutCoordinates + val windowGeometry = object : WindowGeometry { + val fakeWindowGeometry by lazy { + fakeWindowGeometry( + density = density, + twoPaneCoordinates = twoPaneCoordinates, + localFoldingFeatures = emptyList() + ) + } + + override val windowSizeClass: WindowSizeClass get() = + fakeWindowGeometry.windowSizeClass + override val displayFeatures: List get() = + fakeWindowGeometry.displayFeatures + } composeTestRule.setContent { density = LocalDensity.current @@ -932,15 +946,11 @@ class TwoPaneTest { ) }, strategy = TwoPaneStrategy( - fallbackStrategy = FractionVerticalTwoPaneStrategy( + windowGeometry = windowGeometry, + defaultStrategy = VerticalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 1f / 3f - ), - windowGeometry = object : WindowGeometry { - override val windowSizeClass: WindowSizeClass = - WindowSizeClass.calculateFromSize(DpSize(900.dp, 1200.dp)) - override val displayFeatures: List = - emptyList() - } + ) ), modifier = Modifier .requiredSize(900.dp, 1200.dp) @@ -977,6 +987,27 @@ class TwoPaneTest { lateinit var twoPaneCoordinates: LayoutCoordinates lateinit var firstCoordinates: LayoutCoordinates lateinit var secondCoordinates: LayoutCoordinates + val windowGeometry = object : WindowGeometry { + val fakeWindowGeometry by lazy { + fakeWindowGeometry( + density = density, + twoPaneCoordinates = twoPaneCoordinates, + localFoldingFeatures = listOf( + LocalFoldingFeature( + center = 600.dp, + size = 0.dp, + state = FoldingFeature.State.HALF_OPENED, + orientation = FoldingFeature.Orientation.HORIZONTAL + ) + ) + ) + } + + override val windowSizeClass: WindowSizeClass get() = + fakeWindowGeometry.windowSizeClass + override val displayFeatures: List get() = + fakeWindowGeometry.displayFeatures + } composeTestRule.setContent { density = LocalDensity.current @@ -998,30 +1029,11 @@ class TwoPaneTest { ) }, strategy = TwoPaneStrategy( - fallbackStrategy = FractionHorizontalTwoPaneStrategy( + windowGeometry = windowGeometry, + defaultStrategy = VerticalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 1f / 3f - ), - windowGeometry = object : WindowGeometry { - val fakeWindowGeometry by lazy { - fakeWindowGeometry( - density = density, - twoPaneCoordinates = twoPaneCoordinates, - localFoldingFeatures = listOf( - LocalFoldingFeature( - center = 600.dp, - size = 0.dp, - state = FoldingFeature.State.HALF_OPENED, - orientation = FoldingFeature.Orientation.HORIZONTAL - ) - ) - ) - } - - override val windowSizeClass: WindowSizeClass get() = - fakeWindowGeometry.windowSizeClass - override val displayFeatures: List get() = - fakeWindowGeometry.displayFeatures - } + ) ), modifier = Modifier .requiredSize(900.dp, 1200.dp) @@ -1058,6 +1070,27 @@ class TwoPaneTest { lateinit var twoPaneCoordinates: LayoutCoordinates lateinit var firstCoordinates: LayoutCoordinates lateinit var secondCoordinates: LayoutCoordinates + val windowGeometry = object : WindowGeometry { + val fakeWindowGeometry by lazy { + fakeWindowGeometry( + density = density, + twoPaneCoordinates = twoPaneCoordinates, + localFoldingFeatures = listOf( + LocalFoldingFeature( + center = 600.dp, + size = 60.dp, + state = FoldingFeature.State.FLAT, + orientation = FoldingFeature.Orientation.HORIZONTAL + ) + ) + ) + } + + override val windowSizeClass: WindowSizeClass get() = + fakeWindowGeometry.windowSizeClass + override val displayFeatures: List get() = + fakeWindowGeometry.displayFeatures + } composeTestRule.setContent { density = LocalDensity.current @@ -1079,30 +1112,11 @@ class TwoPaneTest { ) }, strategy = TwoPaneStrategy( - fallbackStrategy = FractionHorizontalTwoPaneStrategy( + windowGeometry = windowGeometry, + defaultStrategy = VerticalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 1f / 3f - ), - windowGeometry = object : WindowGeometry { - val fakeWindowGeometry by lazy { - fakeWindowGeometry( - density = density, - twoPaneCoordinates = twoPaneCoordinates, - localFoldingFeatures = listOf( - LocalFoldingFeature( - center = 600.dp, - size = 60.dp, - state = FoldingFeature.State.FLAT, - orientation = FoldingFeature.Orientation.HORIZONTAL - ) - ) - ) - } - - override val windowSizeClass: WindowSizeClass get() = - fakeWindowGeometry.windowSizeClass - override val displayFeatures: List get() = - fakeWindowGeometry.displayFeatures - } + ) ), modifier = Modifier .requiredSize(900.dp, 1200.dp) @@ -1139,6 +1153,27 @@ class TwoPaneTest { lateinit var twoPaneCoordinates: LayoutCoordinates lateinit var firstCoordinates: LayoutCoordinates lateinit var secondCoordinates: LayoutCoordinates + val windowGeometry = object : WindowGeometry { + val fakeWindowGeometry by lazy { + fakeWindowGeometry( + density = density, + twoPaneCoordinates = twoPaneCoordinates, + localFoldingFeatures = listOf( + LocalFoldingFeature( + center = 600.dp, + size = 0.dp, + state = FoldingFeature.State.FLAT, + orientation = FoldingFeature.Orientation.HORIZONTAL + ) + ) + ) + } + + override val windowSizeClass: WindowSizeClass get() = + fakeWindowGeometry.windowSizeClass + override val displayFeatures: List get() = + fakeWindowGeometry.displayFeatures + } composeTestRule.setContent { density = LocalDensity.current @@ -1160,30 +1195,11 @@ class TwoPaneTest { ) }, strategy = TwoPaneStrategy( - fallbackStrategy = FractionVerticalTwoPaneStrategy( + windowGeometry = windowGeometry, + defaultStrategy = VerticalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 1f / 3f ), - windowGeometry = object : WindowGeometry { - val fakeWindowGeometry by lazy { - fakeWindowGeometry( - density = density, - twoPaneCoordinates = twoPaneCoordinates, - localFoldingFeatures = listOf( - LocalFoldingFeature( - center = 600.dp, - size = 0.dp, - state = FoldingFeature.State.FLAT, - orientation = FoldingFeature.Orientation.HORIZONTAL - ) - ) - ) - } - - override val windowSizeClass: WindowSizeClass get() = - fakeWindowGeometry.windowSizeClass - override val displayFeatures: List get() = - fakeWindowGeometry.displayFeatures - } ), modifier = Modifier .requiredSize(900.dp, 1200.dp) @@ -1220,6 +1236,27 @@ class TwoPaneTest { lateinit var twoPaneCoordinates: LayoutCoordinates lateinit var firstCoordinates: LayoutCoordinates lateinit var secondCoordinates: LayoutCoordinates + val windowGeometry = object : WindowGeometry { + val fakeWindowGeometry by lazy { + fakeWindowGeometry( + density = density, + twoPaneCoordinates = twoPaneCoordinates, + localFoldingFeatures = listOf( + LocalFoldingFeature( + center = 450.dp, + size = 0.dp, + state = FoldingFeature.State.HALF_OPENED, + orientation = FoldingFeature.Orientation.VERTICAL + ) + ) + ) + } + + override val windowSizeClass: WindowSizeClass get() = + fakeWindowGeometry.windowSizeClass + override val displayFeatures: List get() = + fakeWindowGeometry.displayFeatures + } composeTestRule.setContent { density = LocalDensity.current @@ -1241,30 +1278,11 @@ class TwoPaneTest { ) }, strategy = TwoPaneStrategy( - fallbackStrategy = FractionHorizontalTwoPaneStrategy( + windowGeometry = windowGeometry, + defaultStrategy = VerticalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 1f / 3f ), - windowGeometry = object : WindowGeometry { - val fakeWindowGeometry by lazy { - fakeWindowGeometry( - density = density, - twoPaneCoordinates = twoPaneCoordinates, - localFoldingFeatures = listOf( - LocalFoldingFeature( - center = 450.dp, - size = 0.dp, - state = FoldingFeature.State.HALF_OPENED, - orientation = FoldingFeature.Orientation.VERTICAL - ) - ) - ) - } - - override val windowSizeClass: WindowSizeClass get() = - fakeWindowGeometry.windowSizeClass - override val displayFeatures: List get() = - fakeWindowGeometry.displayFeatures - } ), modifier = Modifier .requiredSize(900.dp, 1200.dp) @@ -1301,6 +1319,27 @@ class TwoPaneTest { lateinit var twoPaneCoordinates: LayoutCoordinates lateinit var firstCoordinates: LayoutCoordinates lateinit var secondCoordinates: LayoutCoordinates + val windowGeometry = object : WindowGeometry { + val fakeWindowGeometry by lazy { + fakeWindowGeometry( + density = density, + twoPaneCoordinates = twoPaneCoordinates, + localFoldingFeatures = listOf( + LocalFoldingFeature( + center = 450.dp, + size = 64.dp, + state = FoldingFeature.State.FLAT, + orientation = FoldingFeature.Orientation.VERTICAL + ) + ) + ) + } + + override val windowSizeClass: WindowSizeClass get() = + fakeWindowGeometry.windowSizeClass + override val displayFeatures: List get() = + fakeWindowGeometry.displayFeatures + } composeTestRule.setContent { density = LocalDensity.current @@ -1322,30 +1361,11 @@ class TwoPaneTest { ) }, strategy = TwoPaneStrategy( - fallbackStrategy = FractionHorizontalTwoPaneStrategy( + windowGeometry = windowGeometry, + defaultStrategy = HorizontalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 1f / 3f ), - windowGeometry = object : WindowGeometry { - val fakeWindowGeometry by lazy { - fakeWindowGeometry( - density = density, - twoPaneCoordinates = twoPaneCoordinates, - localFoldingFeatures = listOf( - LocalFoldingFeature( - center = 450.dp, - size = 64.dp, - state = FoldingFeature.State.FLAT, - orientation = FoldingFeature.Orientation.VERTICAL - ) - ) - ) - } - - override val windowSizeClass: WindowSizeClass get() = - fakeWindowGeometry.windowSizeClass - override val displayFeatures: List get() = - fakeWindowGeometry.displayFeatures - } ), modifier = Modifier .requiredSize(900.dp, 1200.dp) @@ -1385,6 +1405,28 @@ class TwoPaneTest { composeTestRule.setContent { density = LocalDensity.current + val windowGeometry = object : WindowGeometry { + val fakeWindowGeometry by lazy { + fakeWindowGeometry( + density = density, + twoPaneCoordinates = twoPaneCoordinates, + localFoldingFeatures = listOf( + LocalFoldingFeature( + center = 450.dp, + size = 0.dp, + state = FoldingFeature.State.FLAT, + orientation = FoldingFeature.Orientation.VERTICAL + ) + ) + ) + } + + override val windowSizeClass: WindowSizeClass get() = + fakeWindowGeometry.windowSizeClass + override val displayFeatures: List get() = + fakeWindowGeometry.displayFeatures + } + TwoPane( first = { Spacer( @@ -1403,30 +1445,11 @@ class TwoPaneTest { ) }, strategy = TwoPaneStrategy( - fallbackStrategy = FractionVerticalTwoPaneStrategy( + windowGeometry = windowGeometry, + defaultStrategy = VerticalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 1f / 3f - ), - windowGeometry = object : WindowGeometry { - val fakeWindowGeometry by lazy { - fakeWindowGeometry( - density = density, - twoPaneCoordinates = twoPaneCoordinates, - localFoldingFeatures = listOf( - LocalFoldingFeature( - center = 450.dp, - size = 0.dp, - state = FoldingFeature.State.FLAT, - orientation = FoldingFeature.Orientation.VERTICAL - ) - ) - ) - } - - override val windowSizeClass: WindowSizeClass get() = - fakeWindowGeometry.windowSizeClass - override val displayFeatures: List get() = - fakeWindowGeometry.displayFeatures - } + ) ), modifier = Modifier .requiredSize(900.dp, 1200.dp) diff --git a/sample/src/main/java/com/google/accompanist/sample/adaptive/BasicTwoPaneSample.kt b/sample/src/main/java/com/google/accompanist/sample/adaptive/BasicTwoPaneSample.kt index baefb4261..3d5564637 100644 --- a/sample/src/main/java/com/google/accompanist/sample/adaptive/BasicTwoPaneSample.kt +++ b/sample/src/main/java/com/google/accompanist/sample/adaptive/BasicTwoPaneSample.kt @@ -27,10 +27,10 @@ import androidx.compose.material.Text import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.google.accompanist.adaptive.FractionHorizontalTwoPaneStrategy -import com.google.accompanist.adaptive.FractionVerticalTwoPaneStrategy +import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy import com.google.accompanist.adaptive.TwoPane import com.google.accompanist.adaptive.TwoPaneStrategy +import com.google.accompanist.adaptive.VerticalTwoPaneStrategy import com.google.accompanist.adaptive.calculateWindowGeometry import com.google.accompanist.sample.AccompanistSampleTheme @@ -67,19 +67,21 @@ class BasicTwoPaneSample : ComponentActivity() { } }, strategy = TwoPaneStrategy( - fallbackStrategy = { density, layoutDirection, layoutCoordinates -> + windowGeometry = windowGeometry, + defaultStrategy = { density, layoutDirection, layoutCoordinates -> // Split vertically if the height is larger than the width if (layoutCoordinates.size.height >= layoutCoordinates.size.width) { - FractionVerticalTwoPaneStrategy( + VerticalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 0.75f, ) } else { - FractionHorizontalTwoPaneStrategy( + HorizontalTwoPaneStrategy( + windowGeometry = windowGeometry, splitFraction = 0.75f, ) }.calculateSplitResult(density, layoutDirection, layoutCoordinates) }, - windowGeometry = windowGeometry ), modifier = Modifier.padding(8.dp) )