1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.compose.animation.scene.transformation
18 
19 import androidx.compose.ui.unit.IntSize
20 import com.android.compose.animation.scene.ContentKey
21 import com.android.compose.animation.scene.ElementKey
22 import com.android.compose.animation.scene.content.state.TransitionState
23 
24 /** Anchor the size of an element to the size of another element. */
25 internal class AnchoredSize
26 private constructor(
27     private val anchor: ElementKey,
28     private val anchorWidth: Boolean,
29     private val anchorHeight: Boolean,
30 ) : InterpolatedPropertyTransformation<IntSize> {
31     override val property = PropertyTransformation.Property.Size
32 
transformnull33     override fun PropertyTransformationScope.transform(
34         content: ContentKey,
35         element: ElementKey,
36         transition: TransitionState.Transition,
37         idleValue: IntSize,
38     ): IntSize {
39         fun anchorSizeIn(content: ContentKey): IntSize {
40             val size =
41                 anchor.targetSize(content)
42                     ?: throwMissingAnchorException(
43                         transformation = "AnchoredSize",
44                         anchor = anchor,
45                         content = content,
46                     )
47 
48             return IntSize(
49                 width = if (anchorWidth) size.width else idleValue.width,
50                 height = if (anchorHeight) size.height else idleValue.height,
51             )
52         }
53 
54         // This simple implementation assumes that the size of [element] is the same as the size of
55         // the [anchor] in [scene], so simply transform to the size of the anchor in the other
56         // scene.
57         return if (content == transition.fromContent) {
58             anchorSizeIn(transition.toContent)
59         } else {
60             anchorSizeIn(transition.fromContent)
61         }
62     }
63 
64     class Factory(
65         private val anchor: ElementKey,
66         private val anchorWidth: Boolean,
67         private val anchorHeight: Boolean,
68     ) : Transformation.Factory {
createnull69         override fun create(): Transformation = AnchoredSize(anchor, anchorWidth, anchorHeight)
70     }
71 }
72