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.geometry.Offset
20 import com.android.compose.animation.scene.Edge
21 import com.android.compose.animation.scene.Element
22 import com.android.compose.animation.scene.ElementMatcher
23 import com.android.compose.animation.scene.SceneKey
24 import com.android.compose.animation.scene.SceneTransitionLayoutImpl
25 import com.android.compose.animation.scene.TransitionState
26 
27 /** Translate an element from an edge of the layout. */
28 internal class EdgeTranslate(
29     override val matcher: ElementMatcher,
30     private val edge: Edge,
31     private val startsOutsideLayoutBounds: Boolean = true,
32 ) : PropertyTransformation<Offset> {
transformnull33     override fun transform(
34         layoutImpl: SceneTransitionLayoutImpl,
35         scene: SceneKey,
36         element: Element,
37         sceneState: Element.SceneState,
38         transition: TransitionState.Transition,
39         value: Offset
40     ): Offset {
41         val sceneSize = layoutImpl.scene(scene).targetSize
42         val elementSize = sceneState.targetSize
43         if (elementSize == Element.SizeUnspecified) {
44             return value
45         }
46 
47         return when (edge) {
48             Edge.Top ->
49                 if (startsOutsideLayoutBounds) {
50                     Offset(value.x, -elementSize.height.toFloat())
51                 } else {
52                     Offset(value.x, 0f)
53                 }
54             Edge.Left ->
55                 if (startsOutsideLayoutBounds) {
56                     Offset(-elementSize.width.toFloat(), value.y)
57                 } else {
58                     Offset(0f, value.y)
59                 }
60             Edge.Bottom ->
61                 if (startsOutsideLayoutBounds) {
62                     Offset(value.x, sceneSize.height.toFloat())
63                 } else {
64                     Offset(value.x, (sceneSize.height - elementSize.height).toFloat())
65                 }
66             Edge.Right ->
67                 if (startsOutsideLayoutBounds) {
68                     Offset(sceneSize.width.toFloat(), value.y)
69                 } else {
70                     Offset((sceneSize.width - elementSize.width).toFloat(), value.y)
71                 }
72         }
73     }
74 }
75