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

Update LazyDropdownMenu for the latest Material 3 library #2150

Merged
merged 4 commits into from
Sep 5, 2024
Merged
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
Expand All @@ -19,10 +20,14 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
Expand All @@ -35,27 +40,38 @@
import kotlin.math.max
import kotlin.math.min

/** Forked version of [androidx.compose.material3.DropdownMenu] supporting a LazyColumn */
/**
* Forked version of [androidx.compose.material3.DropdownMenu] supporting a LazyColumn
*
* This can go away once this issue is officially supported: https://issuetracker.google.com/issues/242398344
*/
@Composable
fun LazyDropdownMenu(
expanded: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
offset: DpOffset = DpOffset(0.dp, 0.dp),
properties: PopupProperties = PopupProperties(focusable = true),
shape: Shape = MenuDefaults.shape,
containerColor: Color = MenuDefaults.containerColor,
tonalElevation: Dp = MenuDefaults.TonalElevation,
shadowElevation: Dp = MenuDefaults.ShadowElevation,
border: BorderStroke? = null,
content: LazyListScope.() -> Unit
) {
val expandedStates = remember { MutableTransitionState(false) }
expandedStates.targetState = expanded
val expandedState = remember { MutableTransitionState(false) }
expandedState.targetState = expanded

Check warning on line 63 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L62-L63

Added lines #L62 - L63 were not covered by tests

if (expandedStates.currentState || expandedStates.targetState) {
if (expandedState.currentState || expandedState.targetState) {
val transformOriginState = remember { mutableStateOf(TransformOrigin.Center) }
val density = LocalDensity.current
val popupPositionProvider = DropdownMenuPositionProvider(
offset,
density
) { parentBounds, menuBounds ->
transformOriginState.value = calculateTransformOrigin(parentBounds, menuBounds)
val popupPositionProvider = remember(offset, density) {
DropdownMenuPositionProvider(
offset,
density,
) { parentBounds, menuBounds ->
transformOriginState.value = calculateTransformOrigin(parentBounds, menuBounds)

Check warning on line 73 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L68-L73

Added lines #L68 - L73 were not covered by tests
}
}

Popup(
Expand All @@ -64,10 +80,15 @@
properties = properties
) {
LazyDropdownMenuContent(
expandedStates = expandedStates,
expandedState = expandedState,

Check warning on line 83 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L83

Added line #L83 was not covered by tests
transformOriginState = transformOriginState,
shape = shape,
containerColor = containerColor,
tonalElevation = tonalElevation,
shadowElevation = shadowElevation,
border = border,

Check warning on line 89 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L85-L89

Added lines #L85 - L89 were not covered by tests
modifier = modifier,
content = content
content = content,

Check warning on line 91 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L91

Added line #L91 was not covered by tests
)
}
}
Expand All @@ -77,42 +98,38 @@
@Composable
@Suppress(
"ktlint:compose:modifier-not-used-at-root",
"ktlint:compose:modifier-without-default-check",
"ktlint:compose:mutable-state-param-check",
"ktlint:standard:multiline-if-else",
"TransitionPropertiesLabel",
)
private fun LazyDropdownMenuContent(
expandedStates: MutableTransitionState<Boolean>,
modifier: Modifier,
expandedState: MutableTransitionState<Boolean>,
transformOriginState: MutableState<TransformOrigin>,
modifier: Modifier = Modifier,
shape: Shape,
containerColor: Color,
tonalElevation: Dp,
shadowElevation: Dp,
border: BorderStroke?,
content: LazyListScope.() -> Unit
) {
// Menu open/close animation.
val transition = updateTransition(expandedStates, "DropDownMenu")
@Suppress("DEPRECATION")
val transition = updateTransition(expandedState, "DropDownMenu")

Check warning on line 119 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L119

Added line #L119 was not covered by tests

val scale by transition.animateFloat(
transitionSpec = {
if (false isTransitioningTo true) {
// Dismissed to expanded
tween(
durationMillis = InTransitionDuration,
easing = LinearOutSlowInEasing
)
tween(durationMillis = InTransitionDuration, easing = LinearOutSlowInEasing)

Check warning on line 125 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L125

Added line #L125 was not covered by tests
} else {
// Expanded to dismissed.
tween(
durationMillis = 1,
delayMillis = OutTransitionDuration - 1
)
tween(durationMillis = 1, delayMillis = OutTransitionDuration - 1)

Check warning on line 128 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L128

Added line #L128 was not covered by tests
}
},
) {
if (it) {
// Menu is expanded.
1f
} else {
// Menu is dismissed.
0.8f
}
) { expanded ->
if (expanded) ExpandedScaleTarget else ClosedScaleTarget
}

val alpha by transition.animateFloat(
Expand All @@ -125,26 +142,30 @@
tween(durationMillis = OutTransitionDuration)
}
}
) {
if (it) {
// Menu is expanded.
1f
} else {
// Menu is dismissed.
0f
}
) { expanded ->
if (expanded) ExpandedAlphaTarget else ClosedAlphaTarget
}

val isInspecting = LocalInspectionMode.current

Check warning on line 149 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L149

Added line #L149 was not covered by tests
Surface(
modifier = Modifier.graphicsLayer {
scaleX = scale
scaleY = scale
this.alpha = alpha
modifier =
Modifier.graphicsLayer {
scaleX =

Check warning on line 153 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L152-L153

Added lines #L152 - L153 were not covered by tests
if (!isInspecting) scale
else if (expandedState.targetState) ExpandedScaleTarget else ClosedScaleTarget
scaleY =

Check warning on line 156 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L156

Added line #L156 was not covered by tests
if (!isInspecting) scale
else if (expandedState.targetState) ExpandedScaleTarget else ClosedScaleTarget
this.alpha =

Check warning on line 159 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L159

Added line #L159 was not covered by tests
if (!isInspecting) alpha
else if (expandedState.targetState) ExpandedAlphaTarget else ClosedAlphaTarget
transformOrigin = transformOriginState.value
},
shape = MaterialTheme.shapes.extraSmall,
color = MaterialTheme.colorScheme.surface,
tonalElevation = 3.dp,
shadowElevation = 3.dp
shape = shape,
color = containerColor,
tonalElevation = tonalElevation,
shadowElevation = shadowElevation,
border = border,

Check warning on line 168 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L164-L168

Added lines #L164 - L168 were not covered by tests
) {
LazyColumn(
modifier = modifier.padding(vertical = DropdownMenuVerticalPadding),
Expand All @@ -166,6 +187,18 @@
/** Copied from [androidx.compose.material3.OutTransitionDuration] */
private const val OutTransitionDuration = 75

/** Copied from [androidx.compose.material3.ExpandedScaleTarget] */
private const val ExpandedScaleTarget = 1f

/** Copied from [androidx.compose.material3.ClosedScaleTarget] */
private const val ClosedScaleTarget = 0.8f

/** Copied from [androidx.compose.material3.ExpandedAlphaTarget] */
private const val ExpandedAlphaTarget = 1f

/** Copied from [androidx.compose.material3.ClosedAlphaTarget] */
private const val ClosedAlphaTarget = 0f

/**
* Copied from [androidx.compose.material3.DropdownMenuPositionProvider]
*/
Expand Down Expand Up @@ -232,24 +265,24 @@
/**
* Copied from [androidx.compose.material3.calculateTransformOrigin]
*/
private fun calculateTransformOrigin(parentBounds: IntRect, menuBounds: IntRect): TransformOrigin {
private fun calculateTransformOrigin(anchorBounds: IntRect, menuBounds: IntRect): TransformOrigin {
val pivotX = when {
menuBounds.left >= parentBounds.right -> 0f
menuBounds.right <= parentBounds.left -> 1f
menuBounds.left >= anchorBounds.right -> 0f
menuBounds.right <= anchorBounds.left -> 1f
menuBounds.width == 0 -> 0f
else -> {
val intersectionCenter =
(max(parentBounds.left, menuBounds.left) + min(parentBounds.right, menuBounds.right)) / 2
(max(anchorBounds.left, menuBounds.left) + min(anchorBounds.right, menuBounds.right)) / 2

Check warning on line 275 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L275

Added line #L275 was not covered by tests
(intersectionCenter - menuBounds.left).toFloat() / menuBounds.width
}
}
val pivotY = when {
menuBounds.top >= parentBounds.bottom -> 0f
menuBounds.bottom <= parentBounds.top -> 1f
menuBounds.top >= anchorBounds.bottom -> 0f
menuBounds.bottom <= anchorBounds.top -> 1f
menuBounds.height == 0 -> 0f
else -> {
val intersectionCenter =
(max(parentBounds.top, menuBounds.top) + min(parentBounds.bottom, menuBounds.bottom)) / 2
(max(anchorBounds.top, menuBounds.top) + min(anchorBounds.bottom, menuBounds.bottom)) / 2

Check warning on line 285 in gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt

View check run for this annotation

Codecov / codecov/patch

gto-support-androidx-compose-material3/src/main/kotlin/org/ccci/gto/android/common/androidx/compose/material3/ui/menu/LazyDropdownMenu.kt#L285

Added line #L285 was not covered by tests
(intersectionCenter - menuBounds.top).toFloat() / menuBounds.height
}
}
Expand Down