From a4fde71c183bd68d0852c192fbf6d3b764a1b747 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Sun, 24 Jan 2021 10:02:51 +0000 Subject: [PATCH 1/6] New Kotlin DSL --- library/api/library.api | 21 ++ .../dev/chrisbanes/insetter/InsetterDsl.kt | 214 ++++++++++++++++++ .../dev/chrisbanes/insetter/InsetterKtx.kt | 108 ++++++--- .../main/java/dev/chrisbanes/insetter/Side.kt | 29 ++- 4 files changed, 336 insertions(+), 36 deletions(-) create mode 100644 library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt diff --git a/library/api/library.api b/library/api/library.api index 76aed43..67b3060 100644 --- a/library/api/library.api +++ b/library/api/library.api @@ -45,6 +45,26 @@ public final class dev/chrisbanes/insetter/Insetter$Companion { public abstract interface annotation class dev/chrisbanes/insetter/Insetter$ConsumeOptions : java/lang/annotation/Annotation { } +public final class dev/chrisbanes/insetter/InsetterApplyTypeDsl { + public final fun margin ()V + public final fun margin (ZZZZZZ)V + public static synthetic fun margin$default (Ldev/chrisbanes/insetter/InsetterApplyTypeDsl;ZZZZZZILjava/lang/Object;)V + public final fun padding ()V + public final fun padding (ZZZZZZ)V + public static synthetic fun padding$default (Ldev/chrisbanes/insetter/InsetterApplyTypeDsl;ZZZZZZILjava/lang/Object;)V +} + +public final class dev/chrisbanes/insetter/InsetterDsl { + public final fun consume (Z)V + public final fun type (ILkotlin/jvm/functions/Function1;)V + public final fun type (ZZZZZZZZLkotlin/jvm/functions/Function1;)V + public static synthetic fun type$default (Ldev/chrisbanes/insetter/InsetterDsl;ZZZZZZZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V +} + +public final class dev/chrisbanes/insetter/InsetterDslKt { + public static final fun applyInsetter (Landroid/view/View;Lkotlin/jvm/functions/Function1;)Ldev/chrisbanes/insetter/Insetter; +} + public final class dev/chrisbanes/insetter/InsetterKtxKt { public static final fun applySystemGestureInsetsToMargin (Landroid/view/View;ZZZZZ)Ldev/chrisbanes/insetter/Insetter; public static synthetic fun applySystemGestureInsetsToMargin$default (Landroid/view/View;ZZZZZILjava/lang/Object;)Ldev/chrisbanes/insetter/Insetter; @@ -72,6 +92,7 @@ public final class dev/chrisbanes/insetter/Side { public static final field RIGHT I public static final field TOP I public static final fun create (ZZZZ)I + public static final fun create (ZZZZZZ)I } public abstract interface annotation class dev/chrisbanes/insetter/Sides : java/lang/annotation/Annotation { diff --git a/library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt b/library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt new file mode 100644 index 0000000..480e5a2 --- /dev/null +++ b/library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt @@ -0,0 +1,214 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.chrisbanes.insetter + +import android.view.View +import androidx.core.view.WindowInsetsCompat + +/** + * Allows easy building and applying of [WindowInsetsCompat] to this [View]. + * + * As an example, to apply the [navigation bar][WindowInsetsCompat.Type.navigationBars] insets + * as padding to this view, you would call: + * + * ``` + * view.applyInsetter { + * type(navigationBars = true) { + * padding() + * } + * } + * ``` + * + * ### Applying different types + * + * If we want to apply different insets type, we can do that too: + * + * ``` + * view.applyInsetter { + * // Apply the navigation bar insets as padding + * type(navigationBars = true) { + * padding() + * } + * // Apply the status bar insets as margin + * type(statusBars = true) { + * margin() + * } + * } + * ``` + * + * Alternatively, if we want to apply multiple types as padding/margin, you can do the following: + * + * ``` + * view.applyInsetter { + * // Apply the navigation bar and status bars insets as padding + * type(navigationBars = true, statusBars = true) { + * padding() + * } + * } + * ``` + * + * ### Different dimensions + * + * Some times you need to apply sides differently, here we're applying left + right sides to margin, + * and then the bottom as padding: + * + * ``` + * view.applyInsetter { + * // Apply the navigation bar insets... + * type(navigationBars = true) { + * // Add the left/right to the margin + * margin(left = true, right = true) + * // Add the bottom to padding + * padding(bottom = true) + * } + * } + * ``` + */ +fun View.applyInsetter(build: InsetterDsl.() -> Unit): Insetter { + return InsetterDsl().apply(build).builder.applyToView(this) +} + +/** + * Class used in [View.applyInsetter]. + */ +class InsetterDsl internal constructor() { + internal var builder = Insetter.builder() + + /** + * Set how the given [WindowInsetsCompat.Type]s are applied to the view. + * + * All of the common types are provided as boolean parameters. Setting multiple types + * to `true` will result in the combination of those insets to be applied. + * + * @throws IllegalArgumentException if all types are set to `false`. + * + * @param ime True to apply the [WindowInsetsCompat.Type.ime] insets. + * @param navigationBars True to apply the [WindowInsetsCompat.Type.navigationBars] insets. + * @param navigationBars True to apply the [WindowInsetsCompat.Type.navigationBars] insets. + * @param statusBars True to apply the [WindowInsetsCompat.Type.statusBars] insets. + * @param systemGestures True to apply the [WindowInsetsCompat.Type.systemGestures] insets. + * @param mandatorySystemGestures True to apply the [WindowInsetsCompat.Type.mandatorySystemGestures] insets. + * @param displayCutout True to apply the [WindowInsetsCompat.Type.displayCutout] insets. + * @param captionBar True to apply the [WindowInsetsCompat.Type.captionBar] insets. + * @param tappableElement True to apply the [WindowInsetsCompat.Type.tappableElement] insets. + */ + fun type( + ime: Boolean = false, + navigationBars: Boolean = false, + statusBars: Boolean = false, + systemGestures: Boolean = false, + mandatorySystemGestures: Boolean = false, + displayCutout: Boolean = false, + captionBar: Boolean = false, + tappableElement: Boolean = false, + f: InsetterApplyTypeDsl.() -> Unit, + ) { + val type = windowInsetTypesOf( + ime, + navigationBars, + statusBars, + systemGestures, + mandatorySystemGestures, + displayCutout, + captionBar, + tappableElement + ) + type(type, f) + } + + /** + * Set how the given bitmask of [WindowInsetsCompat.Type]s in [type] are applied to the view. + * + * @throws IllegalArgumentException if [type] is empty, by passing in `0`. + * + * @param type Bit mask of [WindowInsetsCompat.Type]s apply. + */ + fun type(type: Int, f: InsetterApplyTypeDsl.() -> Unit,) { + require(type != 0) { "A type is required" } + builder = InsetterApplyTypeDsl(type, builder).apply(f).builder + } + + fun consume(consume: Boolean) { + builder = builder.consume(if (consume) Insetter.CONSUME_ALL else Insetter.CONSUME_NONE) + } +} + +/** + * Class used in [View.applyInsetter]. + */ +class InsetterApplyTypeDsl internal constructor( + private val type: Int, + internal var builder: Insetter.Builder, +) { + /** + * Add the [WindowInsetsCompat.Type] to all padding dimensions. + */ + fun padding() = padding(horizontal = true, vertical = true) + + /** + * Add the [WindowInsetsCompat.Type] to the given padding dimensions. + * + * @param left Add the left value of the insets to the left padding. + * @param top Add the left value of the insets to the top padding. + * @param right Add the left value of the insets to the right padding. + * @param bottom Add the left value of the insets to the bottom padding. + * @param horizontal Add both the left and right values. + * @param vertical Add both the top and bottom values. + */ + fun padding( + left: Boolean = false, + top: Boolean = false, + right: Boolean = false, + bottom: Boolean = false, + horizontal: Boolean = false, + vertical: Boolean = false, + ) { + builder = builder.padding( + insetType = type, + sides = Side.create(left, top, right, bottom, horizontal, vertical) + ) + } + + /** + * Add the [WindowInsetsCompat.Type] to all margin dimensions. + */ + fun margin() = margin(horizontal = true, vertical = true) + + /** + * Add the [WindowInsetsCompat.Type] to the given margin dimensions. + * + * @param left Add the left value of the insets to the left padding. + * @param top Add the left value of the insets to the top padding. + * @param right Add the left value of the insets to the right padding. + * @param bottom Add the left value of the insets to the bottom padding. + * @param horizontal Add both the left and right values. + * @param vertical Add both the top and bottom values. + */ + fun margin( + left: Boolean = false, + top: Boolean = false, + right: Boolean = false, + bottom: Boolean = false, + horizontal: Boolean = false, + vertical: Boolean = false, + ) { + builder = builder.margin( + insetType = type, + sides = Side.create(left, top, right, bottom, horizontal, vertical) + ) + } +} diff --git a/library/src/main/java/dev/chrisbanes/insetter/InsetterKtx.kt b/library/src/main/java/dev/chrisbanes/insetter/InsetterKtx.kt index 50ff80f..7510a63 100644 --- a/library/src/main/java/dev/chrisbanes/insetter/InsetterKtx.kt +++ b/library/src/main/java/dev/chrisbanes/insetter/InsetterKtx.kt @@ -61,19 +61,32 @@ inline fun View.setEdgeToEdgeSystemUiFlags(enabled: Boolean = true) { * @param bottom apply in the bottom indent if true * @param consume consume the system window insets if true */ +@Deprecated( + "Replaced with applyInsetter {}", + ReplaceWith( + """ + applyInsetter { + type(ime = true, statusBars = true, navigationBars = true) { + padding(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) + } + """, + "import dev.chrisbanes.insetter.applyInsetter" + ) +) inline fun View.applySystemWindowInsetsToPadding( left: Boolean = false, top: Boolean = false, right: Boolean = false, bottom: Boolean = false, consume: Boolean = false -) = Insetter.builder() - .padding( - windowInsetTypesOf(ime = true, statusBars = true, navigationBars = true), - Side.create(left, top, right, bottom) - ) - .consume(if (consume) Insetter.CONSUME_ALL else Insetter.CONSUME_NONE) - .applyToView(this) +) = applyInsetter { + type(ime = true, statusBars = true, navigationBars = true) { + padding(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) +} /** * Apply the system window insets to the margins on this [View]. @@ -84,19 +97,32 @@ inline fun View.applySystemWindowInsetsToPadding( * @param bottom apply in the bottom indent if true * @param consume consume the system window insets if true */ +@Deprecated( + "Replaced with applyInsetter {}", + ReplaceWith( + """ + applyInsetter { + type(ime = true, statusBars = true, navigationBars = true) { + margin(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) + } + """, + "import dev.chrisbanes.insetter.applyInsetter" + ) +) inline fun View.applySystemWindowInsetsToMargin( left: Boolean = false, top: Boolean = false, right: Boolean = false, bottom: Boolean = false, consume: Boolean = false -) = Insetter.builder() - .margin( - windowInsetTypesOf(ime = true, statusBars = true, navigationBars = true), - Side.create(left, top, right, bottom) - ) - .consume(if (consume) Insetter.CONSUME_ALL else Insetter.CONSUME_NONE) - .applyToView(this) +) = applyInsetter { + type(ime = true, statusBars = true, navigationBars = true) { + margin(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) +} /** * Apply system gesture insets to the padding of this [View]. @@ -107,19 +133,32 @@ inline fun View.applySystemWindowInsetsToMargin( * @param bottom apply in the bottom indent if true * @param consume consume the system window insets if true */ +@Deprecated( + "Replaced with applyInsetter {}", + ReplaceWith( + """ + applyInsetter { + type(systemGestures = true) { + padding(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) + } + """, + "import dev.chrisbanes.insetter.applyInsetter" + ) +) inline fun View.applySystemGestureInsetsToPadding( left: Boolean = false, top: Boolean = false, right: Boolean = false, bottom: Boolean = false, consume: Boolean = false -) = Insetter.builder() - .padding( - windowInsetTypesOf(systemGestures = true), - Side.create(left, top, right, bottom) - ) - .consume(if (consume) Insetter.CONSUME_ALL else Insetter.CONSUME_NONE) - .applyToView(this) +) = applyInsetter { + type(systemGestures = true) { + padding(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) +} /** * Apply system gesture insets to the margins on this [View]. @@ -130,16 +169,29 @@ inline fun View.applySystemGestureInsetsToPadding( * @param bottom apply in the bottom indent if true * @param consume consume the system window insets if true */ +@Deprecated( + "Replaced with applyInsetter {}", + ReplaceWith( + """ + applyInsetter { + type(systemGestures = true) { + margin(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) + } + """, + "import dev.chrisbanes.insetter.applyInsetter" + ) +) inline fun View.applySystemGestureInsetsToMargin( left: Boolean = false, top: Boolean = false, right: Boolean = false, bottom: Boolean = false, consume: Boolean = false -) = Insetter.builder() - .margin( - windowInsetTypesOf(systemGestures = true), - Side.create(left, top, right, bottom) - ) - .consume(if (consume) Insetter.CONSUME_ALL else Insetter.CONSUME_NONE) - .applyToView(this) +) = applyInsetter { + type(systemGestures = true) { + margin(left = left, top = top, right = right, bottom = bottom) + } + consume(consume) +} diff --git a/library/src/main/java/dev/chrisbanes/insetter/Side.kt b/library/src/main/java/dev/chrisbanes/insetter/Side.kt index c4e9853..144bded 100644 --- a/library/src/main/java/dev/chrisbanes/insetter/Side.kt +++ b/library/src/main/java/dev/chrisbanes/insetter/Side.kt @@ -31,13 +31,26 @@ object Side { top: Boolean, right: Boolean, bottom: Boolean - ): Int = (if (left) LEFT else 0) or - (if (top) TOP else 0) or - (if (right) RIGHT else 0) or - (if (bottom) BOTTOM else 0) + ): Int = create( + left = left, + top = top, + right = right, + bottom = bottom, + horizontal = false, + vertical = false + ) - @Suppress("NOTHING_TO_INLINE") - internal inline fun hasSide(sides: Int, @Sides flag: Int): Boolean { - return sides and flag == flag - } + @Sides + @JvmStatic + fun create( + left: Boolean, + top: Boolean, + right: Boolean, + bottom: Boolean, + horizontal: Boolean, + vertical: Boolean, + ): Int = (if (left || horizontal) LEFT else 0) or + (if (top || vertical) TOP else 0) or + (if (right || horizontal) RIGHT else 0) or + (if (bottom || vertical) BOTTOM else 0) } From 9e24e4b02ad3113c5dbee268e55c4304bc8b1525 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Sun, 24 Jan 2021 10:26:29 +0000 Subject: [PATCH 2/6] Use DslMarker --- library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt b/library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt index 480e5a2..4210b09 100644 --- a/library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt +++ b/library/src/main/java/dev/chrisbanes/insetter/InsetterDsl.kt @@ -82,9 +82,13 @@ fun View.applyInsetter(build: InsetterDsl.() -> Unit): Insetter { return InsetterDsl().apply(build).builder.applyToView(this) } +@DslMarker +annotation class InsetterDslMarker + /** * Class used in [View.applyInsetter]. */ +@InsetterDslMarker class InsetterDsl internal constructor() { internal var builder = Insetter.builder() @@ -150,6 +154,7 @@ class InsetterDsl internal constructor() { /** * Class used in [View.applyInsetter]. */ +@InsetterDslMarker class InsetterApplyTypeDsl internal constructor( private val type: Int, internal var builder: Insetter.Builder, From 011b0ad2ceec4bbf97cd5bd1447db3f6700d6cc5 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Sun, 24 Jan 2021 10:26:36 +0000 Subject: [PATCH 3/6] Update docs for DSL --- docs/index.md | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/docs/index.md b/docs/index.md index ea6f7fc..ee612eb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,9 +21,9 @@ instances: ``` java Insetter.builder() - // This will apply the system window insets as padding to left, bottom and right of the view, + // This will add the navigation bars insets as padding to all sides of the view, // maintaining the original padding (from the layout XML, style, etc) - .applySystemWindowInsetsToPadding(Side.LEFT | Side.BOTTOM | Side.RIGHT) + .padding(WindowInsetsCompat.Type.navigationBars()) // This is a shortcut for view.setOnApplyWindowInsetsListener(builder.build()) .applyToView(view); ``` @@ -31,21 +31,15 @@ instances: === "Kotlin" ``` kotlin - Insetter.builder() - // This will apply the system window insets as padding to left, bottom and right of the view, - // maintaining the original padding (from the layout XML, style, etc) - .applySystemWindowInsetsToPadding(Side.LEFT or Side.BOTTOM or Side.RIGHT) - // This is a shortcut for view.setOnApplyWindowInsetsListener(builder.build()) - .applyToView(view) + view.applyInsetter { + // Apply the navigation bar insets... + type(navigationBars = true) { + // Add to padding on all sides + padding() + } + } ``` -It also provides some Kotlin-only extension functions allowing easy access to the library functions: - -``` kotlin -bottomNav.applySystemWindowInsetsToPadding(bottom = true) -btnConfirm.applySystemWindowInsetsToMargin(bottom = true, right = true) -``` - ### [insetter-dbx](dbx/) A [Data Binding][databinding] extension library, providing [Data Binding][databinding] specific functionality. From 72c490481405647d36dd681c8565624ffe62757d Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Sun, 24 Jan 2021 10:29:16 +0000 Subject: [PATCH 4/6] Doc tweaks --- docs/index.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/index.md b/docs/index.md index ee612eb..60b83e9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,17 +17,6 @@ The base library which provides an easy-to-use [OnApplyWindowInsetsListener](https://developer.android.com/reference/androidx/core/view/OnApplyWindowInsetsListener) instances: -=== "Java" - - ``` java - Insetter.builder() - // This will add the navigation bars insets as padding to all sides of the view, - // maintaining the original padding (from the layout XML, style, etc) - .padding(WindowInsetsCompat.Type.navigationBars()) - // This is a shortcut for view.setOnApplyWindowInsetsListener(builder.build()) - .applyToView(view); - ``` - === "Kotlin" ``` kotlin @@ -40,6 +29,17 @@ instances: } ``` +=== "Java" + + ``` java + Insetter.builder() + // This will add the navigation bars insets as padding to all sides of the view, + // maintaining the original padding (from the layout XML, style, etc) + .padding(WindowInsetsCompat.Type.navigationBars()) + // This is a shortcut for view.setOnApplyWindowInsetsListener(builder.build()) + .applyToView(view); + ``` + ### [insetter-dbx](dbx/) A [Data Binding][databinding] extension library, providing [Data Binding][databinding] specific functionality. @@ -99,7 +99,7 @@ at a later date. ## Download -=== "Java" +=== "Stable" Latest version: ![GitHub release](https://img.shields.io/maven-central/v/dev.chrisbanes.insetter/insetter) From 3073329fea9d1641b30a9f846db106520de60bc0 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Sun, 24 Jan 2021 10:37:51 +0000 Subject: [PATCH 5/6] Add links from docs --- docs/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/index.md b/docs/index.md index 60b83e9..21456d9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,6 +29,8 @@ instances: } ``` + See [here](api/library/library/dev.chrisbanes.insetter/apply-insetter.html) for more information. + === "Java" ``` java @@ -40,6 +42,8 @@ instances: .applyToView(view); ``` + See [here](api/library/library/dev.chrisbanes.insetter/-insetter/) for more information. + ### [insetter-dbx](dbx/) A [Data Binding][databinding] extension library, providing [Data Binding][databinding] specific functionality. From 2ae7ecb7871cb84afc8ff05e8d714ef6bca34bda Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Sun, 24 Jan 2021 10:38:47 +0000 Subject: [PATCH 6/6] More doc updates --- docs/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 21456d9..c0f175a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,9 +10,9 @@ blog post. There are a number of libraries available: -### [insetter](library/) +### [Main library](library/) -The base library which provides an easy-to-use +The main library provides an easy-to-use [Builder](/library/src/main/java/dev/chrisbanes/insetter/Insetter.kt) for [OnApplyWindowInsetsListener](https://developer.android.com/reference/androidx/core/view/OnApplyWindowInsetsListener) instances: