1 /*
2 * Copyright 2022 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 androidx.compose.foundation.layout
18
19 import androidx.compose.runtime.Composable
20 import androidx.compose.runtime.Immutable
21 import androidx.compose.runtime.ReadOnlyComposable
22 import androidx.compose.runtime.Stable
23 import androidx.compose.runtime.getValue
24 import androidx.compose.runtime.mutableStateOf
25 import androidx.compose.runtime.setValue
26 import androidx.compose.ui.Modifier
27 import androidx.compose.ui.platform.LocalDensity
28 import androidx.compose.ui.unit.Density
29 import androidx.compose.ui.unit.Dp
30 import androidx.compose.ui.unit.LayoutDirection
31 import androidx.compose.ui.unit.dp
32
33 /**
34 * A representation of window insets that tracks access to enable recomposition, relayout, and
35 * redrawing when values change. These values should not be read during composition to avoid doing
36 * composition for every frame of an animation. Use methods like [Modifier.windowInsetsPadding],
37 * [Modifier.systemBarsPadding], and [Modifier.windowInsetsTopHeight] for Modifiers that will not
38 * cause recomposition when values change.
39 *
40 * Use the [WindowInsets.Companion] extensions to retrieve [WindowInsets] for the current window.
41 */
42 @Stable
43 interface WindowInsets {
44 /** The space, in pixels, at the left of the window that the inset represents. */
getLeftnull45 fun getLeft(density: Density, layoutDirection: LayoutDirection): Int
46
47 /** The space, in pixels, at the top of the window that the inset represents. */
48 fun getTop(density: Density): Int
49
50 /** The space, in pixels, at the right of the window that the inset represents. */
51 fun getRight(density: Density, layoutDirection: LayoutDirection): Int
52
53 /** The space, in pixels, at the bottom of the window that the inset represents. */
54 fun getBottom(density: Density): Int
55
56 companion object
57 }
58
59 /**
60 * A [WindowInsets] whose values can change without changing the instance. This is useful to avoid
61 * recomposition when [WindowInsets] can change.
62 *
63 * @sample androidx.compose.foundation.layout.samples.withConsumedInsetsSample
64 *
65 * Note: This API as experimental since it doesn't enforce the right consumption patterns.
66 */
67 @ExperimentalLayoutApi
68 class MutableWindowInsets(initialInsets: WindowInsets = WindowInsets(0, 0, 0, 0)) : WindowInsets {
69 /**
70 * The [WindowInsets] that are used for [left][getLeft], [top][getTop], [right][getRight], and
71 * [bottom][getBottom] values.
72 */
73 var insets by mutableStateOf(initialInsets)
74
75 override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int =
76 insets.getLeft(density, layoutDirection)
77
78 override fun getTop(density: Density): Int = insets.getTop(density)
79
80 override fun getRight(density: Density, layoutDirection: LayoutDirection): Int =
81 insets.getRight(density, layoutDirection)
82
83 override fun getBottom(density: Density): Int = insets.getBottom(density)
84 }
85
86 /**
87 * [WindowInsetsSides] is used in [WindowInsets.only] to define which sides of the [WindowInsets]
88 * should apply.
89 */
90 @kotlin.jvm.JvmInline
91 value class WindowInsetsSides private constructor(private val value: Int) {
92 /** Returns a [WindowInsetsSides] containing sides defied in [sides] and the sides in `this`. */
plusnull93 operator fun plus(sides: WindowInsetsSides): WindowInsetsSides =
94 WindowInsetsSides(value or sides.value)
95
96 internal fun hasAny(sides: WindowInsetsSides): Boolean = (value and sides.value) != 0
97
98 override fun toString(): String = "WindowInsetsSides(${valueToString()})"
99
100 private fun valueToString(): String = buildString {
101 fun appendPlus(text: String) {
102 if (isNotEmpty()) append('+')
103 append(text)
104 }
105
106 if (value and Start.value == Start.value) appendPlus("Start")
107 if (value and Left.value == Left.value) appendPlus("Left")
108 if (value and Top.value == Top.value) appendPlus("Top")
109 if (value and End.value == End.value) appendPlus("End")
110 if (value and Right.value == Right.value) appendPlus("Right")
111 if (value and Bottom.value == Bottom.value) appendPlus("Bottom")
112 }
113
114 companion object {
115 // _---- allowLeft in ltr
116 // /
117 // | _--- allowRight in ltr
118 // |/
119 // || _-- allowLeft in rtl
120 // ||/
121 // ||| _- allowRight in rtl
122 // |||/
123 // VVVV
124 // Mask = ----
125 //
126 // Left = 1010
127 // Right = 0101
128 // Start = 1001
129 // End = 0110
130
131 internal val AllowLeftInLtr = WindowInsetsSides(1 shl 3)
132 internal val AllowRightInLtr = WindowInsetsSides(1 shl 2)
133 internal val AllowLeftInRtl = WindowInsetsSides(1 shl 1)
134 internal val AllowRightInRtl = WindowInsetsSides(1 shl 0)
135
136 /**
137 * Indicates a [WindowInsets] start side, which is left or right depending on
138 * [LayoutDirection]. If [LayoutDirection.Ltr], [Start] is the left side. If
139 * [LayoutDirection.Rtl], [Start] is the right side.
140 *
141 * Use [Left] or [Right] if the physical direction is required.
142 */
143 val Start = AllowLeftInLtr + AllowRightInRtl
144
145 /**
146 * Indicates a [WindowInsets] end side, which is left or right depending on
147 * [LayoutDirection]. If [LayoutDirection.Ltr], [End] is the right side. If
148 * [LayoutDirection.Rtl], [End] is the left side.
149 *
150 * Use [Left] or [Right] if the physical direction is required.
151 */
152 val End = AllowRightInLtr + AllowLeftInRtl
153
154 /** Indicates a [WindowInsets] top side. */
155 val Top = WindowInsetsSides(1 shl 4)
156
157 /** Indicates a [WindowInsets] bottom side. */
158 val Bottom = WindowInsetsSides(1 shl 5)
159
160 /**
161 * Indicates a [WindowInsets] left side. Most layouts will prefer using [Start] or [End] to
162 * account for [LayoutDirection].
163 */
164 val Left = AllowLeftInLtr + AllowLeftInRtl
165
166 /**
167 * Indicates a [WindowInsets] right side. Most layouts will prefer using [Start] or [End] to
168 * account for [LayoutDirection].
169 */
170 val Right = AllowRightInLtr + AllowRightInRtl
171
172 /**
173 * Indicates a [WindowInsets] horizontal sides. This is a combination of [Left] and [Right]
174 * sides, or [Start] and [End] sides.
175 */
176 val Horizontal = Left + Right
177
178 /** Indicates a [WindowInsets] [Top] and [Bottom] sides. */
179 val Vertical = Top + Bottom
180 }
181 }
182
183 /** Returns a [WindowInsets] that has the maximum values of this [WindowInsets] and [insets]. */
WindowInsetsnull184 fun WindowInsets.union(insets: WindowInsets): WindowInsets = UnionInsets(this, insets)
185
186 /**
187 * Returns the values in this [WindowInsets] that are not also in [insets]. For example, if this
188 * [WindowInsets] has a [WindowInsets.getTop] value of `10` and [insets] has a [WindowInsets.getTop]
189 * value of `8`, the returned [WindowInsets] will have a [WindowInsets.getTop] value of `2`.
190 *
191 * Negative values are never returned. For example if [insets] has a [WindowInsets.getTop] of `10`
192 * and this has a [WindowInsets.getTop] of `0`, the returned [WindowInsets] will have a
193 * [WindowInsets.getTop] value of `0`.
194 */
195 fun WindowInsets.exclude(insets: WindowInsets): WindowInsets = ExcludeInsets(this, insets)
196
197 /**
198 * Returns a [WindowInsets] that has values of this, added to the values of [insets]. For example,
199 * if this has a top of 10 and insets has a top of 5, the returned [WindowInsets] will have a top
200 * of 15.
201 */
202 fun WindowInsets.add(insets: WindowInsets): WindowInsets = AddedInsets(this, insets)
203
204 /**
205 * Returns a [WindowInsets] that eliminates all dimensions except the ones that are enabled. For
206 * example, to have a [WindowInsets] at the bottom of the screen, pass [WindowInsetsSides.Bottom].
207 */
208 fun WindowInsets.only(sides: WindowInsetsSides): WindowInsets = LimitInsets(this, sides)
209
210 /**
211 * Convert a [WindowInsets] to a [PaddingValues] and uses [LocalDensity] for DP to pixel conversion.
212 * [PaddingValues] can be passed to some containers to pad internal content so that it doesn't
213 * overlap the insets when fully scrolled. Ensure that the insets are
214 * [consumed][consumeWindowInsets] after the padding is applied if insets are to be used further
215 * down the hierarchy.
216 *
217 * @sample androidx.compose.foundation.layout.samples.paddingValuesSample
218 */
219 @ReadOnlyComposable
220 @Composable
221 fun WindowInsets.asPaddingValues(): PaddingValues = InsetsPaddingValues(this, LocalDensity.current)
222
223 /**
224 * Convert a [WindowInsets] to a [PaddingValues] and uses [density] for DP to pixel conversion.
225 * [PaddingValues] can be passed to some containers to pad internal content so that it doesn't
226 * overlap the insets when fully scrolled. Ensure that the insets are
227 * [consumed][consumeWindowInsets] after the padding is applied if insets are to be used further
228 * down the hierarchy.
229 *
230 * @sample androidx.compose.foundation.layout.samples.paddingValuesSample
231 */
232 fun WindowInsets.asPaddingValues(density: Density): PaddingValues =
233 InsetsPaddingValues(this, density)
234
235 /** Convert a [PaddingValues] to a [WindowInsets]. */
236 internal fun PaddingValues.asInsets(): WindowInsets = PaddingValuesInsets(this)
237
238 /** Create a [WindowInsets] with fixed dimensions of 0 on all sides. */
239 fun WindowInsets(): WindowInsets = EmptyWindowInsets
240
241 /**
242 * Create a [WindowInsets] with fixed dimensions.
243 *
244 * @sample androidx.compose.foundation.layout.samples.insetsInt
245 */
246 fun WindowInsets(left: Int = 0, top: Int = 0, right: Int = 0, bottom: Int = 0): WindowInsets =
247 FixedIntInsets(left, top, right, bottom)
248
249 /**
250 * Create a [WindowInsets] with fixed dimensions, using [Dp] values.
251 *
252 * @sample androidx.compose.foundation.layout.samples.insetsDp
253 */
254 fun WindowInsets(
255 left: Dp = 0.dp,
256 top: Dp = 0.dp,
257 right: Dp = 0.dp,
258 bottom: Dp = 0.dp
259 ): WindowInsets = FixedDpInsets(left, top, right, bottom)
260
261 @Immutable
262 private class FixedIntInsets(
263 private val leftVal: Int,
264 private val topVal: Int,
265 private val rightVal: Int,
266 private val bottomVal: Int
267 ) : WindowInsets {
268 override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int = leftVal
269
270 override fun getTop(density: Density): Int = topVal
271
272 override fun getRight(density: Density, layoutDirection: LayoutDirection): Int = rightVal
273
274 override fun getBottom(density: Density): Int = bottomVal
275
276 override fun toString(): String {
277 return "Insets(left=$leftVal, top=$topVal, right=$rightVal, bottom=$bottomVal)"
278 }
279
280 override fun equals(other: Any?): Boolean {
281 if (this === other) {
282 return true
283 }
284 if (other !is FixedIntInsets) {
285 return false
286 }
287
288 return leftVal == other.leftVal &&
289 topVal == other.topVal &&
290 rightVal == other.rightVal &&
291 bottomVal == other.bottomVal
292 }
293
294 override fun hashCode(): Int {
295 var result = leftVal
296 result = 31 * result + topVal
297 result = 31 * result + rightVal
298 result = 31 * result + bottomVal
299 return result
300 }
301 }
302
303 @Immutable
304 private class FixedDpInsets(
305 private val leftDp: Dp,
306 private val topDp: Dp,
307 private val rightDp: Dp,
308 private val bottomDp: Dp
309 ) : WindowInsets {
getLeftnull310 override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
311 with(density) { leftDp.roundToPx() }
312
<lambda>null313 override fun getTop(density: Density) = with(density) { topDp.roundToPx() }
314
getRightnull315 override fun getRight(density: Density, layoutDirection: LayoutDirection) =
316 with(density) { rightDp.roundToPx() }
317
<lambda>null318 override fun getBottom(density: Density) = with(density) { bottomDp.roundToPx() }
319
toStringnull320 override fun toString(): String {
321 return "Insets(left=$leftDp, top=$topDp, right=$rightDp, bottom=$bottomDp)"
322 }
323
equalsnull324 override fun equals(other: Any?): Boolean {
325 if (this === other) {
326 return true
327 }
328 if (other !is FixedDpInsets) {
329 return false
330 }
331
332 return leftDp == other.leftDp &&
333 topDp == other.topDp &&
334 rightDp == other.rightDp &&
335 bottomDp == other.bottomDp
336 }
337
hashCodenull338 override fun hashCode(): Int {
339 var result = leftDp.hashCode()
340 result = 31 * result + topDp.hashCode()
341 result = 31 * result + rightDp.hashCode()
342 result = 31 * result + bottomDp.hashCode()
343 return result
344 }
345 }
346
347 private val EmptyWindowInsets = FixedIntInsets(0, 0, 0, 0)
348
349 /**
350 * An [WindowInsets] that comes straight from [androidx.core.graphics.Insets], whose value can be
351 * updated.
352 */
353 @Stable
354 internal class ValueInsets(insets: InsetsValues, val name: String) : WindowInsets {
355 internal var value by mutableStateOf(insets)
356
getLeftnull357 override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int = value.left
358
359 override fun getTop(density: Density) = value.top
360
361 override fun getRight(density: Density, layoutDirection: LayoutDirection) = value.right
362
363 override fun getBottom(density: Density) = value.bottom
364
365 override fun equals(other: Any?): Boolean {
366 if (other === this) {
367 return true
368 }
369 if (other !is ValueInsets) {
370 return false
371 }
372 return value == other.value
373 }
374
hashCodenull375 override fun hashCode(): Int {
376 return name.hashCode()
377 }
378
toStringnull379 override fun toString(): String {
380 return "$name(left=${value.left}, top=${value.top}, " +
381 "right=${value.right}, bottom=${value.bottom})"
382 }
383 }
384
385 @Immutable
386 internal class InsetsValues(val left: Int, val top: Int, val right: Int, val bottom: Int) {
equalsnull387 override fun equals(other: Any?): Boolean {
388 if (this === other) {
389 return true
390 }
391 if (other !is InsetsValues) {
392 return false
393 }
394
395 return left == other.left &&
396 top == other.top &&
397 right == other.right &&
398 bottom == other.bottom
399 }
400
hashCodenull401 override fun hashCode(): Int {
402 var result = left
403 result = 31 * result + top
404 result = 31 * result + right
405 result = 31 * result + bottom
406 return result
407 }
408
toStringnull409 override fun toString(): String =
410 "InsetsValues(left=$left, top=$top, right=$right, bottom=$bottom)"
411 }
412
413 /**
414 * An [WindowInsets] that includes the maximum value of [first] and [second] as returned from
415 * [WindowInsets.union].
416 */
417 @Stable
418 private class UnionInsets(private val first: WindowInsets, private val second: WindowInsets) :
419 WindowInsets {
420 override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
421 maxOf(first.getLeft(density, layoutDirection), second.getLeft(density, layoutDirection))
422
423 override fun getTop(density: Density) = maxOf(first.getTop(density), second.getTop(density))
424
425 override fun getRight(density: Density, layoutDirection: LayoutDirection) =
426 maxOf(first.getRight(density, layoutDirection), second.getRight(density, layoutDirection))
427
428 override fun getBottom(density: Density) =
429 maxOf(first.getBottom(density), second.getBottom(density))
430
431 override fun hashCode(): Int = first.hashCode() + second.hashCode() * 31
432
433 override fun equals(other: Any?): Boolean {
434 if (this === other) {
435 return true
436 }
437 if (other !is UnionInsets) {
438 return false
439 }
440 return other.first == first && other.second == second
441 }
442
443 override fun toString(): String = "($first ∪ $second)"
444 }
445
446 /** An [WindowInsets] that includes the added value of [first] to [second]. */
447 @Stable
448 private class AddedInsets(private val first: WindowInsets, private val second: WindowInsets) :
449 WindowInsets {
getLeftnull450 override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
451 first.getLeft(density, layoutDirection) + second.getLeft(density, layoutDirection)
452
453 override fun getTop(density: Density) = first.getTop(density) + second.getTop(density)
454
455 override fun getRight(density: Density, layoutDirection: LayoutDirection) =
456 first.getRight(density, layoutDirection) + second.getRight(density, layoutDirection)
457
458 override fun getBottom(density: Density) = first.getBottom(density) + second.getBottom(density)
459
460 override fun hashCode(): Int = first.hashCode() + second.hashCode() * 31
461
462 override fun equals(other: Any?): Boolean {
463 if (this === other) {
464 return true
465 }
466 if (other !is AddedInsets) {
467 return false
468 }
469 return other.first == first && other.second == second
470 }
471
toStringnull472 override fun toString(): String = "($first + $second)"
473 }
474
475 /**
476 * An [WindowInsets] that includes the value of [included] that is not included in [excluded] as
477 * returned from [WindowInsets.exclude].
478 */
479 @Stable
480 private class ExcludeInsets(
481 private val included: WindowInsets,
482 private val excluded: WindowInsets
483 ) : WindowInsets {
484 override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
485 (included.getLeft(density, layoutDirection) - excluded.getLeft(density, layoutDirection))
486 .coerceAtLeast(0)
487
488 override fun getTop(density: Density) =
489 (included.getTop(density) - excluded.getTop(density)).coerceAtLeast(0)
490
491 override fun getRight(density: Density, layoutDirection: LayoutDirection) =
492 (included.getRight(density, layoutDirection) - excluded.getRight(density, layoutDirection))
493 .coerceAtLeast(0)
494
495 override fun getBottom(density: Density) =
496 (included.getBottom(density) - excluded.getBottom(density)).coerceAtLeast(0)
497
498 override fun toString(): String = "($included - $excluded)"
499
500 override fun equals(other: Any?): Boolean {
501 if (this === other) {
502 return true
503 }
504 if (other !is ExcludeInsets) {
505 return false
506 }
507
508 return (other.included == included && other.excluded == excluded)
509 }
510
511 override fun hashCode(): Int = 31 * included.hashCode() + excluded.hashCode()
512 }
513
514 /** An [WindowInsets] calculated from [paddingValues]. */
515 @Stable
516 private class PaddingValuesInsets(private val paddingValues: PaddingValues) : WindowInsets {
getLeftnull517 override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
518 with(density) { paddingValues.calculateLeftPadding(layoutDirection).roundToPx() }
519
getTopnull520 override fun getTop(density: Density) =
521 with(density) { paddingValues.calculateTopPadding().roundToPx() }
522
getRightnull523 override fun getRight(density: Density, layoutDirection: LayoutDirection) =
524 with(density) { paddingValues.calculateRightPadding(layoutDirection).roundToPx() }
525
getBottomnull526 override fun getBottom(density: Density) =
527 with(density) { paddingValues.calculateBottomPadding().roundToPx() }
528
toStringnull529 override fun toString(): String {
530 val layoutDirection = LayoutDirection.Ltr
531 val start = paddingValues.calculateLeftPadding(layoutDirection)
532 val top = paddingValues.calculateTopPadding()
533 val end = paddingValues.calculateRightPadding(layoutDirection)
534 val bottom = paddingValues.calculateBottomPadding()
535 return "PaddingValues($start, $top, $end, $bottom)"
536 }
537
equalsnull538 override fun equals(other: Any?): Boolean {
539 if (this === other) {
540 return true
541 }
542 if (other !is PaddingValuesInsets) {
543 return false
544 }
545
546 return other.paddingValues == paddingValues
547 }
548
hashCodenull549 override fun hashCode(): Int = paddingValues.hashCode()
550 }
551
552 @Stable
553 private class LimitInsets(val insets: WindowInsets, val sides: WindowInsetsSides) : WindowInsets {
554 override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int {
555 val layoutDirectionSide =
556 if (layoutDirection == LayoutDirection.Ltr) {
557 WindowInsetsSides.AllowLeftInLtr
558 } else {
559 WindowInsetsSides.AllowLeftInRtl
560 }
561 val allowLeft = sides.hasAny(layoutDirectionSide)
562 return if (allowLeft) {
563 insets.getLeft(density, layoutDirection)
564 } else {
565 0
566 }
567 }
568
569 override fun getTop(density: Density): Int =
570 if (sides.hasAny(WindowInsetsSides.Top)) insets.getTop(density) else 0
571
572 override fun getRight(density: Density, layoutDirection: LayoutDirection): Int {
573 val layoutDirectionSide =
574 if (layoutDirection == LayoutDirection.Ltr) {
575 WindowInsetsSides.AllowRightInLtr
576 } else {
577 WindowInsetsSides.AllowRightInRtl
578 }
579 val allowRight = sides.hasAny(layoutDirectionSide)
580 return if (allowRight) {
581 insets.getRight(density, layoutDirection)
582 } else {
583 0
584 }
585 }
586
587 override fun getBottom(density: Density): Int =
588 if (sides.hasAny(WindowInsetsSides.Bottom)) insets.getBottom(density) else 0
589
590 override fun equals(other: Any?): Boolean {
591 if (this === other) {
592 return true
593 }
594 if (other !is LimitInsets) {
595 return false
596 }
597 return insets == other.insets && sides == other.sides
598 }
599
600 override fun hashCode(): Int {
601 var result = insets.hashCode()
602 result = 31 * result + sides.hashCode()
603 return result
604 }
605
606 override fun toString(): String = "($insets only $sides)"
607 }
608
609 @Stable
610 private class InsetsPaddingValues(val insets: WindowInsets, private val density: Density) :
611 PaddingValues {
calculateLeftPaddingnull612 override fun calculateLeftPadding(layoutDirection: LayoutDirection) =
613 with(density) { insets.getLeft(this, layoutDirection).toDp() }
614
<lambda>null615 override fun calculateTopPadding() = with(density) { insets.getTop(this).toDp() }
616
calculateRightPaddingnull617 override fun calculateRightPadding(layoutDirection: LayoutDirection) =
618 with(density) { insets.getRight(this, layoutDirection).toDp() }
619
<lambda>null620 override fun calculateBottomPadding() = with(density) { insets.getBottom(this).toDp() }
621
toStringnull622 override fun toString(): String {
623 return "InsetsPaddingValues(insets=$insets, density=$density)"
624 }
625
equalsnull626 override fun equals(other: Any?): Boolean {
627 if (this === other) {
628 return true
629 }
630 if (other !is InsetsPaddingValues) {
631 return false
632 }
633 return insets == other.insets && density == other.density
634 }
635
hashCodenull636 override fun hashCode(): Int {
637 var result = insets.hashCode()
638 result = 31 * result + density.hashCode()
639 return result
640 }
641 }
642
643 /** An insets type representing the window of a caption bar. */
644 expect val WindowInsets.Companion.captionBar: WindowInsets
645 @Composable get
646
647 /** This [WindowInsets] represents the area with the display cutout (e.g. for camera). */
648 expect val WindowInsets.Companion.displayCutout: WindowInsets
649 @Composable get
650
651 /** An insets type representing the window of the software keyboard. */
652 expect val WindowInsets.Companion.ime: WindowInsets
653 @Composable get
654
655 /**
656 * These insets represent the space where system gestures have priority over application gestures.
657 */
658 expect val WindowInsets.Companion.mandatorySystemGestures: WindowInsets
659 @Composable get
660
661 /**
662 * These insets represent where system UI places navigation bars. Interactive UI should avoid the
663 * navigation bars area.
664 */
665 expect val WindowInsets.Companion.navigationBars: WindowInsets
666 @Composable get
667
668 /** These insets represent status bar. */
669 expect val WindowInsets.Companion.statusBars: WindowInsets
670 @Composable get
671
672 /**
673 * These insets represent all system bars. Includes [statusBars], [captionBar] as well as
674 * [navigationBars], but not [ime].
675 */
676 expect val WindowInsets.Companion.systemBars: WindowInsets
677 @Composable get
678
679 /**
680 * The [systemGestures] insets represent the area of a window where system gestures have priority
681 * and may consume some or all touch input, e.g. due to the system bar occupying it, or it being
682 * reserved for touch-only gestures.
683 */
684 expect val WindowInsets.Companion.systemGestures: WindowInsets
685 @Composable get
686
687 /** Returns the tappable element insets. */
688 expect val WindowInsets.Companion.tappableElement: WindowInsets
689 @Composable get
690
691 /** The insets for the curved areas in a waterfall display. */
692 expect val WindowInsets.Companion.waterfall: WindowInsets
693 @Composable get
694
695 /**
696 * The insets that include areas where content may be covered by other drawn content. This includes
697 * all [systemBars], [displayCutout], and [ime].
698 */
699 expect val WindowInsets.Companion.safeDrawing: WindowInsets
700 @Composable get
701
702 /**
703 * The insets that include areas where gestures may be confused with other input, including
704 * [systemGestures], [mandatorySystemGestures], [waterfall], and [tappableElement].
705 */
706 expect val WindowInsets.Companion.safeGestures: WindowInsets
707 @Composable get
708
709 /**
710 * The insets that include all areas that may be drawn over or have gesture confusion, including
711 * everything in [safeDrawing] and [safeGestures].
712 */
713 expect val WindowInsets.Companion.safeContent: WindowInsets
714 @Composable get
715