Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Material 3 1.4.0-alpha04 #1715

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 58 additions & 52 deletions compose/material3/adaptive/adaptive-layout/api/current.txt

Large diffs are not rendered by default.

Large diffs are not rendered by default.

110 changes: 58 additions & 52 deletions compose/material3/adaptive/adaptive-layout/api/restricted_current.txt

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions compose/material3/adaptive/adaptive-layout/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ kotlin {
implementation(project(":compose:foundation:foundation-layout"))
implementation(project(":compose:ui:ui-geometry"))
implementation(project(":compose:ui:ui-util"))
implementation("org.jetbrains.androidx.window:window-core:1.3.1")
implementation(project(":window:window-core"))
implementation(project(":collection:collection"))
}
}

commonTest {
dependencies {
implementation(libs.kotlinTest)
api("org.jetbrains.compose.annotation-internal:annotation:1.7.1")
api(project(":annotation:annotation"))
implementation(project(":kruth:kruth"))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@
package androidx.compose.material3.adaptive.layout

import android.os.Build
import androidx.compose.material3.MaterialTheme
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.VerticalDragHandle
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.testutils.assertAgainstGolden
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.createComposeRule
Expand Down Expand Up @@ -112,6 +117,64 @@ class ThreePaneScaffoldScreenshotTest {
.assertAgainstGolden(screenshotRule, "threePaneScaffold_listDetail_dense_expanded")
}

@Test
fun threePaneScaffold_scaffoldStateTransitionFraction_0percent() {
rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
val detailExtraExpanded =
ThreePaneScaffoldValue(
primary = PaneAdaptedValue.Expanded,
secondary = PaneAdaptedValue.Hidden,
tertiary = PaneAdaptedValue.Expanded,
)
val listDetailExpanded =
ThreePaneScaffoldValue(
primary = PaneAdaptedValue.Expanded,
secondary = PaneAdaptedValue.Expanded,
tertiary = PaneAdaptedValue.Hidden,
)
val scaffoldState = remember { MutableThreePaneScaffoldState(detailExtraExpanded) }
LaunchedEffect(Unit) { scaffoldState.seekTo(0f, listDetailExpanded) }
SampleThreePaneScaffoldWithScaffoldState(scaffoldState)
}

rule
.onNodeWithTag(ThreePaneScaffoldTestTag)
.captureToImage()
.assertAgainstGolden(
screenshotRule,
"threePaneScaffold_scaffoldStateTransitionFraction_0percent"
)
}

@Test
fun threePaneScaffold_scaffoldStateTransitionFraction_10percent() {
rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
val detailExtraExpanded =
ThreePaneScaffoldValue(
primary = PaneAdaptedValue.Expanded,
secondary = PaneAdaptedValue.Hidden,
tertiary = PaneAdaptedValue.Expanded,
)
val listDetailExpanded =
ThreePaneScaffoldValue(
primary = PaneAdaptedValue.Expanded,
secondary = PaneAdaptedValue.Expanded,
tertiary = PaneAdaptedValue.Hidden,
)
val scaffoldState = remember { MutableThreePaneScaffoldState(detailExtraExpanded) }
LaunchedEffect(Unit) { scaffoldState.seekTo(0.1f, listDetailExpanded) }
SampleThreePaneScaffoldWithScaffoldState(scaffoldState)
}

rule
.onNodeWithTag(ThreePaneScaffoldTestTag)
.captureToImage()
.assertAgainstGolden(
screenshotRule,
"threePaneScaffold_scaffoldStateTransitionFraction_10percent"
)
}

