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

Commit 2d23c9e6 authored by Andreas Miko's avatar Andreas Miko
Browse files

Clean up computeValue()

This method has become a god method, many vals have similar sounding
variants and large blocks of code do unrelated things that require us
to scroll a lot. I tried breaking them out a bit and clear up naming but
this is far from perfect and we may want to invest more into cleaning
this up. Especially as we add new functionality we should be strict
about not further bloating this method.

Bug: 376659778
Test: REFACTOR_ONLY
Flag: com.android.systemui.scene_container
Change-Id: I9737404e16073b2c81e3474c230c708ce2a7c814
parent 461e3b43
Loading
Loading
Loading
Loading
+195 −154
Original line number Diff line number Diff line
@@ -1307,8 +1307,7 @@ private inline fun <T> computeValue(

    val currentContent = currentContentState.contents.last()

    // The element is shared: interpolate between the value in fromContent and the value in
    // toContent.
    // The element is shared: interpolate between the value in fromContent and toContent.
    // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
    // elements follow the finger direction.
    val isSharedElement = fromState != null && toState != null
@@ -1343,28 +1342,133 @@ private inline fun <T> computeValue(
    // The content for which we compute the transformation. Note that this is not necessarily
    // [currentContent] because [currentContent] could be a different content than the transition
    // fromContent or toContent during interruptions or when a ancestor transition is running.
    val content: ContentKey
    val transformationContentKey: ContentKey =
        getTransformationContentKey(
            isDisabledSharedElement = isSharedElement,
            currentContent = currentContent,
            layoutImpl = layoutImpl,
            transition = transition,
            element = element,
            currentSceneState = currentSceneState,
        )
    // Get the transformed value, i.e. the target value at the beginning (for entering elements) or
    // end (for leaving elements) of the transition.
    val contentState: Element.State
    val targetState: Element.State = element.stateByContent.getValue(transformationContentKey)
    val idleValue = contentValue(targetState)

    val transformationWithRange =
        transformation(
            transition.transformationSpec.transformations(element.key, transformationContentKey)
        )

    val isElementEntering =
        when {
        isSharedElement -> {
            content = currentContent
            contentState = currentContentState
            transformationContentKey == toContent -> true
            transformationContentKey == fromContent -> false
            isAncestorTransition(layoutImpl, transition) ->
                isEnteringAncestorTransition(layoutImpl, transition)
            transformationContentKey == transition.currentScene -> toState == null
            else -> transformationContentKey == toContent
        }

    val previewTransformation =
        transition.previewTransformationSpec?.let {
            transformation(it.transformations(element.key, transformationContentKey))
        }

    if (previewTransformation != null) {
        return computePreviewTransformationValue(
            transition,
            idleValue,
            transformationContentKey,
            isElementEntering,
            previewTransformation,
            element,
            layoutImpl,
            transformationWithRange,
            lerp,
        )
    }

    if (transformationWithRange == null) {
        // If there is no transformation explicitly associated to this element value, let's use
        // the value given by the system (like the current position and size given by the layout
        // pass).
        return currentValue()
    }

    val transformation = transformationWithRange.transformation
    when (transformation) {
        is CustomPropertyTransformation ->
            return with(transformation) {
                layoutImpl.propertyTransformationScope.transform(
                    transformationContentKey,
                    element.key,
                    transition,
                    transition.coroutineScope,
                )
            }
        is InterpolatedPropertyTransformation -> {
            /* continue */
        }
    }

    val targetValue =
        with(transformation) {
            layoutImpl.propertyTransformationScope.transform(
                transformationContentKey,
                element.key,
                transition,
                idleValue,
            )
        }

    // Make sure we don't read progress if values are the same and we don't need to interpolate, so
    // we don't invalidate the phase where this is read.
    if (targetValue == idleValue) {
        return targetValue
    }

    val progress = transition.progress
    // TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
    val rangeProgress = transformationWithRange.range?.progress(progress) ?: progress

    return if (isElementEntering) {
        lerp(targetValue, idleValue, rangeProgress)
    } else {
        lerp(idleValue, targetValue, rangeProgress)
    }
}

private fun getTransformationContentKey(
    isDisabledSharedElement: Boolean,
    currentContent: ContentKey,
    layoutImpl: SceneTransitionLayoutImpl,
    transition: TransitionState.Transition,
    element: Element,
    currentSceneState: Element.State?,
): ContentKey {
    return when {
        isDisabledSharedElement -> {
            currentContent
        }
        isAncestorTransition(layoutImpl, transition) -> {
            if (
                fromState != null &&
                    transition.transformationSpec.hasTransformation(element.key, fromContent)
                element.stateByContent[transition.fromContent] != null &&
                    transition.transformationSpec.hasTransformation(
                        element.key,
                        transition.fromContent,
                    )
            ) {
                content = fromContent
                contentState = fromState
                transition.fromContent
            } else if (
                toState != null &&
                    transition.transformationSpec.hasTransformation(element.key, toContent)
                element.stateByContent[transition.toContent] != null &&
                    transition.transformationSpec.hasTransformation(
                        element.key,
                        transition.toContent,
                    )
            ) {
                content = toContent
                contentState = toState
                transition.toContent
            } else {
                throw IllegalStateException(
                    "Ancestor transition is active but no transformation " +
@@ -1374,31 +1478,30 @@ private inline fun <T> computeValue(
            }
        }
        currentSceneState != null && currentContent == transition.currentScene -> {
            content = currentContent
            contentState = currentSceneState
            currentContent
        }
        fromState != null -> {
            content = fromContent
            contentState = fromState
        element.stateByContent[transition.fromContent] != null -> {
            transition.fromContent
        }
        else -> {
            content = toContent
            contentState = toState!!
            transition.toContent
        }
    }

    val transformationWithRange =
        transformation(transition.transformationSpec.transformations(element.key, content))

    val previewTransformation =
        transition.previewTransformationSpec?.let {
            transformation(it.transformations(element.key, content))
}
    if (previewTransformation != null) {

private inline fun <T> computePreviewTransformationValue(
    transition: TransitionState.Transition,
    idleValue: T,
    transformationContentKey: ContentKey,
    isEntering: Boolean,
    previewTransformation: TransformationWithRange<PropertyTransformation<T>>,
    element: Element,
    layoutImpl: SceneTransitionLayoutImpl,
    transformationWithRange: TransformationWithRange<PropertyTransformation<T>>?,
    lerp: (T, T, Float) -> T,
): T {
    val isInPreviewStage = transition.isInPreviewStage

        val idleValue = contentValue(contentState)
        val isEntering = content == toContent
    val previewTargetValue =
        with(
            previewTransformation.transformation.requireInterpolatedTransformation(
@@ -1409,7 +1512,7 @@ private inline fun <T> computeValue(
            }
        ) {
            layoutImpl.propertyTransformationScope.transform(
                    content,
                transformationContentKey,
                element.key,
                transition,
                idleValue,
@@ -1427,7 +1530,7 @@ private inline fun <T> computeValue(
                }
            ) {
                layoutImpl.propertyTransformationScope.transform(
                        content,
                    transformationContentKey,
                    element.key,
                    transition,
                    idleValue,
@@ -1485,74 +1588,12 @@ private inline fun <T> computeValue(
            lerp(
                lerp(idleValue, previewTargetValue, previewRangeProgress),
                targetValueOrNull,
                    transformationWithRange.range?.progress(transition.progress)
                        ?: transition.progress,
                transformationWithRange.range?.progress(transition.progress) ?: transition.progress,
            )
        }
    }
}

    if (transformationWithRange == null) {
        // If there is no transformation explicitly associated to this element value, let's use
        // the value given by the system (like the current position and size given by the layout
        // pass).
        return currentValue()
    }

    val transformation = transformationWithRange.transformation
    when (transformation) {
        is CustomPropertyTransformation ->
            return with(transformation) {
                layoutImpl.propertyTransformationScope.transform(
                    content,
                    element.key,
                    transition,
                    transition.coroutineScope,
                )
            }
        is InterpolatedPropertyTransformation -> {
            /* continue */
        }
    }

    val idleValue = contentValue(contentState)
    val targetValue =
        with(transformation) {
            layoutImpl.propertyTransformationScope.transform(
                content,
                element.key,
                transition,
                idleValue,
            )
        }

    // Make sure we don't read progress if values are the same and we don't need to interpolate, so
    // we don't invalidate the phase where this is read.
    if (targetValue == idleValue) {
        return targetValue
    }

    val progress = transition.progress
    // TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
    val rangeProgress = transformationWithRange.range?.progress(progress) ?: progress

    // Interpolate between the value at rest and the value before entering/after leaving.
    val isEntering =
        when {
            content == toContent -> true
            content == fromContent -> false
            isAncestorTransition(layoutImpl, transition) ->
                isEnteringAncestorTransition(layoutImpl, transition)
            content == transition.currentScene -> toState == null
            else -> content == toContent
        }
    return if (isEntering) {
        lerp(targetValue, idleValue, rangeProgress)
    } else {
        lerp(idleValue, targetValue, rangeProgress)
    }
}

private fun isAncestorTransition(
    layoutImpl: SceneTransitionLayoutImpl,
    transition: TransitionState.Transition,
@@ -1564,7 +1605,7 @@ private fun isAncestorTransition(

private fun isEnteringAncestorTransition(
    layoutImpl: SceneTransitionLayoutImpl,
    transition: TransitionState.Transition
    transition: TransitionState.Transition,
): Boolean {
    return layoutImpl.ancestors.fastAny { it.inContent == transition.toContent }
}