Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 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 | |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 17 | package androidx.compose.ui.layout |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 18 | |
Mihai Popa | 5836ac4 | 2020-11-06 10:36:03 +0000 | [diff] [blame] | 19 | import androidx.compose.foundation.layout.Box |
| 20 | import androidx.compose.foundation.layout.ExperimentalLayout |
| 21 | import androidx.compose.foundation.layout.IntrinsicSize |
| 22 | import androidx.compose.foundation.layout.preferredWidth |
Louis Pullen-Freilich | 1f10a59 | 2020-07-24 16:35:14 +0100 | [diff] [blame] | 23 | import androidx.compose.runtime.Composable |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 24 | import androidx.compose.runtime.Providers |
Louis Pullen-Freilich | 534385a | 2020-08-14 14:10:12 +0100 | [diff] [blame] | 25 | import androidx.compose.runtime.mutableStateOf |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 26 | import androidx.compose.ui.FixedSize |
Louis Pullen-Freilich | 534385a | 2020-08-14 14:10:12 +0100 | [diff] [blame] | 27 | import androidx.compose.ui.Modifier |
| 28 | import androidx.compose.ui.geometry.Offset |
Louis Pullen-Freilich | a03fd6c | 2020-07-24 23:26:29 +0100 | [diff] [blame] | 29 | import androidx.compose.ui.node.Ref |
Louis Pullen-Freilich | 209df68 | 2020-11-11 00:13:18 +0000 | [diff] [blame] | 30 | import androidx.compose.ui.platform.AmbientLayoutDirection |
Louis Pullen-Freilich | a03fd6c | 2020-07-24 23:26:29 +0100 | [diff] [blame] | 31 | import androidx.compose.ui.platform.setContent |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 32 | import androidx.compose.ui.runOnUiThreadIR |
| 33 | import androidx.compose.ui.test.TestActivity |
Louis Pullen-Freilich | a7eeb10 | 2020-07-22 17:54:24 +0100 | [diff] [blame] | 34 | import androidx.compose.ui.unit.Density |
Louis Pullen-Freilich | 534385a | 2020-08-14 14:10:12 +0100 | [diff] [blame] | 35 | import androidx.compose.ui.unit.LayoutDirection |
Filip Pavlis | ce148943 | 2020-10-29 12:18:06 +0000 | [diff] [blame] | 36 | import androidx.test.ext.junit.runners.AndroidJUnit4 |
Louis Pullen-Freilich | 534385a | 2020-08-14 14:10:12 +0100 | [diff] [blame] | 37 | import androidx.test.filters.SmallTest |
Mihai Popa | 5836ac4 | 2020-11-06 10:36:03 +0000 | [diff] [blame] | 38 | import org.junit.Assert |
Mihai Popa | fe2f8fa | 2020-04-21 18:00:21 +0100 | [diff] [blame] | 39 | import org.junit.Assert.assertEquals |
| 40 | import org.junit.Assert.assertTrue |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 41 | import org.junit.Before |
| 42 | import org.junit.Rule |
| 43 | import org.junit.Test |
| 44 | import org.junit.runner.RunWith |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 45 | import java.util.concurrent.CountDownLatch |
| 46 | import java.util.concurrent.TimeUnit |
| 47 | |
| 48 | @SmallTest |
Jelle Fresen | 17628d7 | 2020-09-24 16:23:51 +0100 | [diff] [blame] | 49 | @RunWith(AndroidJUnit4::class) |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 50 | class RtlLayoutTest { |
Aurimas Liutikas | 506ab64d | 2020-06-02 14:37:26 -0700 | [diff] [blame] | 51 | @Suppress("DEPRECATION") |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 52 | @get:Rule |
Aurimas Liutikas | 506ab64d | 2020-06-02 14:37:26 -0700 | [diff] [blame] | 53 | val activityTestRule = |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 54 | androidx.test.rule.ActivityTestRule<TestActivity>( |
Jeff Gaston | a3bbb7e | 2020-09-18 15:11:15 -0400 | [diff] [blame] | 55 | TestActivity::class.java |
| 56 | ) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 57 | private lateinit var activity: TestActivity |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 58 | internal lateinit var density: Density |
| 59 | internal lateinit var countDownLatch: CountDownLatch |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 60 | internal lateinit var position: Array<Ref<Offset>> |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 61 | private val size = 100 |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 62 | |
| 63 | @Before |
| 64 | fun setup() { |
| 65 | activity = activityTestRule.activity |
| 66 | density = Density(activity) |
| 67 | activity.hasFocusLatch.await(5, TimeUnit.SECONDS) |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 68 | position = Array(3) { Ref<Offset>() } |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 69 | countDownLatch = CountDownLatch(3) |
| 70 | } |
| 71 | |
| 72 | @Test |
| 73 | fun customLayout_absolutePositioning() = with(density) { |
| 74 | activityTestRule.runOnUiThreadIR { |
Andrey Kulikov | 1526ea5 | 2020-04-07 18:43:27 +0100 | [diff] [blame] | 75 | activity.setContent { |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 76 | CustomLayout(true, LayoutDirection.Ltr) |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | countDownLatch.await(1, TimeUnit.SECONDS) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 81 | assertEquals(Offset(0f, 0f), position[0].value) |
| 82 | assertEquals(Offset(size.toFloat(), size.toFloat()), position[1].value) |
| 83 | assertEquals( |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 84 | Offset( |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 85 | (size * 2).toFloat(), |
| 86 | (size * 2).toFloat() |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 87 | ), |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 88 | position[2].value |
| 89 | ) |
| 90 | } |
| 91 | |
| 92 | @Test |
| 93 | fun customLayout_absolutePositioning_rtl() = with(density) { |
| 94 | activityTestRule.runOnUiThreadIR { |
Andrey Kulikov | 1526ea5 | 2020-04-07 18:43:27 +0100 | [diff] [blame] | 95 | activity.setContent { |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 96 | CustomLayout(true, LayoutDirection.Rtl) |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | countDownLatch.await(1, TimeUnit.SECONDS) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 101 | assertEquals( |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 102 | Offset(0f, 0f), |
| 103 | position[0].value |
| 104 | ) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 105 | assertEquals( |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 106 | Offset( |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 107 | size.toFloat(), |
| 108 | size.toFloat() |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 109 | ), |
| 110 | position[1].value |
| 111 | ) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 112 | assertEquals( |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 113 | Offset( |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 114 | (size * 2).toFloat(), |
| 115 | (size * 2).toFloat() |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 116 | ), |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 117 | position[2].value |
| 118 | ) |
| 119 | } |
| 120 | |
| 121 | @Test |
| 122 | fun customLayout_positioning() = with(density) { |
| 123 | activityTestRule.runOnUiThreadIR { |
Andrey Kulikov | 1526ea5 | 2020-04-07 18:43:27 +0100 | [diff] [blame] | 124 | activity.setContent { |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 125 | CustomLayout(false, LayoutDirection.Ltr) |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | countDownLatch.await(1, TimeUnit.SECONDS) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 130 | assertEquals(Offset(0f, 0f), position[0].value) |
| 131 | assertEquals(Offset(size.toFloat(), size.toFloat()), position[1].value) |
| 132 | assertEquals( |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 133 | Offset( |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 134 | (size * 2).toFloat(), |
| 135 | (size * 2).toFloat() |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 136 | ), |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 137 | position[2].value |
| 138 | ) |
| 139 | } |
| 140 | |
| 141 | @Test |
| 142 | fun customLayout_positioning_rtl() = with(density) { |
| 143 | activityTestRule.runOnUiThreadIR { |
Andrey Kulikov | 1526ea5 | 2020-04-07 18:43:27 +0100 | [diff] [blame] | 144 | activity.setContent { |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 145 | CustomLayout(false, LayoutDirection.Rtl) |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | countDownLatch.await(1, TimeUnit.SECONDS) |
| 150 | |
| 151 | countDownLatch.await(1, TimeUnit.SECONDS) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 152 | assertEquals( |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 153 | Offset( |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 154 | (size * 2).toFloat(), |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 155 | 0f |
| 156 | ), |
| 157 | position[0].value |
| 158 | ) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 159 | assertEquals( |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 160 | Offset(size.toFloat(), size.toFloat()), |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 161 | position[1].value |
| 162 | ) |
Louis Pullen-Freilich | a11fd94 | 2020-07-24 19:31:19 +0100 | [diff] [blame] | 163 | assertEquals(Offset(0f, (size * 2).toFloat()), position[2].value) |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 164 | } |
| 165 | |
Mihai Popa | fc355b1 | 2020-04-15 17:34:17 +0100 | [diff] [blame] | 166 | @Test |
Andrey Kulikov | f437d21 | 2020-05-06 14:25:10 +0100 | [diff] [blame] | 167 | fun customLayout_updatingDirectionCausesRemeasure() { |
| 168 | val direction = mutableStateOf(LayoutDirection.Rtl) |
| 169 | var latch = CountDownLatch(1) |
| 170 | var actualDirection: LayoutDirection? = null |
| 171 | |
| 172 | activityTestRule.runOnUiThread { |
| 173 | activity.setContent { |
| 174 | val children = @Composable { |
Anastasia Soboleva | 5e382dd | 2020-06-17 21:51:38 +0100 | [diff] [blame] | 175 | Layout({}) { _, _ -> |
Andrey Kulikov | f437d21 | 2020-05-06 14:25:10 +0100 | [diff] [blame] | 176 | actualDirection = layoutDirection |
| 177 | latch.countDown() |
George Mount | 8f23757 | 2020-04-30 12:08:30 -0700 | [diff] [blame] | 178 | layout(100, 100) {} |
Andrey Kulikov | f437d21 | 2020-05-06 14:25:10 +0100 | [diff] [blame] | 179 | } |
| 180 | } |
Louis Pullen-Freilich | 209df68 | 2020-11-11 00:13:18 +0000 | [diff] [blame] | 181 | Providers(AmbientLayoutDirection provides direction.value) { |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 182 | Layout(children) { measurables, constraints -> |
| 183 | layout(100, 100) { |
Anastasia Soboleva | 63cab53 | 2020-08-06 11:06:37 +0100 | [diff] [blame] | 184 | measurables.first().measure(constraints).placeRelative(0, 0) |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 185 | } |
Andrey Kulikov | f437d21 | 2020-05-06 14:25:10 +0100 | [diff] [blame] | 186 | } |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | assertTrue(latch.await(1, TimeUnit.SECONDS)) |
| 191 | assertEquals(LayoutDirection.Rtl, actualDirection) |
| 192 | |
| 193 | latch = CountDownLatch(1) |
| 194 | activityTestRule.runOnUiThread { direction.value = LayoutDirection.Ltr } |
| 195 | |
| 196 | assertTrue(latch.await(1, TimeUnit.SECONDS)) |
| 197 | assertEquals(LayoutDirection.Ltr, actualDirection) |
| 198 | } |
Mihai Popa | 5836ac4 | 2020-11-06 10:36:03 +0000 | [diff] [blame] | 199 | @Test |
| 200 | fun testModifiedLayoutDirection_inMeasureScope() { |
| 201 | val latch = CountDownLatch(1) |
| 202 | val resultLayoutDirection = Ref<LayoutDirection>() |
| 203 | |
| 204 | activityTestRule.runOnUiThread { |
| 205 | activity.setContent { |
| 206 | Providers(AmbientLayoutDirection provides LayoutDirection.Rtl) { |
| 207 | Layout(content = {}) { _, _ -> |
| 208 | resultLayoutDirection.value = layoutDirection |
| 209 | latch.countDown() |
| 210 | layout(0, 0) {} |
| 211 | } |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | assertTrue(latch.await(1, TimeUnit.SECONDS)) |
| 217 | assertTrue(LayoutDirection.Rtl == resultLayoutDirection.value) |
| 218 | } |
| 219 | |
| 220 | @Test |
| 221 | fun testModifiedLayoutDirection_inIntrinsicsMeasure() { |
| 222 | val latch = CountDownLatch(1) |
| 223 | var resultLayoutDirection: LayoutDirection? = null |
| 224 | |
| 225 | activityTestRule.runOnUiThread { |
| 226 | activity.setContent { |
| 227 | @OptIn(ExperimentalLayout::class) |
| 228 | Providers(AmbientLayoutDirection provides LayoutDirection.Rtl) { |
| 229 | Layout( |
| 230 | content = {}, |
| 231 | modifier = Modifier.preferredWidth(IntrinsicSize.Max), |
| 232 | minIntrinsicWidthMeasureBlock = { _, _ -> 0 }, |
| 233 | minIntrinsicHeightMeasureBlock = { _, _ -> 0 }, |
| 234 | maxIntrinsicWidthMeasureBlock = { _, _ -> |
| 235 | resultLayoutDirection = this.layoutDirection |
| 236 | latch.countDown() |
| 237 | 0 |
| 238 | }, |
| 239 | maxIntrinsicHeightMeasureBlock = { _, _ -> 0 } |
| 240 | ) { _, _ -> |
| 241 | layout(0, 0) {} |
| 242 | } |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | assertTrue(latch.await(1, TimeUnit.SECONDS)) |
| 248 | Assert.assertNotNull(resultLayoutDirection) |
| 249 | assertTrue(LayoutDirection.Rtl == resultLayoutDirection) |
| 250 | } |
| 251 | |
| 252 | @Test |
| 253 | fun testRestoreLocaleLayoutDirection() { |
| 254 | val latch = CountDownLatch(1) |
| 255 | val resultLayoutDirection = Ref<LayoutDirection>() |
| 256 | |
| 257 | activityTestRule.runOnUiThread { |
| 258 | activity.setContent { |
| 259 | val initialLayoutDirection = AmbientLayoutDirection.current |
| 260 | Providers(AmbientLayoutDirection provides LayoutDirection.Rtl) { |
| 261 | Box { |
| 262 | Providers(AmbientLayoutDirection provides initialLayoutDirection) { |
Leland Richardson | 18f7455 | 2021-01-25 18:34:20 -0800 | [diff] [blame] | 263 | Layout({}) { _, _ -> |
Mihai Popa | 5836ac4 | 2020-11-06 10:36:03 +0000 | [diff] [blame] | 264 | resultLayoutDirection.value = layoutDirection |
| 265 | latch.countDown() |
| 266 | layout(0, 0) {} |
| 267 | } |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | assertTrue(latch.await(1, TimeUnit.SECONDS)) |
| 275 | assertEquals(LayoutDirection.Ltr, resultLayoutDirection.value) |
| 276 | } |
Andrey Kulikov | f437d21 | 2020-05-06 14:25:10 +0100 | [diff] [blame] | 277 | |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 278 | @Composable |
| 279 | private fun CustomLayout( |
| 280 | absolutePositioning: Boolean, |
| 281 | testLayoutDirection: LayoutDirection |
| 282 | ) { |
Louis Pullen-Freilich | 209df68 | 2020-11-11 00:13:18 +0000 | [diff] [blame] | 283 | Providers(AmbientLayoutDirection provides testLayoutDirection) { |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 284 | Layout( |
Mihai Popa | 5836ac4 | 2020-11-06 10:36:03 +0000 | [diff] [blame] | 285 | content = { |
| 286 | FixedSize(size, modifier = Modifier.saveLayoutInfo(position[0], countDownLatch)) |
| 287 | FixedSize(size, modifier = Modifier.saveLayoutInfo(position[1], countDownLatch)) |
| 288 | FixedSize(size, modifier = Modifier.saveLayoutInfo(position[2], countDownLatch)) |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 289 | } |
| 290 | ) { measurables, constraints -> |
| 291 | val placeables = measurables.map { it.measure(constraints) } |
| 292 | val width = placeables.fold(0) { sum, p -> sum + p.width } |
| 293 | val height = placeables.fold(0) { sum, p -> sum + p.height } |
| 294 | layout(width, height) { |
Andrey Kulikov | 33185fb | 2020-11-06 15:45:30 +0000 | [diff] [blame] | 295 | var x = 0 |
| 296 | var y = 0 |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 297 | for (placeable in placeables) { |
| 298 | if (absolutePositioning) { |
Andrey Kulikov | 33185fb | 2020-11-06 15:45:30 +0000 | [diff] [blame] | 299 | placeable.place(x, y) |
Anastasia Soboleva | 63cab53 | 2020-08-06 11:06:37 +0100 | [diff] [blame] | 300 | } else { |
Andrey Kulikov | 33185fb | 2020-11-06 15:45:30 +0000 | [diff] [blame] | 301 | placeable.placeRelative(x, y) |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 302 | } |
Andrey Kulikov | 33185fb | 2020-11-06 15:45:30 +0000 | [diff] [blame] | 303 | x += placeable.width |
| 304 | y += placeable.height |
Anastasia Soboleva | 2833c36 | 2020-07-23 20:19:13 +0100 | [diff] [blame] | 305 | } |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 306 | } |
| 307 | } |
| 308 | } |
| 309 | } |
| 310 | |
Louis Pullen-Freilich | 46bf1f1 | 2020-11-16 16:58:49 +0000 | [diff] [blame] | 311 | private fun Modifier.saveLayoutInfo( |
Nader Jawad | 6df0612 | 2020-06-03 15:27:08 -0700 | [diff] [blame] | 312 | position: Ref<Offset>, |
George Mount | d02af60 | 2020-03-06 16:41:40 -0800 | [diff] [blame] | 313 | countDownLatch: CountDownLatch |
Louis Pullen-Freilich | 46bf1f1 | 2020-11-16 16:58:49 +0000 | [diff] [blame] | 314 | ): Modifier = onGloballyPositioned { |
Filip Pavlis | a1dc264 | 2020-07-15 19:23:33 +0100 | [diff] [blame] | 315 | position.value = it.localToRoot(Offset(0f, 0f)) |
George Mount | d02af60 | 2020-03-06 16:41:40 -0800 | [diff] [blame] | 316 | countDownLatch.countDown() |
Anastasia Soboleva | adfed53 | 2020-03-02 12:00:07 +0000 | [diff] [blame] | 317 | } |
Mihai Popa | fe2f8fa | 2020-04-21 18:00:21 +0100 | [diff] [blame] | 318 | } |