@Test
fun threePaneScaffold_paneExpansion_fixedFirstPaneWidth() {
rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
Expand Down Expand Up @@ -332,7 +395,7 @@ class ThreePaneScaffoldScreenshotTest {
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle { mockPaneExpansionState.dispatchRawDelta(mockDraggingDp) }
rule.runOnIdle { mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingDp) }

rule
.onNodeWithTag(ThreePaneScaffoldTestTag)
Expand All @@ -353,7 +416,7 @@ class ThreePaneScaffoldScreenshotTest {
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle { mockPaneExpansionState.dispatchRawDelta(mockDraggingDp) }
rule.runOnIdle { mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingDp) }

rule
.onNodeWithTag(ThreePaneScaffoldTestTag)
Expand All @@ -374,7 +437,7 @@ class ThreePaneScaffoldScreenshotTest {
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle { mockPaneExpansionState.dispatchRawDelta(mockDraggingDp) }
rule.runOnIdle { mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingDp) }

rule
.onNodeWithTag(ThreePaneScaffoldTestTag)
Expand Down Expand Up @@ -421,6 +484,18 @@ private fun SampleThreePaneScaffoldDenseMode() {
)
}

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
private fun SampleThreePaneScaffoldWithScaffoldState(scaffoldState: ThreePaneScaffoldState) {
val scaffoldDirective =
calculatePaneScaffoldDirectiveWithTwoPanesOnMediumWidth(currentWindowAdaptiveInfo())
SampleThreePaneScaffold(
scaffoldDirective,
scaffoldState,
ListDetailPaneScaffoldDefaults.PaneOrder
)
}

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
internal fun SampleThreePaneScaffoldWithPaneExpansion(
Expand All @@ -447,5 +522,14 @@ internal fun SampleThreePaneScaffoldWithPaneExpansion(
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
internal fun ThreePaneScaffoldScope.MockDragHandle(state: PaneExpansionState) {
PaneExpansionDragHandle(state, MaterialTheme.colorScheme.outline)
val interactionSource = remember { MutableInteractionSource() }
VerticalDragHandle(
modifier =
Modifier.paneExpansionDraggable(
state,
LocalMinimumInteractiveComponentSize.current,
interactionSource
),
interactionSource = interactionSource
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,21 +168,22 @@ class ThreePaneScaffoldTest {

@Test
fun threePaneScaffold_paneExpansionWithDragHandle_slowDraggingAndSettling() {
val mockPaneExpansionState = PaneExpansionState(anchors = MockPaneExpansionAnchors)
var mockDraggingPx = 0f
var expectedSettledOffsetPx = 0
lateinit var mockPaneExpansionState: PaneExpansionState
lateinit var scope: CoroutineScope

rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
scope = rememberCoroutineScope()
mockPaneExpansionState = rememberPaneExpansionState(anchors = MockPaneExpansionAnchors)
mockDraggingPx = with(LocalDensity.current) { 200.dp.toPx() }
expectedSettledOffsetPx =
with(LocalDensity.current) { MockPaneExpansionMiddleAnchor.toPx().toInt() }
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle {
mockPaneExpansionState.dispatchRawDelta(mockDraggingPx)
mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingPx)
scope.launch { mockPaneExpansionState.settleToAnchorIfNeeded(0F) }
}

Expand All @@ -194,18 +195,19 @@ class ThreePaneScaffoldTest {

@Test
fun threePaneScaffold_paneExpansionWithDragHandle_fastDraggingAndSettling() {
val mockPaneExpansionState = PaneExpansionState(anchors = MockPaneExpansionAnchors)
var mockDraggingPx = 0f
lateinit var mockPaneExpansionState: PaneExpansionState
lateinit var scope: CoroutineScope

rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
scope = rememberCoroutineScope()
mockPaneExpansionState = rememberPaneExpansionState(anchors = MockPaneExpansionAnchors)
mockDraggingPx = with(LocalDensity.current) { 200.dp.toPx() }
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle {
mockPaneExpansionState.dispatchRawDelta(mockDraggingPx)
mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingPx)
scope.launch { mockPaneExpansionState.settleToAnchorIfNeeded(400F) }
}

Expand All @@ -215,20 +217,45 @@ class ThreePaneScaffoldTest {
}
}

@Test
fun threePaneScaffold_paneExpansionWithDragHandle_flingOverAnchorAndSettling() {
var mockDraggingPx = 0f
lateinit var mockPaneExpansionState: PaneExpansionState
lateinit var scope: CoroutineScope

rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
scope = rememberCoroutineScope()
mockPaneExpansionState = rememberPaneExpansionState(anchors = MockPaneExpansionAnchors)
mockDraggingPx = with(LocalDensity.current) { 100.dp.toPx() }
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle {
mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingPx)
scope.launch { mockPaneExpansionState.settleToAnchorIfNeeded(800F) }
}

rule.runOnIdle {
assertThat(mockPaneExpansionState.currentMeasuredDraggingOffset)
.isEqualTo(mockPaneExpansionState.maxExpansionWidth)
}
}

@Test
fun threePaneScaffold_paneExpansionWithDragHandle_draggingAndSettlingCloseToLeftEdge() {
val mockPaneExpansionState = PaneExpansionState(anchors = MockPaneExpansionAnchors)
var mockDraggingDp = 0f
lateinit var mockPaneExpansionState: PaneExpansionState
lateinit var scope: CoroutineScope

rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
scope = rememberCoroutineScope()
mockPaneExpansionState = rememberPaneExpansionState(anchors = MockPaneExpansionAnchors)
mockDraggingDp = with(LocalDensity.current) { -360.dp.toPx() }
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle {
mockPaneExpansionState.dispatchRawDelta(mockDraggingDp)
mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingDp)
scope.launch { mockPaneExpansionState.settleToAnchorIfNeeded(-200F) }
}

Expand All @@ -239,18 +266,19 @@ class ThreePaneScaffoldTest {

@Test
fun threePaneScaffold_paneExpansionWithDragHandle_draggingAndSettlingCloseToRightEdge() {
val mockPaneExpansionState = PaneExpansionState(anchors = MockPaneExpansionAnchors)
var mockDraggingDp = 0f
lateinit var mockPaneExpansionState: PaneExpansionState
lateinit var scope: CoroutineScope

rule.setContentWithSimulatedSize(simulatedWidth = 1024.dp, simulatedHeight = 800.dp) {
scope = rememberCoroutineScope()
mockPaneExpansionState = rememberPaneExpansionState(anchors = MockPaneExpansionAnchors)
mockDraggingDp = with(LocalDensity.current) { 640.dp.toPx() }
SampleThreePaneScaffoldWithPaneExpansion(mockPaneExpansionState) { MockDragHandle(it) }
}

rule.runOnIdle {
mockPaneExpansionState.dispatchRawDelta(mockDraggingDp)
mockPaneExpansionState.draggableState.dispatchRawDelta(mockDraggingDp)
scope.launch { mockPaneExpansionState.settleToAnchorIfNeeded(200F) }
}

Expand Down Expand Up @@ -324,3 +352,38 @@ internal fun SampleThreePaneScaffold(
}
}
}

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
internal fun SampleThreePaneScaffold(
scaffoldDirective: PaneScaffoldDirective,
scaffoldState: ThreePaneScaffoldState,
paneOrder: ThreePaneScaffoldHorizontalOrder,
) {
ThreePaneScaffold(
modifier = Modifier.fillMaxSize().testTag(ThreePaneScaffoldTestTag),
scaffoldDirective = scaffoldDirective,
scaffoldState = scaffoldState,
paneOrder = paneOrder,
secondaryPane = {
AnimatedPane(modifier = Modifier.testTag(tag = "SecondaryPane")) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.secondary
) {}
}
},
tertiaryPane = {
AnimatedPane(modifier = Modifier.testTag(tag = "TertiaryPane")) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.tertiary
) {}
}
}
) {
AnimatedPane(modifier = Modifier.testTag(tag = "PrimaryPane")) {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.primary) {}
}
}
}
Loading
Loading