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

Commit 561077a5 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Add a lambda based color overload to ExpandableController

This CL adds a lambda color parameter to ExpandableController, so that
the background color of an Expandable can be animated without causing
recompositions.

Bug: 402059261
Test: Manual, with the TileExpandable
Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Change-Id: I0714871b053e6fc2a028804af79fe7b2bd384c3d
parent 22ed296e
Loading
Loading
Loading
Loading
+27 −18
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewGroupOverlay
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -62,6 +61,7 @@ import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.graphics.layer.GraphicsLayer
import androidx.compose.ui.graphics.layer.drawLayer
import androidx.compose.ui.graphics.rememberGraphicsLayer
@@ -82,6 +82,7 @@ import androidx.lifecycle.setViewTreeLifecycleOwner
import androidx.lifecycle.setViewTreeViewModelStoreOwner
import androidx.savedstate.findViewTreeSavedStateRegistryOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import com.android.compose.modifiers.animatedBackground
import com.android.compose.modifiers.thenIf
import com.android.compose.ui.graphics.FullScreenComposeViewInOverlay
import com.android.systemui.animation.ComposableControllerFactory
@@ -291,7 +292,7 @@ fun Expandable(
                    .updateExpandableSize()
                    .then(minInteractiveSizeModifier)
                    .then(clickModifier(controller, onClick, interactionSource))
                    .background(color, shape)
                    .animatedBackground(color, shape = shape)
                    .border(controller)
                    .onGloballyPositioned { controller.boundsInComposeViewRoot = it.boundsInRoot() }
            ) {
@@ -307,12 +308,14 @@ private fun WrappedContent(
    contentColor: Color,
    content: @Composable (Expandable) -> Unit,
) {
    CompositionLocalProvider(LocalContentColor provides contentColor) {
        // We make sure that the content itself (wrapped by the background) is at least 40.dp, which
        // is the same as the M3 buttons. This applies even if onClick is null, to make it easier to
        // write expandables that are sometimes clickable and sometimes not. There shouldn't be any
        // Expandable smaller than 40dp because if the expandable is not clickable directly, then
        // something in its content should be (and with a size >= 40dp).
    val minSizeContent =
        @Composable {
            // We make sure that the content itself (wrapped by the background) is at least 40.dp,
            // which is the same as the M3 buttons. This applies even if onClick is null, to make it
            // easier to write expandables that are sometimes clickable and sometimes not. There
            // shouldn't be any Expandable smaller than 40dp because if the expandable is not
            // clickable directly, then something in its content should be (and with a size >=
            // 40dp).
            val minSize = 40.dp
            Box(
                Modifier.defaultMinSize(minWidth = minSize, minHeight = minSize),
@@ -321,6 +324,12 @@ private fun WrappedContent(
                content(expandable)
            }
        }

    if (contentColor.isSpecified) {
        CompositionLocalProvider(LocalContentColor provides contentColor, content = minSizeContent)
    } else {
        minSizeContent()
    }
}

@Composable
@@ -345,7 +354,7 @@ private fun Modifier.expandable(
        .thenIf(drawContent) {
            Modifier.border(controller)
                .then(clickModifier(controller, onClick, interactionSource))
                .background(controller.color, controller.shape)
                .animatedBackground(controller.color, shape = controller.shape)
        }
        .onPlaced { controller.boundsInComposeViewRoot = it.boundsInRoot() }
        .drawWithContent {
@@ -422,7 +431,7 @@ private class DrawExpandableInOverlayNode(
            // Background.
            this@draw.drawBackground(
                state,
                controller.color,
                controller.color(),
                controller.borderStroke,
                size = Size(state.width.toFloat(), state.height.toFloat()),
            )
@@ -469,7 +478,7 @@ private fun clickModifier(
/** Draw [content] in [overlay] while respecting its screen position given by [animatorState]. */
@Composable
private fun AnimatedContentInOverlay(
    color: Color,
    color: () -> Color,
    sizeInOriginalLayout: Size,
    overlay: ViewGroupOverlay,
    controller: ExpandableControllerImpl,
@@ -523,7 +532,7 @@ private fun AnimatedContentInOverlay(
                                    return@drawWithContent
                                }

                                drawBackground(animatorState, color, controller.borderStroke)
                                drawBackground(animatorState, color(), controller.borderStroke)
                                drawContent()
                            },
                            // We center the content in the expanding container.
+19 −2
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -79,6 +78,24 @@ fun rememberExpandableController(
    contentColor: Color = contentColorFor(color),
    borderStroke: BorderStroke? = null,
    transitionControllerFactory: ComposableControllerFactory? = null,
): ExpandableController {
    return rememberExpandableController(
        color = { color },
        shape = shape,
        contentColor = contentColor,
        borderStroke = borderStroke,
        transitionControllerFactory = transitionControllerFactory,
    )
}

/** Create an [ExpandableController] to control an [Expandable]. */
@Composable
fun rememberExpandableController(
    color: () -> Color,
    shape: Shape,
    contentColor: Color = Color.Unspecified,
    borderStroke: BorderStroke? = null,
    transitionControllerFactory: ComposableControllerFactory? = null,
): ExpandableController {
    val composeViewRoot = LocalView.current
    val density = LocalDensity.current
@@ -125,7 +142,7 @@ fun rememberExpandableController(
}

internal class ExpandableControllerImpl(
    internal val color: Color,
    internal val color: () -> Color,
    internal val contentColor: Color,
    internal val shape: Shape,
    internal val borderStroke: BorderStroke?,
+2 −2
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ import androidx.compose.ui.util.trace
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.animation.Expandable
import com.android.compose.animation.bounceable
import com.android.compose.animation.rememberExpandableController
import com.android.compose.modifiers.thenIf
import com.android.systemui.Flags
import com.android.systemui.animation.Expandable
@@ -260,8 +261,7 @@ private fun TileExpandable(
    content: @Composable (Expandable) -> Unit,
) {
    Expandable(
        color = color(),
        shape = shape,
        controller = rememberExpandableController(color = color, shape = shape),
        modifier = modifier.clip(shape).verticalSquish(squishiness),
        useModifierBasedImplementation = true,
    ) {