Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 541535c3 authored by Mike Schneider's avatar Mike Schneider Committed by Android (Google) Code Review
Browse files

Merge "Floating version of VerticalExpandContainerSpec" into main

parents 72f26891 4767fdaa
Loading
Loading
Loading
Loading
+59 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.mechanics.behavior

import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
@@ -34,19 +35,72 @@ import androidx.compose.ui.util.fastCoerceIn
import androidx.compose.ui.util.lerp
import kotlin.math.min

/**
 * Draws the background of a vertically container, and applies clipping to it.
 *
 * Intended to be used with a [VerticalExpandContainerSpec] motion.
 */
fun Modifier.verticalExpandContainerBackground(
    backgroundColor: Color,
    spec: VerticalExpandContainerSpec,
): Modifier =
    this.then(
        if (spec.isFloating) {
            Modifier.verticalFloatingExpandContainerBackground(backgroundColor, spec)
        } else {
            Modifier.verticalEdgeExpandContainerBackground(backgroundColor, spec)
        }
    )

/**
 * Draws the background of an floating container, and applies clipping to it.
 *
 * Intended to be used with a [VerticalExpandContainerSpec] motion.
 */
internal fun Modifier.verticalFloatingExpandContainerBackground(
    backgroundColor: Color,
    spec: VerticalExpandContainerSpec,
): Modifier =
    this.drawWithCache {
        val targetRadiusPx = spec.radius.toPx()
        val currentRadiusPx = min(targetRadiusPx, min(size.width, size.height) / 2f)
        val horizontalInset = targetRadiusPx - currentRadiusPx
        val shapeTopLeft = Offset(horizontalInset, 0f)
        val shapeSize = Size(size.width - (horizontalInset * 2f), size.height)

        val layer =
            obtainGraphicsLayer().apply {
                clip = true
                setRoundRectOutline(shapeTopLeft, shapeSize, cornerRadius = currentRadiusPx)

                record { drawContent() }
            }

        onDrawWithContent {
            drawRoundRect(
                color = backgroundColor,
                topLeft = shapeTopLeft,
                size = shapeSize,
                cornerRadius = CornerRadius(currentRadiusPx),
            )

            drawLayer(layer)
        }
    }

/**
 * Draws the background of an edge container, and applies clipping to it.
 *
 * Intended to be used with a [EdgeContainerExpansionSpec] motion.
 * Intended to be used with a [VerticalExpandContainerSpec] motion.
 */
fun Modifier.edgeContainerExpansionBackground(
internal fun Modifier.verticalEdgeExpandContainerBackground(
    backgroundColor: Color,
    spec: EdgeContainerExpansionSpec,
    spec: VerticalExpandContainerSpec,
): Modifier = this.then(EdgeContainerExpansionBackgroundElement(backgroundColor, spec))

internal class EdgeContainerExpansionBackgroundNode(
    var backgroundColor: Color,
    var spec: EdgeContainerExpansionSpec,
    var spec: VerticalExpandContainerSpec,
) : Modifier.Node(), DrawModifierNode {

    private var graphicsLayer: GraphicsLayer? = null
@@ -126,7 +180,7 @@ internal class EdgeContainerExpansionBackgroundNode(

private data class EdgeContainerExpansionBackgroundElement(
    val backgroundColor: Color,
    val spec: EdgeContainerExpansionSpec,
    val spec: VerticalExpandContainerSpec,
) : ModifierNodeElement<EdgeContainerExpansionBackgroundNode>() {
    override fun create(): EdgeContainerExpansionBackgroundNode =
        EdgeContainerExpansionBackgroundNode(backgroundColor, spec)
+14 −10
Original line number Diff line number Diff line
@@ -34,19 +34,21 @@ import com.android.mechanics.spec.MotionSpec
import com.android.mechanics.spec.OnChangeSegmentHandler
import com.android.mechanics.spec.SegmentData
import com.android.mechanics.spec.SegmentKey
import com.android.mechanics.spec.buildDirectionalMotionSpec
import com.android.mechanics.spec.builder
import com.android.mechanics.spec.reverseBuilder
import com.android.mechanics.spring.SpringParameters

/** Motion spec for a vertically expandable container. */
class EdgeContainerExpansionSpec(
class VerticalExpandContainerSpec(
    val isFloating: Boolean,
    val minRadius: Dp = Defaults.MinRadius,
    val radius: Dp = Defaults.Radius,
    val visibleHeight: Dp = Defaults.VisibleHeight,
    val preDetachRatio: Float = Defaults.PreDetachRatio,
    val detachHeight: Dp = Defaults.DetachHeight,
    val attachHeight: Dp = Defaults.AttachHeight,
    val detachHeight: Dp = if (isFloating) radius * 3 else Defaults.DetachHeight,
    val attachHeight: Dp = if (isFloating) radius * 2 else Defaults.AttachHeight,
    val widthOffset: Dp = Defaults.WidthOffset,
    val minRadius: Dp = Defaults.MinRadius,
    val radius: Dp = Defaults.Radius,
    val attachSpring: SpringParameters = Defaults.AttachSpring,
    val detachSpring: SpringParameters = Defaults.DetachSpring,
    val opacitySpring: SpringParameters = Defaults.OpacitySpring,
@@ -99,14 +101,16 @@ class EdgeContainerExpansionSpec(
        density: Density,
    ): MotionSpec {
        return with(density) {
            MotionSpec.builder(
                    SpringParameters(motionScheme.defaultSpatialSpec()),
                    initialMapping = { input ->
            if (isFloating) {
                MotionSpec(buildDirectionalMotionSpec(Mapping.Fixed(intrinsicWidth)))
            } else {
                MotionSpec(
                    buildDirectionalMotionSpec({ input ->
                        val fraction = (input / detachHeight.toPx()).fastCoerceIn(0f, 1f)
                        intrinsicWidth - lerp(widthOffset.toPx(), 0f, fraction)
                    },
                    })
                )
                .complete()
            }
        }
    }