Merge branch 'main' into dt/nav-safe-args

* main:
  Kotlin 2.0.0 (#1036)
  Update app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt
  🤖 Updates screenshots
  🤖 Updates baselines for Dependency Guard
  Update material3-adaptive to beta01
  🤖 Updates baselines for Dependency Guard
  Bump androidxComposeAlpha from 1.7.0-alpha08 to 1.7.0-beta01
  🤖 Updates baselines for Dependency Guard
  Bump hilt from 2.51 to 2.51.1
  Add NavigationSuiteScaffold
  Fix state loss with workaround

Change-Id: I14d7294fe93f68b9aca6df9bf7bf87ff95583581
dt/nav-safe-args
Don Turner 1 month ago
commit a6397b7d82

@ -12,12 +12,11 @@ updates:
registries: "*" registries: "*"
labels: [ "version update" ] labels: [ "version update" ]
groups: groups:
kotlin-ksp-compose: kotlin-ksp:
patterns: patterns:
- "org.jetbrains.kotlin:*" - "org.jetbrains.kotlin:*"
- "org.jetbrains.kotlin.jvm" - "org.jetbrains.kotlin.jvm"
- "com.google.devtools.ksp" - "com.google.devtools.ksp"
- "androidx.compose.compiler:compiler"
open-pull-requests-limit: 10 open-pull-requests-limit: 10
registries: registries:
maven-google: maven-google:

3
.gitignore vendored

@ -43,3 +43,6 @@ _sandbox
# Android Studio captures folder # Android Studio captures folder
captures/ captures/
# Kotlin
.kotlin

@ -2,8 +2,8 @@ androidx.activity:activity-compose:1.8.2
androidx.activity:activity-ktx:1.8.2 androidx.activity:activity-ktx:1.8.2
androidx.activity:activity:1.8.2 androidx.activity:activity:1.8.2
androidx.annotation:annotation-experimental:1.4.0 androidx.annotation:annotation-experimental:1.4.0
androidx.annotation:annotation-jvm:1.7.1 androidx.annotation:annotation-jvm:1.8.0
androidx.annotation:annotation:1.7.1 androidx.annotation:annotation:1.8.0
androidx.appcompat:appcompat-resources:1.6.1 androidx.appcompat:appcompat-resources:1.6.1
androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0 androidx.arch.core:core-runtime:2.2.0
@ -12,61 +12,72 @@ androidx.browser:browser:1.8.0
androidx.collection:collection-jvm:1.4.0 androidx.collection:collection-jvm:1.4.0
androidx.collection:collection-ktx:1.4.0 androidx.collection:collection-ktx:1.4.0
androidx.collection:collection:1.4.0 androidx.collection:collection:1.4.0
androidx.compose.animation:animation-android:1.6.3 androidx.compose.animation:animation-android:1.7.0-beta01
androidx.compose.animation:animation-core-android:1.6.3 androidx.compose.animation:animation-core-android:1.7.0-beta01
androidx.compose.animation:animation-core:1.6.3 androidx.compose.animation:animation-core:1.7.0-beta01
androidx.compose.animation:animation:1.6.3 androidx.compose.animation:animation:1.7.0-beta01
androidx.compose.foundation:foundation-android:1.6.3 androidx.compose.foundation:foundation-android:1.7.0-beta01
androidx.compose.foundation:foundation-layout-android:1.6.3 androidx.compose.foundation:foundation-layout-android:1.7.0-beta01
androidx.compose.foundation:foundation-layout:1.6.3 androidx.compose.foundation:foundation-layout:1.7.0-beta01
androidx.compose.foundation:foundation:1.6.3 androidx.compose.foundation:foundation:1.7.0-beta01
androidx.compose.material3:material3-android:1.2.1 androidx.compose.material3.adaptive:adaptive-android:1.0.0-beta01
androidx.compose.material3:material3:1.2.1 androidx.compose.material3.adaptive:adaptive:1.0.0-beta01
androidx.compose.material3:material3-adaptive-navigation-suite-android:1.3.0-beta01
androidx.compose.material3:material3-adaptive-navigation-suite:1.3.0-beta01
androidx.compose.material3:material3-android:1.3.0-beta01
androidx.compose.material3:material3:1.3.0-beta01
androidx.compose.material:material-icons-core-android:1.6.3 androidx.compose.material:material-icons-core-android:1.6.3
androidx.compose.material:material-icons-core:1.6.3 androidx.compose.material:material-icons-core:1.6.3
androidx.compose.material:material-icons-extended-android:1.6.3 androidx.compose.material:material-icons-extended-android:1.6.3
androidx.compose.material:material-icons-extended:1.6.3 androidx.compose.material:material-icons-extended:1.6.3
androidx.compose.material:material-ripple-android:1.6.3 androidx.compose.material:material-ripple-android:1.7.0-beta01
androidx.compose.material:material-ripple:1.6.3 androidx.compose.material:material-ripple:1.7.0-beta01
androidx.compose.runtime:runtime-android:1.6.3 androidx.compose.runtime:runtime-android:1.7.0-beta01
androidx.compose.runtime:runtime-saveable-android:1.6.3 androidx.compose.runtime:runtime-saveable-android:1.7.0-beta01
androidx.compose.runtime:runtime-saveable:1.6.3 androidx.compose.runtime:runtime-saveable:1.7.0-beta01
androidx.compose.runtime:runtime:1.6.3 androidx.compose.runtime:runtime:1.7.0-beta01
androidx.compose.ui:ui-android:1.6.3 androidx.compose.ui:ui-android:1.7.0-beta01
androidx.compose.ui:ui-geometry-android:1.6.3 androidx.compose.ui:ui-geometry-android:1.7.0-beta01
androidx.compose.ui:ui-geometry:1.6.3 androidx.compose.ui:ui-geometry:1.7.0-beta01
androidx.compose.ui:ui-graphics-android:1.6.3 androidx.compose.ui:ui-graphics-android:1.7.0-beta01
androidx.compose.ui:ui-graphics:1.6.3 androidx.compose.ui:ui-graphics:1.7.0-beta01
androidx.compose.ui:ui-text-android:1.6.3 androidx.compose.ui:ui-text-android:1.7.0-beta01
androidx.compose.ui:ui-text:1.6.3 androidx.compose.ui:ui-text:1.7.0-beta01
androidx.compose.ui:ui-tooling-preview-android:1.6.3 androidx.compose.ui:ui-tooling-preview-android:1.7.0-beta01
androidx.compose.ui:ui-tooling-preview:1.6.3 androidx.compose.ui:ui-tooling-preview:1.7.0-beta01
androidx.compose.ui:ui-unit-android:1.6.3 androidx.compose.ui:ui-unit-android:1.7.0-beta01
androidx.compose.ui:ui-unit:1.6.3 androidx.compose.ui:ui-unit:1.7.0-beta01
androidx.compose.ui:ui-util-android:1.6.3 androidx.compose.ui:ui-util-android:1.7.0-beta01
androidx.compose.ui:ui-util:1.6.3 androidx.compose.ui:ui-util:1.7.0-beta01
androidx.compose.ui:ui:1.6.3 androidx.compose.ui:ui:1.7.0-beta01
androidx.compose:compose-bom:2024.02.02 androidx.compose:compose-bom:2024.02.02
androidx.concurrent:concurrent-futures:1.1.0 androidx.concurrent:concurrent-futures:1.1.0
androidx.core:core-ktx:1.12.0 androidx.core:core-ktx:1.13.1
androidx.core:core:1.12.0 androidx.core:core:1.13.1
androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0
androidx.customview:customview:1.0.0 androidx.customview:customview:1.0.0
androidx.emoji2:emoji2:1.3.0 androidx.emoji2:emoji2:1.3.0
androidx.exifinterface:exifinterface:1.3.7 androidx.exifinterface:exifinterface:1.3.7
androidx.fragment:fragment:1.5.1 androidx.fragment:fragment:1.5.1
androidx.graphics:graphics-path:1.0.1
androidx.interpolator:interpolator:1.0.0 androidx.interpolator:interpolator:1.0.0
androidx.lifecycle:lifecycle-common-java8:2.7.0 androidx.lifecycle:lifecycle-common-java8:2.8.0
androidx.lifecycle:lifecycle-common:2.7.0 androidx.lifecycle:lifecycle-common-jvm:2.8.0
androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 androidx.lifecycle:lifecycle-common:2.8.0
androidx.lifecycle:lifecycle-livedata-core:2.7.0 androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0
androidx.lifecycle:lifecycle-livedata:2.7.0 androidx.lifecycle:lifecycle-livedata-core:2.8.0
androidx.lifecycle:lifecycle-process:2.7.0 androidx.lifecycle:lifecycle-livedata:2.8.0
androidx.lifecycle:lifecycle-runtime-ktx:2.7.0 androidx.lifecycle:lifecycle-process:2.8.0
androidx.lifecycle:lifecycle-runtime:2.7.0 androidx.lifecycle:lifecycle-runtime-android:2.8.0
androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0 androidx.lifecycle:lifecycle-runtime-compose-android:2.8.0
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0 androidx.lifecycle:lifecycle-runtime-compose:2.8.0
androidx.lifecycle:lifecycle-viewmodel:2.7.0 androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.0
androidx.lifecycle:lifecycle-runtime-ktx:2.8.0
androidx.lifecycle:lifecycle-runtime:2.8.0
androidx.lifecycle:lifecycle-viewmodel-android:2.8.0
androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0
androidx.lifecycle:lifecycle-viewmodel:2.8.0
androidx.loader:loader:1.0.0 androidx.loader:loader:1.0.0
androidx.metrics:metrics-performance:1.0.0-alpha04 androidx.metrics:metrics-performance:1.0.0-alpha04
androidx.profileinstaller:profileinstaller:1.3.1 androidx.profileinstaller:profileinstaller:1.3.1
@ -79,12 +90,16 @@ androidx.vectordrawable:vectordrawable-animated:1.1.0
androidx.vectordrawable:vectordrawable:1.1.0 androidx.vectordrawable:vectordrawable:1.1.0
androidx.versionedparcelable:versionedparcelable:1.1.1 androidx.versionedparcelable:versionedparcelable:1.1.1
androidx.viewpager:viewpager:1.0.0 androidx.viewpager:viewpager:1.0.0
androidx.window.extensions.core:core:1.0.0
androidx.window:window-core-android:1.3.0-beta02
androidx.window:window-core:1.3.0-beta02
androidx.window:window:1.3.0-beta02
com.google.accompanist:accompanist-drawablepainter:0.32.0 com.google.accompanist:accompanist-drawablepainter:0.32.0
com.google.code.findbugs:jsr305:3.0.2 com.google.code.findbugs:jsr305:3.0.2
com.google.dagger:dagger-lint-aar:2.51 com.google.dagger:dagger-lint-aar:2.51.1
com.google.dagger:dagger:2.51 com.google.dagger:dagger:2.51.1
com.google.dagger:hilt-android:2.51 com.google.dagger:hilt-android:2.51.1
com.google.dagger:hilt-core:2.51 com.google.dagger:hilt-core:2.51.1
com.google.guava:listenablefuture:1.0 com.google.guava:listenablefuture:1.0
com.squareup.okhttp3:okhttp:4.12.0 com.squareup.okhttp3:okhttp:4.12.0
com.squareup.okio:okio-jvm:3.8.0 com.squareup.okio:okio-jvm:3.8.0
@ -94,10 +109,10 @@ io.coil-kt:coil-compose-base:2.6.0
io.coil-kt:coil-compose:2.6.0 io.coil-kt:coil-compose:2.6.0
io.coil-kt:coil:2.6.0 io.coil-kt:coil:2.6.0
javax.inject:javax.inject:1 javax.inject:javax.inject:1
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.22 org.jetbrains.kotlin:kotlin-stdlib-common:2.0.0
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0 org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0
org.jetbrains.kotlin:kotlin-stdlib:1.9.22 org.jetbrains.kotlin:kotlin-stdlib:2.0.0
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3

@ -2,8 +2,8 @@ androidx.activity:activity-compose:1.8.2
androidx.activity:activity-ktx:1.8.2 androidx.activity:activity-ktx:1.8.2
androidx.activity:activity:1.8.2 androidx.activity:activity:1.8.2
androidx.annotation:annotation-experimental:1.4.0 androidx.annotation:annotation-experimental:1.4.0
androidx.annotation:annotation-jvm:1.8.0-rc01 androidx.annotation:annotation-jvm:1.8.0
androidx.annotation:annotation:1.8.0-rc01 androidx.annotation:annotation:1.8.0
androidx.appcompat:appcompat-resources:1.6.1 androidx.appcompat:appcompat-resources:1.6.1
androidx.appcompat:appcompat:1.6.1 androidx.appcompat:appcompat:1.6.1
androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-common:2.2.0
@ -13,49 +13,51 @@ androidx.browser:browser:1.8.0
androidx.collection:collection-jvm:1.4.0 androidx.collection:collection-jvm:1.4.0
androidx.collection:collection-ktx:1.4.0 androidx.collection:collection-ktx:1.4.0
androidx.collection:collection:1.4.0 androidx.collection:collection:1.4.0
androidx.compose.animation:animation-android:1.7.0-alpha08 androidx.compose.animation:animation-android:1.7.0-beta01
androidx.compose.animation:animation-core-android:1.7.0-alpha08 androidx.compose.animation:animation-core-android:1.7.0-beta01
androidx.compose.animation:animation-core:1.7.0-alpha08 androidx.compose.animation:animation-core:1.7.0-beta01
androidx.compose.animation:animation:1.7.0-alpha08 androidx.compose.animation:animation:1.7.0-beta01
androidx.compose.foundation:foundation-android:1.7.0-alpha08 androidx.compose.foundation:foundation-android:1.7.0-beta01
androidx.compose.foundation:foundation-layout-android:1.7.0-alpha08 androidx.compose.foundation:foundation-layout-android:1.7.0-beta01
androidx.compose.foundation:foundation-layout:1.7.0-alpha08 androidx.compose.foundation:foundation-layout:1.7.0-beta01
androidx.compose.foundation:foundation:1.7.0-alpha08 androidx.compose.foundation:foundation:1.7.0-beta01
androidx.compose.material3.adaptive:adaptive-android:1.0.0-alpha10 androidx.compose.material3.adaptive:adaptive-android:1.0.0-beta01
androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0-alpha10 androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0-beta01
androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha10 androidx.compose.material3.adaptive:adaptive-layout:1.0.0-beta01
androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0-alpha10 androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0-beta01
androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha10 androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-beta01
androidx.compose.material3.adaptive:adaptive:1.0.0-alpha10 androidx.compose.material3.adaptive:adaptive:1.0.0-beta01
androidx.compose.material3:material3-android:1.2.1 androidx.compose.material3:material3-adaptive-navigation-suite-android:1.3.0-beta01
androidx.compose.material3:material3-window-size-class-android:1.2.1 androidx.compose.material3:material3-adaptive-navigation-suite:1.3.0-beta01
androidx.compose.material3:material3-window-size-class:1.2.1 androidx.compose.material3:material3-android:1.3.0-beta01
androidx.compose.material3:material3:1.2.1 androidx.compose.material3:material3-window-size-class-android:1.3.0-beta01
androidx.compose.material3:material3-window-size-class:1.3.0-beta01
androidx.compose.material3:material3:1.3.0-beta01
androidx.compose.material:material-icons-core-android:1.6.3 androidx.compose.material:material-icons-core-android:1.6.3
androidx.compose.material:material-icons-core:1.6.3 androidx.compose.material:material-icons-core:1.6.3
androidx.compose.material:material-icons-extended-android:1.6.3 androidx.compose.material:material-icons-extended-android:1.6.3
androidx.compose.material:material-icons-extended:1.6.3 androidx.compose.material:material-icons-extended:1.6.3
androidx.compose.material:material-ripple-android:1.6.3 androidx.compose.material:material-ripple-android:1.7.0-beta01
androidx.compose.material:material-ripple:1.6.3 androidx.compose.material:material-ripple:1.7.0-beta01
androidx.compose.runtime:runtime-android:1.7.0-alpha08 androidx.compose.runtime:runtime-android:1.7.0-beta01
androidx.compose.runtime:runtime-saveable-android:1.7.0-alpha08 androidx.compose.runtime:runtime-saveable-android:1.7.0-beta01
androidx.compose.runtime:runtime-saveable:1.7.0-alpha08 androidx.compose.runtime:runtime-saveable:1.7.0-beta01
androidx.compose.runtime:runtime-tracing:1.0.0-beta01 androidx.compose.runtime:runtime-tracing:1.0.0-beta01
androidx.compose.runtime:runtime:1.7.0-alpha08 androidx.compose.runtime:runtime:1.7.0-beta01
androidx.compose.ui:ui-android:1.7.0-alpha08 androidx.compose.ui:ui-android:1.7.0-beta01
androidx.compose.ui:ui-geometry-android:1.7.0-alpha08 androidx.compose.ui:ui-geometry-android:1.7.0-beta01
androidx.compose.ui:ui-geometry:1.7.0-alpha08 androidx.compose.ui:ui-geometry:1.7.0-beta01
androidx.compose.ui:ui-graphics-android:1.7.0-alpha08 androidx.compose.ui:ui-graphics-android:1.7.0-beta01
androidx.compose.ui:ui-graphics:1.7.0-alpha08 androidx.compose.ui:ui-graphics:1.7.0-beta01
androidx.compose.ui:ui-text-android:1.7.0-alpha08 androidx.compose.ui:ui-text-android:1.7.0-beta01
androidx.compose.ui:ui-text:1.7.0-alpha08 androidx.compose.ui:ui-text:1.7.0-beta01
androidx.compose.ui:ui-tooling-preview-android:1.7.0-alpha08 androidx.compose.ui:ui-tooling-preview-android:1.7.0-beta01
androidx.compose.ui:ui-tooling-preview:1.7.0-alpha08 androidx.compose.ui:ui-tooling-preview:1.7.0-beta01
androidx.compose.ui:ui-unit-android:1.7.0-alpha08 androidx.compose.ui:ui-unit-android:1.7.0-beta01
androidx.compose.ui:ui-unit:1.7.0-alpha08 androidx.compose.ui:ui-unit:1.7.0-beta01
androidx.compose.ui:ui-util-android:1.7.0-alpha08 androidx.compose.ui:ui-util-android:1.7.0-beta01
androidx.compose.ui:ui-util:1.7.0-alpha08 androidx.compose.ui:ui-util:1.7.0-beta01
androidx.compose.ui:ui:1.7.0-alpha08 androidx.compose.ui:ui:1.7.0-beta01
androidx.compose:compose-bom:2024.02.02 androidx.compose:compose-bom:2024.02.02
androidx.concurrent:concurrent-futures:1.1.0 androidx.concurrent:concurrent-futures:1.1.0
androidx.core:core-ktx:1.13.1 androidx.core:core-ktx:1.13.1
@ -81,26 +83,26 @@ androidx.hilt:hilt-navigation:1.2.0
androidx.hilt:hilt-work:1.1.0 androidx.hilt:hilt-work:1.1.0
androidx.interpolator:interpolator:1.0.0 androidx.interpolator:interpolator:1.0.0
androidx.legacy:legacy-support-core-utils:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0
androidx.lifecycle:lifecycle-common-java8:2.8.0-rc01 androidx.lifecycle:lifecycle-common-java8:2.8.0
androidx.lifecycle:lifecycle-common-jvm:2.8.0-rc01 androidx.lifecycle:lifecycle-common-jvm:2.8.0
androidx.lifecycle:lifecycle-common:2.8.0-rc01 androidx.lifecycle:lifecycle-common:2.8.0
androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0-rc01 androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0
androidx.lifecycle:lifecycle-livedata-core:2.8.0-rc01 androidx.lifecycle:lifecycle-livedata-core:2.8.0
androidx.lifecycle:lifecycle-livedata:2.8.0-rc01 androidx.lifecycle:lifecycle-livedata:2.8.0
androidx.lifecycle:lifecycle-process:2.8.0-rc01 androidx.lifecycle:lifecycle-process:2.8.0
androidx.lifecycle:lifecycle-runtime-android:2.8.0-rc01 androidx.lifecycle:lifecycle-runtime-android:2.8.0
androidx.lifecycle:lifecycle-runtime-compose-android:2.8.0-rc01 androidx.lifecycle:lifecycle-runtime-compose-android:2.8.0
androidx.lifecycle:lifecycle-runtime-compose:2.8.0-rc01 androidx.lifecycle:lifecycle-runtime-compose:2.8.0
androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.0-rc01 androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.0
androidx.lifecycle:lifecycle-runtime-ktx:2.8.0-rc01 androidx.lifecycle:lifecycle-runtime-ktx:2.8.0
androidx.lifecycle:lifecycle-runtime:2.8.0-rc01 androidx.lifecycle:lifecycle-runtime:2.8.0
androidx.lifecycle:lifecycle-service:2.8.0-rc01 androidx.lifecycle:lifecycle-service:2.8.0
androidx.lifecycle:lifecycle-viewmodel-android:2.8.0-rc01 androidx.lifecycle:lifecycle-viewmodel-android:2.8.0
androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.0-rc01 androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.0
androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-rc01 androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0
androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0-rc01 androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0-rc01 androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0
androidx.lifecycle:lifecycle-viewmodel:2.8.0-rc01 androidx.lifecycle:lifecycle-viewmodel:2.8.0
androidx.loader:loader:1.0.0 androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-alpha04 androidx.metrics:metrics-performance:1.0.0-alpha04
@ -130,9 +132,9 @@ androidx.vectordrawable:vectordrawable:1.1.0
androidx.versionedparcelable:versionedparcelable:1.1.1 androidx.versionedparcelable:versionedparcelable:1.1.1
androidx.viewpager:viewpager:1.0.0 androidx.viewpager:viewpager:1.0.0
androidx.window.extensions.core:core:1.0.0 androidx.window.extensions.core:core:1.0.0
androidx.window:window-core-android:1.3.0-alpha03 androidx.window:window-core-android:1.3.0-beta02
androidx.window:window-core:1.3.0-alpha03 androidx.window:window-core:1.3.0-beta02
androidx.window:window:1.3.0-alpha03 androidx.window:window:1.3.0-beta02
androidx.work:work-runtime-ktx:2.9.0 androidx.work:work-runtime-ktx:2.9.0
androidx.work:work-runtime:2.9.0 androidx.work:work-runtime:2.9.0
com.caverock:androidsvg-aar:1.4 com.caverock:androidsvg-aar:1.4
@ -155,10 +157,10 @@ com.google.android.gms:play-services-oss-licenses:17.0.1
com.google.android.gms:play-services-stats:17.0.2 com.google.android.gms:play-services-stats:17.0.2
com.google.android.gms:play-services-tasks:18.0.2 com.google.android.gms:play-services-tasks:18.0.2
com.google.code.findbugs:jsr305:3.0.2 com.google.code.findbugs:jsr305:3.0.2
com.google.dagger:dagger-lint-aar:2.51 com.google.dagger:dagger-lint-aar:2.51.1
com.google.dagger:dagger:2.51 com.google.dagger:dagger:2.51.1
com.google.dagger:hilt-android:2.51 com.google.dagger:hilt-android:2.51.1
com.google.dagger:hilt-core:2.51 com.google.dagger:hilt-core:2.51.1
com.google.errorprone:error_prone_annotations:2.11.0 com.google.errorprone:error_prone_annotations:2.11.0
com.google.firebase:firebase-abt:21.1.1 com.google.firebase:firebase-abt:21.1.1
com.google.firebase:firebase-analytics-ktx:21.4.0 com.google.firebase:firebase-analytics-ktx:21.4.0
@ -204,10 +206,10 @@ io.coil-kt:coil-svg:2.6.0
io.coil-kt:coil:2.6.0 io.coil-kt:coil:2.6.0
javax.inject:javax.inject:1 javax.inject:javax.inject:1
org.checkerframework:checker-qual:3.12.0 org.checkerframework:checker-qual:3.12.0
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.22 org.jetbrains.kotlin:kotlin-stdlib-common:2.0.0
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0 org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0
org.jetbrains.kotlin:kotlin-stdlib:1.9.22 org.jetbrains.kotlin:kotlin-stdlib:2.0.0
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.0 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.0
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0

@ -20,7 +20,6 @@ import androidx.annotation.StringRes
import androidx.compose.ui.test.assertCountEquals import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertIsOn import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.AndroidComposeTestRule
@ -225,12 +224,7 @@ class NavigationTest {
onNodeWithText(ok).performClick() onNodeWithText(ok).performClick()
// Check that the saved screen is still visible and selected. // Check that the saved screen is still visible and selected.
onNode( onNode(hasText(saved) and hasTestTag("NiaNavItem")).assertIsSelected()
hasText(saved) and
hasAnyAncestor(
hasTestTag("NiaBottomBar") or hasTestTag("NiaNavRail"),
),
).assertIsSelected()
} }
} }

@ -1,247 +0,0 @@
/*
* Copyright 2022 The Android Open Source Project
*
* 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
*
* https://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 com.google.samples.apps.nowinandroid.ui
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.DeviceConfigurationOverride
import androidx.compose.ui.test.ForcedSize
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import com.google.samples.apps.nowinandroid.core.rules.GrantPostNotificationsPermissionRule
import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import javax.inject.Inject
/**
* Tests that the navigation UI is rendered correctly on different screen sizes.
*/
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@HiltAndroidTest
class NavigationUiTest {
/**
* Manages the components' state and is used to perform injection on your test
*/
@get:Rule(order = 0)
val hiltRule = HiltAndroidRule(this)
/**
* Create a temporary folder used to create a Data Store file. This guarantees that
* the file is removed in between each test, preventing a crash.
*/
@BindValue
@get:Rule(order = 1)
val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()
/**
* Grant [android.Manifest.permission.POST_NOTIFICATIONS] permission.
*/
@get:Rule(order = 2)
val postNotificationsPermission = GrantPostNotificationsPermissionRule()
/**
* Use a test activity to set the content on.
*/
@get:Rule(order = 3)
val composeTestRule = createAndroidComposeRule<HiltComponentActivity>()
val userNewsResourceRepository = CompositeUserNewsResourceRepository(
newsRepository = TestNewsRepository(),
userDataRepository = TestUserDataRepository(),
)
@Inject
lateinit var networkMonitor: NetworkMonitor
@Inject
lateinit var timeZoneMonitor: TimeZoneMonitor
@Before
fun setup() {
hiltRule.inject()
}
@Test
fun compactWidth_compactHeight_showsNavigationBar() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(400.dp, 400.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaBottomBar").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaNavRail").assertDoesNotExist()
}
@Test
fun mediumWidth_compactHeight_showsNavigationRail() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(610.dp, 400.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaNavRail").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaBottomBar").assertDoesNotExist()
}
@Test
fun expandedWidth_compactHeight_showsNavigationRail() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(900.dp, 400.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaNavRail").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaBottomBar").assertDoesNotExist()
}
@Test
fun compactWidth_mediumHeight_showsNavigationBar() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(400.dp, 500.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaBottomBar").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaNavRail").assertDoesNotExist()
}
@Test
fun mediumWidth_mediumHeight_showsNavigationRail() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(610.dp, 500.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaNavRail").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaBottomBar").assertDoesNotExist()
}
@Test
fun expandedWidth_mediumHeight_showsNavigationRail() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(900.dp, 500.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaNavRail").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaBottomBar").assertDoesNotExist()
}
@Test
fun compactWidth_expandedHeight_showsNavigationBar() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(400.dp, 1000.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaBottomBar").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaNavRail").assertDoesNotExist()
}
@Test
fun mediumWidth_expandedHeight_showsNavigationRail() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(610.dp, 1000.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaNavRail").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaBottomBar").assertDoesNotExist()
}
@Test
fun expandedWidth_expandedHeight_showsNavigationRail() {
composeTestRule.setContent {
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(900.dp, 1000.dp)),
) {
BoxWithConstraints {
NiaApp(fakeAppState(maxWidth, maxHeight))
}
}
}
composeTestRule.onNodeWithTag("NiaNavRail").assertIsDisplayed()
composeTestRule.onNodeWithTag("NiaBottomBar").assertDoesNotExist()
}
@Composable
private fun fakeAppState(maxWidth: Dp, maxHeight: Dp) = rememberNiaAppState(
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(maxWidth, maxHeight)),
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
}

@ -16,15 +16,11 @@
package com.google.samples.apps.nowinandroid.ui package com.google.samples.apps.nowinandroid.ui
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.ComposeNavigator import androidx.navigation.compose.ComposeNavigator
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@ -43,7 +39,6 @@ import kotlinx.datetime.TimeZone
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
/** /**
@ -52,7 +47,6 @@ import kotlin.test.assertTrue
* Note: This could become an unit test if Robolectric is added to the project and the Context * Note: This could become an unit test if Robolectric is added to the project and the Context
* is faked. * is faked.
*/ */
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
class NiaAppStateTest { class NiaAppStateTest {
@get:Rule @get:Rule
@ -79,7 +73,6 @@ class NiaAppStateTest {
NiaAppState( NiaAppState(
navController = navController, navController = navController,
coroutineScope = backgroundScope, coroutineScope = backgroundScope,
windowSizeClass = getCompactWindowClass(),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor, timeZoneMonitor = timeZoneMonitor,
@ -102,7 +95,6 @@ class NiaAppStateTest {
fun niaAppState_destinations() = runTest { fun niaAppState_destinations() = runTest {
composeTestRule.setContent { composeTestRule.setContent {
state = rememberNiaAppState( state = rememberNiaAppState(
windowSizeClass = getCompactWindowClass(),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor, timeZoneMonitor = timeZoneMonitor,
@ -115,64 +107,12 @@ class NiaAppStateTest {
assertTrue(state.topLevelDestinations[2].name.contains("interests", true)) assertTrue(state.topLevelDestinations[2].name.contains("interests", true))
} }
@Test
fun niaAppState_showBottomBar_compact() = runTest {
composeTestRule.setContent {
state = NiaAppState(
navController = NavHostController(LocalContext.current),
coroutineScope = backgroundScope,
windowSizeClass = getCompactWindowClass(),
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
}
assertTrue(state.shouldShowBottomBar)
assertFalse(state.shouldShowNavRail)
}
@Test
fun niaAppState_showNavRail_medium() = runTest {
composeTestRule.setContent {
state = NiaAppState(
navController = NavHostController(LocalContext.current),
coroutineScope = backgroundScope,
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(800.dp, 800.dp)),
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
}
assertTrue(state.shouldShowNavRail)
assertFalse(state.shouldShowBottomBar)
}
@Test
fun niaAppState_showNavRail_large() = runTest {
composeTestRule.setContent {
state = NiaAppState(
navController = NavHostController(LocalContext.current),
coroutineScope = backgroundScope,
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(900.dp, 1200.dp)),
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
}
assertTrue(state.shouldShowNavRail)
assertFalse(state.shouldShowBottomBar)
}
@Test @Test
fun niaAppState_whenNetworkMonitorIsOffline_StateIsOffline() = runTest(UnconfinedTestDispatcher()) { fun niaAppState_whenNetworkMonitorIsOffline_StateIsOffline() = runTest(UnconfinedTestDispatcher()) {
composeTestRule.setContent { composeTestRule.setContent {
state = NiaAppState( state = NiaAppState(
navController = NavHostController(LocalContext.current), navController = NavHostController(LocalContext.current),
coroutineScope = backgroundScope, coroutineScope = backgroundScope,
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(900.dp, 1200.dp)),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor, timeZoneMonitor = timeZoneMonitor,
@ -193,7 +133,6 @@ class NiaAppStateTest {
state = NiaAppState( state = NiaAppState(
navController = NavHostController(LocalContext.current), navController = NavHostController(LocalContext.current),
coroutineScope = backgroundScope, coroutineScope = backgroundScope,
windowSizeClass = getCompactWindowClass(),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor, timeZoneMonitor = timeZoneMonitor,
@ -207,8 +146,6 @@ class NiaAppStateTest {
state.currentTimeZone.value, state.currentTimeZone.value,
) )
} }
private fun getCompactWindowClass() = WindowSizeClass.calculateFromSize(DpSize(500.dp, 300.dp))
} }
@Composable @Composable

@ -23,8 +23,7 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
@ -58,7 +57,6 @@ import javax.inject.Inject
private const val TAG = "MainActivity" private const val TAG = "MainActivity"
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ -134,7 +132,6 @@ class MainActivity : ComponentActivity() {
} }
val appState = rememberNiaAppState( val appState = rememberNiaAppState(
windowSizeClass = calculateWindowSizeClass(this),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor, timeZoneMonitor = timeZoneMonitor,
@ -151,6 +148,7 @@ class MainActivity : ComponentActivity() {
androidTheme = shouldUseAndroidTheme(uiState), androidTheme = shouldUseAndroidTheme(uiState),
disableDynamicTheming = shouldDisableDynamicTheming(uiState), disableDynamicTheming = shouldDisableDynamicTheming(uiState),
) { ) {
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
NiaApp(appState) NiaApp(appState)
} }
} }

@ -18,7 +18,6 @@ package com.google.samples.apps.nowinandroid.ui
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.consumeWindowInsets
@ -26,7 +25,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@ -39,6 +37,9 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult.ActionPerformed import androidx.compose.material3.SnackbarResult.ActionPerformed
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -64,10 +65,7 @@ import androidx.navigation.NavDestination.Companion.hierarchy
import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.R
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaGradientBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaGradientBackground
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationBar import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationSuiteScaffold
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationBarItem
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationRail
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationRailItem
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopAppBar import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopAppBar
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColors import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColors
@ -77,8 +75,13 @@ import com.google.samples.apps.nowinandroid.navigation.NiaNavHost
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination
import com.google.samples.apps.nowinandroid.feature.settings.R as settingsR import com.google.samples.apps.nowinandroid.feature.settings.R as settingsR
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable @Composable
fun NiaApp(appState: NiaAppState, modifier: Modifier = Modifier) { fun NiaApp(
appState: NiaAppState,
modifier: Modifier = Modifier,
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(),
) {
val shouldShowGradientBackground = val shouldShowGradientBackground =
appState.currentTopLevelDestination == TopLevelDestination.FOR_YOU appState.currentTopLevelDestination == TopLevelDestination.FOR_YOU
var showSettingsDialog by rememberSaveable { mutableStateOf(false) } var showSettingsDialog by rememberSaveable { mutableStateOf(false) }
@ -112,13 +115,18 @@ fun NiaApp(appState: NiaAppState, modifier: Modifier = Modifier) {
showSettingsDialog = showSettingsDialog, showSettingsDialog = showSettingsDialog,
onSettingsDismissed = { showSettingsDialog = false }, onSettingsDismissed = { showSettingsDialog = false },
onTopAppBarActionClick = { showSettingsDialog = true }, onTopAppBarActionClick = { showSettingsDialog = true },
windowAdaptiveInfo = windowAdaptiveInfo,
) )
} }
} }
} }
@Composable @Composable
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) @OptIn(
ExperimentalMaterial3Api::class,
ExperimentalComposeUiApi::class,
ExperimentalMaterial3AdaptiveApi::class,
)
internal fun NiaApp( internal fun NiaApp(
appState: NiaAppState, appState: NiaAppState,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
@ -126,59 +134,69 @@ internal fun NiaApp(
onSettingsDismissed: () -> Unit, onSettingsDismissed: () -> Unit,
onTopAppBarActionClick: () -> Unit, onTopAppBarActionClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(),
) { ) {
val unreadDestinations by appState.topLevelDestinationsWithUnreadResources val unreadDestinations by appState.topLevelDestinationsWithUnreadResources
.collectAsStateWithLifecycle() .collectAsStateWithLifecycle()
val currentDestination = appState.currentDestination
if (showSettingsDialog) { if (showSettingsDialog) {
SettingsDialog( SettingsDialog(
onDismiss = { onSettingsDismissed() }, onDismiss = { onSettingsDismissed() },
) )
} }
Scaffold(
modifier = modifier.semantics { NiaNavigationSuiteScaffold(
testTagsAsResourceId = true navigationSuiteItems = {
}, appState.topLevelDestinations.forEach { destination ->
containerColor = Color.Transparent, val hasUnread = unreadDestinations.contains(destination)
contentColor = MaterialTheme.colorScheme.onBackground, val selected = currentDestination
contentWindowInsets = WindowInsets(0, 0, 0, 0), .isTopLevelDestinationInHierarchy(destination)
snackbarHost = { SnackbarHost(snackbarHostState) }, item(
bottomBar = { selected = selected,
if (appState.shouldShowBottomBar) { onClick = { appState.navigateToTopLevelDestination(destination) },
NiaBottomBar( icon = {
destinations = appState.topLevelDestinations, Icon(
destinationsWithUnreadResources = unreadDestinations, imageVector = destination.unselectedIcon,
onNavigateToDestination = appState::navigateToTopLevelDestination, contentDescription = null,
currentDestination = appState.currentDestination, )
modifier = Modifier.testTag("NiaBottomBar"), },
selectedIcon = {
Icon(
imageVector = destination.selectedIcon,
contentDescription = null,
)
},
label = { Text(stringResource(destination.iconTextId)) },
modifier =
Modifier
.testTag("NiaNavItem")
.then(if (hasUnread) Modifier.notificationDot() else Modifier),
) )
} }
}, },
) { padding -> windowAdaptiveInfo = windowAdaptiveInfo,
Row( ) {
Modifier Scaffold(
.fillMaxSize() modifier = modifier.semantics {
.padding(padding) testTagsAsResourceId = true
.consumeWindowInsets(padding) },
.windowInsetsPadding( containerColor = Color.Transparent,
WindowInsets.safeDrawing.only( contentColor = MaterialTheme.colorScheme.onBackground,
WindowInsetsSides.Horizontal, contentWindowInsets = WindowInsets(0, 0, 0, 0),
snackbarHost = { SnackbarHost(snackbarHostState) },
) { padding ->
Column(
Modifier
.fillMaxSize()
.padding(padding)
.consumeWindowInsets(padding)
.windowInsetsPadding(
WindowInsets.safeDrawing.only(
WindowInsetsSides.Horizontal,
),
), ),
), ) {
) {
if (appState.shouldShowNavRail) {
NiaNavRail(
destinations = appState.topLevelDestinations,
destinationsWithUnreadResources = unreadDestinations,
onNavigateToDestination = appState::navigateToTopLevelDestination,
currentDestination = appState.currentDestination,
modifier = Modifier
.testTag("NiaNavRail")
.safeDrawingPadding(),
)
}
Column(Modifier.fillMaxSize()) {
// Show the top app bar on top level destinations. // Show the top app bar on top level destinations.
val destination = appState.currentTopLevelDestination val destination = appState.currentTopLevelDestination
val shouldShowTopAppBar = destination != null val shouldShowTopAppBar = destination != null
@ -202,13 +220,14 @@ internal fun NiaApp(
} }
Box( Box(
modifier = if (shouldShowTopAppBar) { // Workaround for https://issuetracker.google.com/338478720
Modifier.consumeWindowInsets( modifier = Modifier.consumeWindowInsets(
WindowInsets.safeDrawing.only(WindowInsetsSides.Top), if (shouldShowTopAppBar) {
) WindowInsets.safeDrawing.only(WindowInsetsSides.Top)
} else { } else {
Modifier WindowInsets(0, 0, 0, 0)
}, },
),
) { ) {
NiaNavHost( NiaNavHost(
appState = appState, appState = appState,
@ -221,80 +240,10 @@ internal fun NiaApp(
}, },
) )
} }
}
// TODO: We may want to add padding or spacer when the snackbar is shown so that // TODO: We may want to add padding or spacer when the snackbar is shown so that
// content doesn't display behind it. // content doesn't display behind it.
} }
}
}
@Composable
private fun NiaNavRail(
destinations: List<TopLevelDestination>,
destinationsWithUnreadResources: Set<TopLevelDestination>,
onNavigateToDestination: (TopLevelDestination) -> Unit,
currentDestination: NavDestination?,
modifier: Modifier = Modifier,
) {
NiaNavigationRail(modifier = modifier) {
destinations.forEach { destination ->
val selected = currentDestination.isTopLevelDestinationInHierarchy(destination)
val hasUnread = destinationsWithUnreadResources.contains(destination)
NiaNavigationRailItem(
selected = selected,
onClick = { onNavigateToDestination(destination) },
icon = {
Icon(
imageVector = destination.unselectedIcon,
contentDescription = null,
)
},
selectedIcon = {
Icon(
imageVector = destination.selectedIcon,
contentDescription = null,
)
},
label = { Text(stringResource(destination.iconTextId)) },
modifier = if (hasUnread) Modifier.notificationDot() else Modifier,
)
}
}
}
@Composable
private fun NiaBottomBar(
destinations: List<TopLevelDestination>,
destinationsWithUnreadResources: Set<TopLevelDestination>,
onNavigateToDestination: (TopLevelDestination) -> Unit,
currentDestination: NavDestination?,
modifier: Modifier = Modifier,
) {
NiaNavigationBar(
modifier = modifier,
) {
destinations.forEach { destination ->
val hasUnread = destinationsWithUnreadResources.contains(destination)
val selected = currentDestination.isTopLevelDestinationInHierarchy(destination)
NiaNavigationBarItem(
selected = selected,
onClick = { onNavigateToDestination(destination) },
icon = {
Icon(
imageVector = destination.unselectedIcon,
contentDescription = null,
)
},
selectedIcon = {
Icon(
imageVector = destination.selectedIcon,
contentDescription = null,
)
},
label = { Text(stringResource(destination.iconTextId)) },
modifier = if (hasUnread) Modifier.notificationDot() else Modifier,
)
} }
} }
} }

@ -16,8 +16,6 @@
package com.google.samples.apps.nowinandroid.ui package com.google.samples.apps.nowinandroid.ui
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -56,7 +54,6 @@ import kotlinx.datetime.TimeZone
@Composable @Composable
fun rememberNiaAppState( fun rememberNiaAppState(
windowSizeClass: WindowSizeClass,
networkMonitor: NetworkMonitor, networkMonitor: NetworkMonitor,
userNewsResourceRepository: UserNewsResourceRepository, userNewsResourceRepository: UserNewsResourceRepository,
timeZoneMonitor: TimeZoneMonitor, timeZoneMonitor: TimeZoneMonitor,
@ -67,7 +64,6 @@ fun rememberNiaAppState(
return remember( return remember(
navController, navController,
coroutineScope, coroutineScope,
windowSizeClass,
networkMonitor, networkMonitor,
userNewsResourceRepository, userNewsResourceRepository,
timeZoneMonitor, timeZoneMonitor,
@ -75,7 +71,6 @@ fun rememberNiaAppState(
NiaAppState( NiaAppState(
navController = navController, navController = navController,
coroutineScope = coroutineScope, coroutineScope = coroutineScope,
windowSizeClass = windowSizeClass,
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor, timeZoneMonitor = timeZoneMonitor,
@ -87,7 +82,6 @@ fun rememberNiaAppState(
class NiaAppState( class NiaAppState(
val navController: NavHostController, val navController: NavHostController,
coroutineScope: CoroutineScope, coroutineScope: CoroutineScope,
val windowSizeClass: WindowSizeClass,
networkMonitor: NetworkMonitor, networkMonitor: NetworkMonitor,
userNewsResourceRepository: UserNewsResourceRepository, userNewsResourceRepository: UserNewsResourceRepository,
timeZoneMonitor: TimeZoneMonitor, timeZoneMonitor: TimeZoneMonitor,
@ -106,12 +100,6 @@ class NiaAppState(
return null return null
} }
val shouldShowBottomBar: Boolean
get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact
val shouldShowNavRail: Boolean
get() = !shouldShowBottomBar
val isOffline = networkMonitor.isOnline val isOffline = networkMonitor.isOnline
.map(Boolean::not) .map(Boolean::not)
.stateIn( .stateIn(

@ -16,8 +16,9 @@
package com.google.samples.apps.nowinandroid.ui package com.google.samples.apps.nowinandroid.ui
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.adaptive.Posture
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.test.DeviceConfigurationOverride import androidx.compose.ui.test.DeviceConfigurationOverride
@ -27,6 +28,7 @@ import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.window.core.layout.WindowSizeClass
import com.github.takahirom.roborazzi.captureRoboImage import com.github.takahirom.roborazzi.captureRoboImage
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
@ -57,7 +59,6 @@ import javax.inject.Inject
/** /**
* Tests that the navigation UI is rendered correctly on different screen sizes. * Tests that the navigation UI is rendered correctly on different screen sizes.
*/ */
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE) @GraphicsMode(GraphicsMode.Mode.NATIVE)
// Configure Robolectric to use a very large screen size that can fit all of the test sizes. // Configure Robolectric to use a very large screen size that can fit all of the test sizes.
@ -122,6 +123,7 @@ class NiaAppScreenSizesScreenshotTests {
TimeZone.setDefault(TimeZone.getTimeZone("UTC")) TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
} }
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
private fun testNiaAppScreenshotWithSize(width: Dp, height: Dp, screenshotName: String) { private fun testNiaAppScreenshotWithSize(width: Dp, height: Dp, screenshotName: String) {
composeTestRule.setContent { composeTestRule.setContent {
CompositionLocalProvider( CompositionLocalProvider(
@ -132,14 +134,20 @@ class NiaAppScreenSizesScreenshotTests {
) { ) {
NiaTheme { NiaTheme {
val fakeAppState = rememberNiaAppState( val fakeAppState = rememberNiaAppState(
windowSizeClass = WindowSizeClass.calculateFromSize(
DpSize(width, height),
),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository, userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor, timeZoneMonitor = timeZoneMonitor,
) )
NiaApp(fakeAppState) NiaApp(
fakeAppState,
windowAdaptiveInfo = WindowAdaptiveInfo(
windowSizeClass = WindowSizeClass.compute(
width.value,
height.value,
),
windowPosture = Posture(),
),
)
} }
} }
} }
@ -162,20 +170,20 @@ class NiaAppScreenSizesScreenshotTests {
} }
@Test @Test
fun mediumWidth_compactHeight_showsNavigationRail() { fun mediumWidth_compactHeight_showsNavigationBar() {
testNiaAppScreenshotWithSize( testNiaAppScreenshotWithSize(
610.dp, 610.dp,
400.dp, 400.dp,
"mediumWidth_compactHeight_showsNavigationRail", "mediumWidth_compactHeight_showsNavigationBar",
) )
} }
@Test @Test
fun expandedWidth_compactHeight_showsNavigationRail() { fun expandedWidth_compactHeight_showsNavigationBar() {
testNiaAppScreenshotWithSize( testNiaAppScreenshotWithSize(
900.dp, 900.dp,
400.dp, 400.dp,
"expandedWidth_compactHeight_showsNavigationRail", "expandedWidth_compactHeight_showsNavigationBar",
) )
} }

@ -19,8 +19,9 @@ package com.google.samples.apps.nowinandroid.ui
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.material3.SnackbarDuration.Indefinite import androidx.compose.material3.SnackbarDuration.Indefinite
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.adaptive.Posture
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalInspectionMode
@ -31,6 +32,7 @@ import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.window.core.layout.WindowSizeClass
import com.github.takahirom.roborazzi.captureRoboImage import com.github.takahirom.roborazzi.captureRoboImage
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository
@ -63,7 +65,6 @@ import javax.inject.Inject
/** /**
* Tests that the Snackbar is correctly displayed on different screen sizes. * Tests that the Snackbar is correctly displayed on different screen sizes.
*/ */
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE) @GraphicsMode(GraphicsMode.Mode.NATIVE)
// Configure Robolectric to use a very large screen size that can fit all of the test sizes. // Configure Robolectric to use a very large screen size that can fit all of the test sizes.
@ -191,6 +192,7 @@ class SnackbarScreenshotTests {
} }
} }
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
private fun testSnackbarScreenshotWithSize( private fun testSnackbarScreenshotWithSize(
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
width: Dp, width: Dp,
@ -210,16 +212,26 @@ class SnackbarScreenshotTests {
DeviceConfigurationOverride.ForcedSize(DpSize(width, height)), DeviceConfigurationOverride.ForcedSize(DpSize(width, height)),
) { ) {
BoxWithConstraints { BoxWithConstraints {
val appState = rememberNiaAppState(
windowSizeClass = WindowSizeClass.calculateFromSize(
DpSize(maxWidth, maxHeight),
),
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
NiaTheme { NiaTheme {
NiaApp(appState, snackbarHostState, false, {}, {}) val appState = rememberNiaAppState(
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
NiaApp(
appState = appState,
snackbarHostState = snackbarHostState,
showSettingsDialog = false,
onSettingsDismissed = {},
onTopAppBarActionClick = {},
windowAdaptiveInfo = WindowAdaptiveInfo(
windowSizeClass = WindowSizeClass.compute(
maxWidth.value,
maxHeight.value,
),
windowPosture = Posture(),
),
)
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
@ -28,15 +29,17 @@ java {
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
} }
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions { kotlin {
jvmTarget = JavaVersion.VERSION_17.toString() compilerOptions {
jvmTarget = JvmTarget.JVM_17
} }
} }
dependencies { dependencies {
compileOnly(libs.android.gradlePlugin) compileOnly(libs.android.gradlePlugin)
compileOnly(libs.android.tools.common) compileOnly(libs.android.tools.common)
compileOnly(libs.compose.gradlePlugin)
compileOnly(libs.firebase.crashlytics.gradlePlugin) compileOnly(libs.firebase.crashlytics.gradlePlugin)
compileOnly(libs.firebase.performance.gradlePlugin) compileOnly(libs.firebase.performance.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin) compileOnly(libs.kotlin.gradlePlugin)

@ -18,12 +18,14 @@ import com.android.build.api.dsl.ApplicationExtension
import com.google.samples.apps.nowinandroid.configureAndroidCompose import com.google.samples.apps.nowinandroid.configureAndroidCompose
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
class AndroidApplicationComposeConventionPlugin : Plugin<Project> { class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {
pluginManager.apply("com.android.application") apply(plugin = "com.android.application")
apply(plugin = "org.jetbrains.kotlin.plugin.compose")
val extension = extensions.getByType<ApplicationExtension>() val extension = extensions.getByType<ApplicationExtension>()
configureAndroidCompose(extension) configureAndroidCompose(extension)

@ -18,14 +18,14 @@ import com.android.build.gradle.LibraryExtension
import com.google.samples.apps.nowinandroid.configureAndroidCompose import com.google.samples.apps.nowinandroid.configureAndroidCompose
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.kotlin
class AndroidLibraryComposeConventionPlugin : Plugin<Project> { class AndroidLibraryComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {
pluginManager.apply("com.android.library") apply(plugin = "com.android.library")
apply(plugin = "org.jetbrains.kotlin.plugin.compose")
val extension = extensions.getByType<LibraryExtension>() val extension = extensions.getByType<LibraryExtension>()
configureAndroidCompose(extension) configureAndroidCompose(extension)

@ -18,9 +18,11 @@ package com.google.samples.apps.nowinandroid
import com.android.build.api.dsl.CommonExtension import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/** /**
* Configure Compose-specific options * Configure Compose-specific options
@ -33,10 +35,6 @@ internal fun Project.configureAndroidCompose(
compose = true compose = true
} }
composeOptions {
kotlinCompilerExtensionVersion = libs.findVersion("androidxComposeCompiler").get().toString()
}
dependencies { dependencies {
val bom = libs.findLibrary("androidx-compose-bom").get() val bom = libs.findLibrary("androidx-compose-bom").get()
add("implementation", platform(bom)) add("implementation", platform(bom))
@ -53,48 +51,22 @@ internal fun Project.configureAndroidCompose(
} }
} }
tasks.withType<KotlinCompile>().configureEach { extensions.configure<ComposeCompilerGradlePluginExtension> {
kotlinOptions { fun Provider<String>.onlyIfTrue() = flatMap { provider { it.takeIf(String::toBoolean) } }
freeCompilerArgs += buildComposeMetricsParameters() fun Provider<*>.relativeToRootProject(dir: String) = flatMap {
freeCompilerArgs += stabilityConfiguration() rootProject.layout.buildDirectory.dir(projectDir.toRelativeString(rootDir))
freeCompilerArgs += strongSkippingConfiguration() }.map { it.dir(dir) }
}
}
}
private fun Project.buildComposeMetricsParameters(): List<String> { project.providers.gradleProperty("enableComposeCompilerMetrics").onlyIfTrue()
val metricParameters = mutableListOf<String>() .relativeToRootProject("compose-metrics")
val enableMetricsProvider = project.providers.gradleProperty("enableComposeCompilerMetrics") .let(metricsDestination::set)
val relativePath = projectDir.relativeTo(rootDir)
val buildDir = layout.buildDirectory.get().asFile
val enableMetrics = (enableMetricsProvider.orNull == "true")
if (enableMetrics) {
val metricsFolder = buildDir.resolve("compose-metrics").resolve(relativePath)
metricParameters.add("-P")
metricParameters.add(
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + metricsFolder.absolutePath,
)
}
val enableReportsProvider = project.providers.gradleProperty("enableComposeCompilerReports") project.providers.gradleProperty("enableComposeCompilerReports").onlyIfTrue()
val enableReports = (enableReportsProvider.orNull == "true") .relativeToRootProject("compose-reports")
if (enableReports) { .let(reportsDestination::set)
val reportsFolder = buildDir.resolve("compose-reports").resolve(relativePath)
metricParameters.add("-P")
metricParameters.add(
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + reportsFolder.absolutePath
)
}
return metricParameters.toList() stabilityConfigurationFile = rootProject.layout.projectDirectory.file("compose_compiler_config.conf")
enableStrongSkippingMode = true
}
} }
private fun Project.stabilityConfiguration() = listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=${project.rootDir.absolutePath}/compose_compiler_config.conf",
)
private fun Project.strongSkippingConfiguration() = listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:experimentalStrongSkipping=true",
)

@ -20,11 +20,14 @@ import com.android.build.api.dsl.CommonExtension
import org.gradle.api.JavaVersion import org.gradle.api.JavaVersion
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
/** /**
* Configure base Kotlin with Android options * Configure base Kotlin with Android options
@ -48,7 +51,7 @@ internal fun Project.configureKotlinAndroid(
} }
} }
configureKotlin() configureKotlin<KotlinAndroidProjectExtension>()
dependencies { dependencies {
add("coreLibraryDesugaring", libs.findLibrary("android.desugarJdkLibs").get()) add("coreLibraryDesugaring", libs.findLibrary("android.desugarJdkLibs").get())
@ -66,26 +69,26 @@ internal fun Project.configureKotlinJvm() {
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
configureKotlin() configureKotlin<KotlinJvmProjectExtension>()
} }
/** /**
* Configure base Kotlin options * Configure base Kotlin options
*/ */
private fun Project.configureKotlin() { private inline fun <reified T : KotlinTopLevelExtension> Project.configureKotlin() = configure<T> {
// Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947 // Treat all Kotlin warnings as errors (disabled by default)
tasks.withType<KotlinCompile>().configureEach { // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties
kotlinOptions { val warningsAsErrors: String? by project
// Set JVM target to 11 when (this) {
jvmTarget = JavaVersion.VERSION_11.toString() is KotlinAndroidProjectExtension -> compilerOptions
// Treat all Kotlin warnings as errors (disabled by default) is KotlinJvmProjectExtension -> compilerOptions
// Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties else -> TODO("Unsupported project extension $this ${T::class}")
val warningsAsErrors: String? by project }.apply {
allWarningsAsErrors = warningsAsErrors.toBoolean() jvmTarget = JvmTarget.JVM_11
freeCompilerArgs = freeCompilerArgs + listOf( allWarningsAsErrors = warningsAsErrors.toBoolean()
// Enable experimental coroutines APIs, including Flow freeCompilerArgs.add(
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", // Enable experimental coroutines APIs, including Flow
) "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
} )
} }
} }

@ -36,6 +36,7 @@ plugins {
alias(libs.plugins.android.library) apply false alias(libs.plugins.android.library) apply false
alias(libs.plugins.android.test) apply false alias(libs.plugins.android.test) apply false
alias(libs.plugins.baselineprofile) apply false alias(libs.plugins.baselineprofile) apply false
alias(libs.plugins.compose) apply false
alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.dependencyGuard) apply false alias(libs.plugins.dependencyGuard) apply false

@ -34,6 +34,8 @@ dependencies {
api(libs.androidx.compose.foundation.layout) api(libs.androidx.compose.foundation.layout)
api(libs.androidx.compose.material.iconsExtended) api(libs.androidx.compose.material.iconsExtended)
api(libs.androidx.compose.material3) api(libs.androidx.compose.material3)
api(libs.androidx.compose.material3.adaptive)
api(libs.androidx.compose.material3.navigationSuite)
api(libs.androidx.compose.runtime) api(libs.androidx.compose.runtime)
api(libs.androidx.compose.ui.util) api(libs.androidx.compose.ui.util)

@ -23,10 +23,20 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationBarItemDefaults import androidx.compose.material3.NavigationBarItemDefaults
import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.NavigationRail import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem import androidx.compose.material3.NavigationRailItem
import androidx.compose.material3.NavigationRailItemDefaults import androidx.compose.material3.NavigationRailItemDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.adaptive.navigationsuite.ExperimentalMaterial3AdaptiveNavigationSuiteApi
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteDefaults
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteItemColors
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldDefaults
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScope
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@ -165,6 +175,101 @@ fun NiaNavigationRail(
) )
} }
/**
* Now in Android navigation suite scaffold with item and content slots.
* Wraps Material 3 [NavigationSuiteScaffold].
*
* @param modifier Modifier to be applied to the navigation suite scaffold.
* @param navigationSuiteItems A slot to display multiple items via [NiaNavigationSuiteScope].
* @param windowAdaptiveInfo The window adaptive info.
* @param content The app content inside the scaffold.
*/
@OptIn(
ExperimentalMaterial3AdaptiveNavigationSuiteApi::class,
ExperimentalMaterial3AdaptiveApi::class,
)
@Composable
fun NiaNavigationSuiteScaffold(
navigationSuiteItems: NiaNavigationSuiteScope.() -> Unit,
modifier: Modifier = Modifier,
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(),
content: @Composable () -> Unit,
) {
val layoutType = NavigationSuiteScaffoldDefaults
.calculateFromAdaptiveInfo(windowAdaptiveInfo)
val navigationSuiteItemColors = NavigationSuiteItemColors(
navigationBarItemColors = NavigationBarItemDefaults.colors(
selectedIconColor = NiaNavigationDefaults.navigationSelectedItemColor(),
unselectedIconColor = NiaNavigationDefaults.navigationContentColor(),
selectedTextColor = NiaNavigationDefaults.navigationSelectedItemColor(),
unselectedTextColor = NiaNavigationDefaults.navigationContentColor(),
indicatorColor = NiaNavigationDefaults.navigationIndicatorColor(),
),
navigationRailItemColors = NavigationRailItemDefaults.colors(
selectedIconColor = NiaNavigationDefaults.navigationSelectedItemColor(),
unselectedIconColor = NiaNavigationDefaults.navigationContentColor(),
selectedTextColor = NiaNavigationDefaults.navigationSelectedItemColor(),
unselectedTextColor = NiaNavigationDefaults.navigationContentColor(),
indicatorColor = NiaNavigationDefaults.navigationIndicatorColor(),
),
navigationDrawerItemColors = NavigationDrawerItemDefaults.colors(
selectedIconColor = NiaNavigationDefaults.navigationSelectedItemColor(),
unselectedIconColor = NiaNavigationDefaults.navigationContentColor(),
selectedTextColor = NiaNavigationDefaults.navigationSelectedItemColor(),
unselectedTextColor = NiaNavigationDefaults.navigationContentColor(),
),
)
NavigationSuiteScaffold(
navigationSuiteItems = {
NiaNavigationSuiteScope(
navigationSuiteScope = this,
navigationSuiteItemColors = navigationSuiteItemColors,
).run(navigationSuiteItems)
},
layoutType = layoutType,
containerColor = Color.Transparent,
navigationSuiteColors = NavigationSuiteDefaults.colors(
navigationBarContentColor = NiaNavigationDefaults.navigationContentColor(),
navigationRailContainerColor = Color.Transparent,
),
modifier = modifier,
) {
content()
}
}
/**
* A wrapper around [NavigationSuiteScope] to declare navigation items.
*/
@OptIn(ExperimentalMaterial3AdaptiveNavigationSuiteApi::class)
class NiaNavigationSuiteScope internal constructor(
private val navigationSuiteScope: NavigationSuiteScope,
private val navigationSuiteItemColors: NavigationSuiteItemColors,
) {
fun item(
selected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
icon: @Composable () -> Unit,
selectedIcon: @Composable () -> Unit = icon,
label: @Composable (() -> Unit)? = null,
) = navigationSuiteScope.item(
selected = selected,
onClick = onClick,
icon = {
if (selected) {
selectedIcon()
} else {
icon()
}
},
label = label,
colors = navigationSuiteItemColors,
modifier = modifier,
)
}
@ThemePreviews @ThemePreviews
@Composable @Composable
fun NiaNavigationBarPreview() { fun NiaNavigationBarPreview() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -7,10 +7,11 @@ androidTools = "31.4.0"
androidxActivity = "1.8.2" androidxActivity = "1.8.2"
androidxAppCompat = "1.6.1" androidxAppCompat = "1.6.1"
androidxBrowser = "1.8.0" androidxBrowser = "1.8.0"
androidxComposeAlpha = "1.7.0-beta01"
androidxComposeBom = "2024.02.02" androidxComposeBom = "2024.02.02"
androidxComposeCompiler = "1.5.8" androidxComposeCompiler = "1.5.12"
androidxComposeUiTest = "1.7.0-alpha06" androidxComposeMaterial3Adaptive = "1.0.0-beta01"
androidxComposeMaterial3Adaptive = "1.0.0-alpha12" androidxComposeMaterial3AdaptiveNavigationSuite = "1.3.0-beta01"
androidxComposeRuntimeTracing = "1.0.0-beta01" androidxComposeRuntimeTracing = "1.0.0-beta01"
androidxCore = "1.12.0" androidxCore = "1.12.0"
androidxCoreSplashscreen = "1.0.1" androidxCoreSplashscreen = "1.0.1"
@ -38,15 +39,15 @@ firebasePerfPlugin = "1.4.2"
gmsPlugin = "4.4.1" gmsPlugin = "4.4.1"
googleOss = "17.0.1" googleOss = "17.0.1"
googleOssPlugin = "0.10.6" googleOssPlugin = "0.10.6"
hilt = "2.51" hilt = "2.51.1"
hiltExt = "1.1.0" hiltExt = "1.1.0"
jacoco = "0.8.7" jacoco = "0.8.7"
junit4 = "4.13.2" junit4 = "4.13.2"
kotlin = "1.9.22" kotlin = "2.0.0"
kotlinxCoroutines = "1.8.0" kotlinxCoroutines = "1.8.0"
kotlinxDatetime = "0.5.0" kotlinxDatetime = "0.5.0"
kotlinxSerializationJson = "1.6.3" kotlinxSerializationJson = "1.6.3"
ksp = "1.9.22-1.0.18" ksp = "2.0.0-1.0.21"
moduleGraph = "2.5.0" moduleGraph = "2.5.0"
okhttp = "4.12.0" okhttp = "4.12.0"
protobuf = "4.26.0" protobuf = "4.26.0"
@ -68,17 +69,18 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version
androidx-benchmark-macro = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "androidxMacroBenchmark" } androidx-benchmark-macro = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "androidxMacroBenchmark" }
androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidxBrowser" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidxBrowser" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidxComposeBom" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidxComposeBom" }
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" } androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "androidxComposeAlpha" }
androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout" } androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout" }
androidx-compose-material-iconsExtended = { group = "androidx.compose.material", name = "material-icons-extended" } androidx-compose-material-iconsExtended = { group = "androidx.compose.material", name = "material-icons-extended" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-compose-material3-navigationSuite = { group = "androidx.compose.material3", name = "material3-adaptive-navigation-suite", version.ref = "androidxComposeMaterial3AdaptiveNavigationSuite" }
androidx-compose-material3-adaptive = { group = "androidx.compose.material3.adaptive", name = "adaptive", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive = { group = "androidx.compose.material3.adaptive", name = "adaptive", version.ref = "androidxComposeMaterial3Adaptive" }
androidx-compose-material3-adaptive-layout = { group = "androidx.compose.material3.adaptive", name = "adaptive-layout", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive-layout = { group = "androidx.compose.material3.adaptive", name = "adaptive-layout", version.ref = "androidxComposeMaterial3Adaptive" }
androidx-compose-material3-adaptive-navigation = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive-navigation = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation", version.ref = "androidxComposeMaterial3Adaptive" }
androidx-compose-material3-windowSizeClass = { group = "androidx.compose.material3", name = "material3-window-size-class" } androidx-compose-material3-windowSizeClass = { group = "androidx.compose.material3", name = "material3-window-size-class" }
androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" } androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" }
androidx-compose-runtime-tracing = { group = "androidx.compose.runtime", name = "runtime-tracing", version.ref = "androidxComposeRuntimeTracing" } androidx-compose-runtime-tracing = { group = "androidx.compose.runtime", name = "runtime-tracing", version.ref = "androidxComposeRuntimeTracing" }
androidx-compose-ui-test = { group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "androidxComposeUiTest" } androidx-compose-ui-test = { group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "androidxComposeAlpha" }
androidx-compose-ui-testManifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-testManifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
@ -144,6 +146,7 @@ turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine
# Dependencies of the included build-logic # Dependencies of the included build-logic
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
android-tools-common = { group = "com.android.tools", name = "common", version.ref = "androidTools" } android-tools-common = { group = "com.android.tools", name = "common", version.ref = "androidTools" }
compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
firebase-crashlytics-gradlePlugin = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "firebaseCrashlyticsPlugin" } firebase-crashlytics-gradlePlugin = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "firebaseCrashlyticsPlugin" }
firebase-performance-gradlePlugin = { group = "com.google.firebase", name = "perf-plugin", version.ref = "firebasePerfPlugin" } firebase-performance-gradlePlugin = { group = "com.google.firebase", name = "perf-plugin", version.ref = "firebasePerfPlugin" }
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
@ -155,6 +158,7 @@ android-application = { id = "com.android.application", version.ref = "androidGr
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
android-test = { id = "com.android.test", version.ref = "androidGradlePlugin" } android-test = { id = "com.android.test", version.ref = "androidGradlePlugin" }
baselineprofile = { id = "androidx.baselineprofile", version.ref = "androidxMacroBenchmark"} baselineprofile = { id = "androidx.baselineprofile", version.ref = "androidxMacroBenchmark"}
compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
dependencyGuard = { id = "com.dropbox.dependency-guard", version.ref = "dependencyGuard" } dependencyGuard = { id = "com.dropbox.dependency-guard", version.ref = "dependencyGuard" }
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebaseCrashlyticsPlugin" } firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebaseCrashlyticsPlugin" }
firebase-perf = { id = "com.google.firebase.firebase-perf", version.ref = "firebasePerfPlugin" } firebase-perf = { id = "com.google.firebase.firebase-perf", version.ref = "firebasePerfPlugin" }

@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
@ -29,9 +30,9 @@ java {
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
tasks.withType<KotlinCompile>().configureEach { kotlin {
kotlinOptions { compilerOptions {
jvmTarget = JavaVersion.VERSION_11.toString() jvmTarget = JvmTarget.JVM_11
} }
} }

Loading…
Cancel
Save