Merge pull request #186 from lihenggui/fix-ci-and-add-agents-md

Fix CI build and add AGENTS.md
pull/2064/head
Mercury Li 3 weeks ago committed by GitHub
commit d3a3157224
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -76,7 +76,7 @@ jobs:
- name: Run all local screenshot tests (Roborazzi)
id: screenshotsverify
continue-on-error: true
run: ./gradlew verifyRoborazziDemoDebug
run: ./gradlew verifyRoborazziDebug
- name: Prevent pushing new screenshots if this is a fork
id: checkfork_screenshots
@ -92,7 +92,7 @@ jobs:
id: screenshotsrecord
if: steps.screenshotsverify.outcome == 'failure' && github.event_name == 'pull_request'
run: |
./gradlew recordRoborazziDemoDebug
./gradlew recordRoborazziDebug
- name: Push new screenshots if available
uses: stefanzweifel/git-auto-commit-action@v5
@ -104,7 +104,7 @@ jobs:
# Run local tests after screenshot tests to avoid wrong UP-TO-DATE. TODO: Ignore screenshots.
- name: Run local tests
run: ./gradlew testDemoDebug :lint:test
run: ./gradlew testDebugUnitTest :lint:test
- name: Build all build type and flavor permutations
run: ./gradlew :app:assemble
@ -130,7 +130,7 @@ jobs:
path: '**/build/outputs/roborazzi/*_compare.png'
- name: Check lint
run: ./gradlew :app:lintProdRelease :app-nia-catalog:lintRelease :lint:lint
run: ./gradlew :app:lintRelease :app-nia-catalog:lintRelease :lint:lint
- name: Upload lint reports (HTML)
if: ${{ !cancelled() }}
@ -146,7 +146,7 @@ jobs:
sarif_file: './'
- name: Check badging
run: ./gradlew :app:checkProdReleaseBadging
run: ./gradlew :app:checkReleaseBadging
androidTest:
runs-on: ubuntu-latest
@ -199,17 +199,16 @@ jobs:
disable-animations: true
disk-size: 6000M
heap-size: 600M
script: ./gradlew connectedDemoDebugAndroidTest --daemon
script: ./gradlew connectedDebugAndroidTest --daemon
- name: Run local tests (including Roborazzi) for the combined coverage report (only API 30)
if: matrix.api-level == 30
# There is no need to verify Roborazzi tests to generate coverage.
run: ./gradlew testDemoDebugUnitTest -Proborazzi.test.verify=false # Add Prod if we ever add JVM tests for prod
run: ./gradlew testDebugUnitTest -Proborazzi.test.verify=false
# Add `createProdDebugUnitTestCoverageReport` if we ever add JVM tests for prod
- name: Generate coverage reports for Debug variants (only API 30)
if: matrix.api-level == 30
run: ./gradlew createDemoDebugCombinedCoverageReport
run: ./gradlew createDebugCombinedCoverageReport
- name: Upload test reports
if: ${{ !cancelled() }}

3
.gitignore vendored

@ -47,3 +47,6 @@ captures/
# Kotlin
.kotlin
# Claude Code
.claude

@ -0,0 +1,99 @@
# AGENTS.md
This file provides guidance to AI coding agents when working with code in this repository.
## Project Overview
Now in Android (KMP edition) — a Kotlin Multiplatform fork of Google's Now in Android reference app. Targets Android, iOS, Desktop (JVM), macOS, and experimental Web (WASM). Uses Compose Multiplatform for shared UI.
## Build Commands
```bash
# Format code (must pass before merge)
./gradlew spotlessApply
./gradlew spotlessCheck --init-script gradle/init.gradle.kts --no-configuration-cache
# Build
./gradlew :app:assemble # main app (all variants)
./gradlew :app-nia-catalog:assemble # design system catalog app
# Run desktop app
# Gradle run config task: desktopRun -DmainClass=MainKt --quiet
# Unit tests
./gradlew testDebugUnitTest # all module tests
./gradlew :feature:foryou:testDebugUnitTest # single module test
./gradlew :lint:test # lint rule tests
# Instrumented tests (requires a connected Android emulator)
./gradlew connectedDebugAndroidTest
# Screenshot tests (Roborazzi — CI only, do NOT run locally)
# CI records/verifies screenshots and auto-commits updates via PR
# ./gradlew verifyRoborazziDebug # verify against baselines (CI only)
# ./gradlew recordRoborazziDebug # record new baselines (CI only)
# Lint
./gradlew :app:lintRelease :app-nia-catalog:lintRelease :lint:lint
# Dependency guard
./gradlew dependencyGuard # check
./gradlew dependencyGuardBaseline # update baseline
# Build-logic check
./gradlew :build-logic:convention:check
# Badging check
./gradlew :app:checkReleaseBadging
```
## Architecture
**Three-layer architecture** with unidirectional data flow (UDF):
- **UI Layer** (`feature:*`) — Compose screens + ViewModels. Each feature module is independent; no inter-feature dependencies.
- **Domain Layer** (`core:domain`) — Use cases combining data from multiple repositories.
- **Data Layer** (`core:data`, `core:database`, `core:datastore`, `core:network`) — Offline-first repositories backed by SQLDelight + Proto DataStore, synced via Ktor/Ktrofit.
### Module Structure
- **`app`** — Main KMP application with app-level navigation (NiaNavHost, TopLevelDestination). WIP for full multiplatform.
- **`app-nia-catalog`** — Standalone design system showcase. Fully multiplatform including WASM.
- **`feature:*`** — Feature modules (foryou, interests, bookmarks, topic, search, settings). Depend only on `core:*` modules.
- **`core:*`** — Shared libraries. Key ones: `designsystem` (Material 3 components), `ui` (reusable composables), `model` (data types), `data` (repositories), `database` (SQLDelight), `network` (Ktor), `datastore` (Proto DataStore).
- **`shared`** — Aggregates features and core for the main app.
- **`sync:work`** — WorkManager-based sync (Android-only).
- **`build-logic/convention`** — Custom Gradle convention plugins.
### Convention Plugins
All modules use convention plugins from `build-logic/convention/` (plugin IDs prefixed `nowinandroid.*`):
- `nowinandroid.kmp.library` — KMP library: configures Android library + KMP targets (JVM, Android, iOS, macOS) + common test deps
- `nowinandroid.cmp.application` — Compose Multiplatform app (Android, Desktop, iOS, macOS)
- `nowinandroid.cmp.feature` — Feature module (inherits kmp.library + adds Compose, Koin, core:ui, core:designsystem)
- `nowinandroid.di.koin` — Koin DI with KSP annotation processing
- `nowinandroid.sqldelight` — SQLDelight database
- `nowinandroid.kmp.inject` — kotlin-inject DI via KSP
### Key Technology Choices
- **DI:** Koin (primary, KMP-friendly service locator) + kotlin-inject (compile-time alternative)
- **Database:** SQLDelight (multiplatform)
- **Preferences:** Proto DataStore
- **Networking:** Ktor client via Ktrofit
- **Image loading:** Coil 3
- **Serialization:** kotlinx-serialization
- **Testing:** No mocking libraries — use test doubles. Roborazzi for screenshot tests (CI only), Turbine for Flow testing.
### Build Variants
Two build types: `debug` and `release`. No flavor dimensions (demo/prod flavors were removed during KMP migration).
### KMP Source Set Layout
Modules use Kotlin Multiplatform default hierarchy: `commonMain`/`commonTest`, `androidMain`/`androidUnitTest`/`androidInstrumentedTest`, `jvmMain`/`jvmTest`, `iosMain`, `macosMain`, etc. Android resource prefixes are auto-derived from module path (e.g., `core_model_`).
## Requirements
- JDK 17+
- Gradle uses 4GB heap (`-Xmx4g`)
- Configuration cache and parallel builds enabled

@ -0,0 +1 @@
AGENTS.md

@ -31,7 +31,7 @@ plugins {
kotlin {
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
moduleName = "composeApp"
outputModuleName.set("composeApp")
browser {
commonWebpackConfig {
outputFileName = "composeApp.js"
@ -52,7 +52,11 @@ kotlin {
}
}
jvm("desktop")
jvm("desktop") {
compilerOptions {
jvmTarget.set(JVM_11)
}
}
listOf(
iosX64(),
@ -94,7 +98,7 @@ android {
versionName = "0.0.1" // X.Y.Z; X = Major, Y = minor, Z = Patch level
minSdk = 24
targetSdk = 34
compileSdk = 34
compileSdk = 35
// The UI catalog does not depend on content from the app, however, it depends on modules
// which do, so we must specify a default value for the contentType dimension.
missingDimensionStrategy("contentType", "demo")

@ -1,86 +1,86 @@
androidx.activity:activity-compose:1.9.3
androidx.activity:activity-ktx:1.9.3
androidx.activity:activity:1.9.3
androidx.activity:activity-compose:1.10.0
androidx.activity:activity-ktx:1.10.0
androidx.activity:activity:1.10.0
androidx.annotation:annotation-experimental:1.4.1
androidx.annotation:annotation-jvm:1.9.0
androidx.annotation:annotation:1.9.0
androidx.annotation:annotation-jvm:1.9.1
androidx.annotation:annotation:1.9.1
androidx.appcompat:appcompat-resources:1.7.0
androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0
androidx.autofill:autofill:1.0.0
androidx.collection:collection-jvm:1.4.4
androidx.collection:collection-ktx:1.4.4
androidx.collection:collection:1.4.4
androidx.compose.animation:animation-android:1.7.4
androidx.compose.animation:animation-core-android:1.7.4
androidx.compose.animation:animation-core:1.7.4
androidx.compose.animation:animation:1.7.4
androidx.compose.foundation:foundation-android:1.7.4
androidx.compose.foundation:foundation-layout-android:1.7.4
androidx.compose.foundation:foundation-layout:1.7.4
androidx.compose.foundation:foundation:1.7.4
androidx.compose.material3.adaptive:adaptive-android:1.0.0
androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0
androidx.compose.material3.adaptive:adaptive-layout:1.0.0
androidx.compose.material3.adaptive:adaptive:1.0.0
androidx.compose.material3:material3-adaptive-navigation-suite-android:1.3.0
androidx.compose.material3:material3-adaptive-navigation-suite:1.3.0
androidx.compose.material3:material3-android:1.3.0
androidx.compose.material3:material3:1.3.0
androidx.compose.material:material-android:1.7.1
androidx.compose.material:material-icons-core-android:1.7.1
androidx.compose.material:material-icons-core:1.7.1
androidx.compose.material:material-icons-extended-android:1.7.1
androidx.compose.material:material-icons-extended:1.7.1
androidx.compose.material:material-ripple-android:1.7.1
androidx.compose.material:material-ripple:1.7.1
androidx.compose.material:material:1.7.1
androidx.compose.runtime:runtime-android:1.7.4
androidx.compose.runtime:runtime-saveable-android:1.7.4
androidx.compose.runtime:runtime-saveable:1.7.4
androidx.compose.runtime:runtime:1.7.4
androidx.compose.ui:ui-android:1.7.4
androidx.compose.ui:ui-geometry-android:1.7.4
androidx.compose.ui:ui-geometry:1.7.4
androidx.compose.ui:ui-graphics-android:1.7.4
androidx.compose.ui:ui-graphics:1.7.4
androidx.compose.ui:ui-text-android:1.7.4
androidx.compose.ui:ui-text:1.7.4
androidx.compose.ui:ui-tooling-preview-android:1.7.4
androidx.compose.ui:ui-tooling-preview:1.7.4
androidx.compose.ui:ui-unit-android:1.7.4
androidx.compose.ui:ui-unit:1.7.4
androidx.compose.ui:ui-util-android:1.7.4
androidx.compose.ui:ui-util:1.7.4
androidx.compose.ui:ui:1.7.4
androidx.collection:collection-jvm:1.5.0
androidx.collection:collection-ktx:1.5.0
androidx.collection:collection:1.5.0
androidx.compose.animation:animation-android:1.8.0
androidx.compose.animation:animation-core-android:1.8.0
androidx.compose.animation:animation-core:1.8.0
androidx.compose.animation:animation:1.8.0
androidx.compose.foundation:foundation-android:1.8.0
androidx.compose.foundation:foundation-layout-android:1.8.0
androidx.compose.foundation:foundation-layout:1.8.0
androidx.compose.foundation:foundation:1.8.0
androidx.compose.material3.adaptive:adaptive-android:1.1.0
androidx.compose.material3.adaptive:adaptive-layout-android:1.1.0
androidx.compose.material3.adaptive:adaptive-layout:1.1.0
androidx.compose.material3.adaptive:adaptive:1.1.0
androidx.compose.material3:material3-adaptive-navigation-suite-android:1.3.2
androidx.compose.material3:material3-adaptive-navigation-suite:1.3.2
androidx.compose.material3:material3-android:1.3.2
androidx.compose.material3:material3:1.3.2
androidx.compose.material:material-android:1.8.0
androidx.compose.material:material-icons-core-android:1.7.6
androidx.compose.material:material-icons-core:1.7.6
androidx.compose.material:material-icons-extended-android:1.7.6
androidx.compose.material:material-icons-extended:1.7.6
androidx.compose.material:material-ripple-android:1.8.0
androidx.compose.material:material-ripple:1.8.0
androidx.compose.material:material:1.8.0
androidx.compose.runtime:runtime-android:1.8.1
androidx.compose.runtime:runtime-saveable-android:1.8.1
androidx.compose.runtime:runtime-saveable:1.8.1
androidx.compose.runtime:runtime:1.8.1
androidx.compose.ui:ui-android:1.8.1
androidx.compose.ui:ui-geometry-android:1.8.1
androidx.compose.ui:ui-geometry:1.8.1
androidx.compose.ui:ui-graphics-android:1.8.1
androidx.compose.ui:ui-graphics:1.8.1
androidx.compose.ui:ui-text-android:1.8.1
androidx.compose.ui:ui-text:1.8.1
androidx.compose.ui:ui-tooling-preview-android:1.8.1
androidx.compose.ui:ui-tooling-preview:1.8.1
androidx.compose.ui:ui-unit-android:1.8.1
androidx.compose.ui:ui-unit:1.8.1
androidx.compose.ui:ui-util-android:1.8.1
androidx.compose.ui:ui-util:1.8.1
androidx.compose.ui:ui:1.8.1
androidx.concurrent:concurrent-futures:1.1.0
androidx.core:core-ktx:1.13.1
androidx.core:core:1.13.1
androidx.core:core-ktx:1.15.0
androidx.core:core:1.15.0
androidx.customview:customview-poolingcontainer:1.0.0
androidx.emoji2:emoji2:1.3.0
androidx.exifinterface:exifinterface:1.3.7
androidx.emoji2:emoji2:1.4.0
androidx.exifinterface:exifinterface:1.4.1
androidx.graphics:graphics-path:1.0.1
androidx.interpolator:interpolator:1.0.0
androidx.lifecycle:lifecycle-common-java8:2.8.6
androidx.lifecycle:lifecycle-common-jvm:2.8.6
androidx.lifecycle:lifecycle-common:2.8.6
androidx.lifecycle:lifecycle-livedata-core:2.8.6
androidx.lifecycle:lifecycle-process:2.8.6
androidx.lifecycle:lifecycle-runtime-android:2.8.6
androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6
androidx.lifecycle:lifecycle-runtime-compose:2.8.6
androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.6
androidx.lifecycle:lifecycle-runtime-ktx:2.8.6
androidx.lifecycle:lifecycle-runtime:2.8.6
androidx.lifecycle:lifecycle-viewmodel-android:2.8.6
androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6
androidx.lifecycle:lifecycle-viewmodel:2.8.6
androidx.lifecycle:lifecycle-common-java8:2.8.7
androidx.lifecycle:lifecycle-common-jvm:2.8.7
androidx.lifecycle:lifecycle-common:2.8.7
androidx.lifecycle:lifecycle-livedata-core:2.8.7
androidx.lifecycle:lifecycle-process:2.8.7
androidx.lifecycle:lifecycle-runtime-android:2.8.7
androidx.lifecycle:lifecycle-runtime-compose-android:2.8.7
androidx.lifecycle:lifecycle-runtime-compose:2.8.7
androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.7
androidx.lifecycle:lifecycle-runtime-ktx:2.8.7
androidx.lifecycle:lifecycle-runtime:2.8.7
androidx.lifecycle:lifecycle-viewmodel-android:2.8.7
androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7
androidx.lifecycle:lifecycle-viewmodel:2.8.7
androidx.profileinstaller:profileinstaller:1.4.1
androidx.savedstate:savedstate-ktx:1.2.1
androidx.savedstate:savedstate:1.2.1
androidx.startup:startup-runtime:1.1.1
androidx.tracing:tracing:1.0.0
androidx.tracing:tracing:1.2.0
androidx.vectordrawable:vectordrawable-animated:1.1.0
androidx.vectordrawable:vectordrawable:1.1.0
androidx.versionedparcelable:versionedparcelable:1.1.1
@ -88,50 +88,51 @@ androidx.window.extensions.core:core:1.0.0
androidx.window:window-core-android:1.3.0
androidx.window:window-core:1.3.0
androidx.window:window:1.3.0
com.google.accompanist:accompanist-drawablepainter:0.36.0
com.google.accompanist:accompanist-drawablepainter:0.37.3
com.google.guava:listenablefuture:1.0
com.squareup.okio:okio-jvm:3.9.1
com.squareup.okio:okio:3.9.1
io.coil-kt.coil3:coil-compose-core-android:3.0.0-rc02
io.coil-kt.coil3:coil-compose-core:3.0.0-rc02
io.coil-kt.coil3:coil-core-android:3.0.0-rc02
io.coil-kt.coil3:coil-core:3.0.0-rc02
org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3
org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.3
org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.3
org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.3
org.jetbrains.androidx.window:window-core:1.3.0
org.jetbrains.compose.animation:animation-core:1.7.0
org.jetbrains.compose.animation:animation:1.7.0
org.jetbrains.compose.annotation-internal:annotation:1.7.0
org.jetbrains.compose.collection-internal:collection:1.7.0
org.jetbrains.compose.components:components-resources-android:1.7.0
org.jetbrains.compose.components:components-resources:1.7.0
org.jetbrains.compose.components:components-ui-tooling-preview-android:1.7.0
org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0
org.jetbrains.compose.foundation:foundation-layout:1.7.0
org.jetbrains.compose.foundation:foundation:1.7.0
org.jetbrains.compose.material3.adaptive:adaptive-layout:1.0.0-alpha03
org.jetbrains.compose.material3.adaptive:adaptive:1.0.0
org.jetbrains.compose.material3:material3-adaptive-navigation-suite:1.7.0
org.jetbrains.compose.material3:material3:1.7.0
org.jetbrains.compose.material:material-icons-core:1.7.0
org.jetbrains.compose.material:material-icons-extended:1.7.0
org.jetbrains.compose.material:material-ripple:1.7.0
org.jetbrains.compose.material:material:1.7.0
org.jetbrains.compose.runtime:runtime-saveable:1.7.0
org.jetbrains.compose.runtime:runtime:1.7.0
org.jetbrains.compose.ui:ui-geometry:1.7.0
org.jetbrains.compose.ui:ui-graphics:1.7.0
org.jetbrains.compose.ui:ui-text:1.7.0
org.jetbrains.compose.ui:ui-unit:1.7.0
org.jetbrains.compose.ui:ui-util:1.7.0
org.jetbrains.compose.ui:ui:1.7.0
org.jetbrains.kotlin:kotlin-stdlib:2.0.21
org.jetbrains.kotlinx:atomicfu-jvm:0.23.2
org.jetbrains.kotlinx:atomicfu:0.23.2
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0
com.squareup.okio:okio-jvm:3.11.0
com.squareup.okio:okio:3.11.0
io.coil-kt.coil3:coil-compose-core-android:3.2.0
io.coil-kt.coil3:coil-compose-core:3.2.0
io.coil-kt.coil3:coil-core-android:3.2.0
io.coil-kt.coil3:coil-core:3.2.0
org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.4
org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.4
org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.4
org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.4
org.jetbrains.androidx.window:window-core:1.3.1
org.jetbrains.compose.animation:animation-core:1.8.0
org.jetbrains.compose.animation:animation:1.8.0
org.jetbrains.compose.annotation-internal:annotation:1.8.0
org.jetbrains.compose.collection-internal:collection:1.8.0
org.jetbrains.compose.components:components-resources-android:1.8.0
org.jetbrains.compose.components:components-resources:1.8.0
org.jetbrains.compose.components:components-ui-tooling-preview-android:1.8.0
org.jetbrains.compose.components:components-ui-tooling-preview:1.8.0
org.jetbrains.compose.foundation:foundation-layout:1.8.0
org.jetbrains.compose.foundation:foundation:1.8.0
org.jetbrains.compose.material3.adaptive:adaptive-layout:1.1.0
org.jetbrains.compose.material3.adaptive:adaptive:1.1.0
org.jetbrains.compose.material3:material3-adaptive-navigation-suite:1.8.0
org.jetbrains.compose.material3:material3:1.8.0
org.jetbrains.compose.material:material-icons-core:1.7.3
org.jetbrains.compose.material:material-icons-extended:1.7.3
org.jetbrains.compose.material:material-ripple:1.8.0
org.jetbrains.compose.material:material:1.8.0
org.jetbrains.compose.runtime:runtime-saveable:1.8.0
org.jetbrains.compose.runtime:runtime:1.8.0
org.jetbrains.compose.ui:ui-backhandler-android:1.8.0
org.jetbrains.compose.ui:ui-backhandler:1.8.0
org.jetbrains.compose.ui:ui-geometry:1.8.0
org.jetbrains.compose.ui:ui-graphics:1.8.0
org.jetbrains.compose.ui:ui-text:1.8.0
org.jetbrains.compose.ui:ui-unit:1.8.0
org.jetbrains.compose.ui:ui-util:1.8.0
org.jetbrains.compose.ui:ui:1.8.0
org.jetbrains.kotlin:kotlin-stdlib:2.1.20
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
org.jetbrains:annotations:23.0.0
org.jspecify:jspecify:1.0.0

@ -114,19 +114,24 @@ kotlin {
commonTest.dependencies {
implementation(projects.core.dataTest)
implementation(projects.core.testing)
implementation(projects.core.screenshotTesting)
// implementation(projects.sync.syncTest)
implementation(libs.kotlin.test)
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.uiTest)
}
androidUnitTest.dependencies {
implementation(projects.core.screenshotTesting)
}
androidInstrumentedTest.dependencies {
implementation(projects.core.dataTest)
implementation(projects.core.testing)
implementation(libs.androidx.navigation.testing)
implementation(project.dependencies.platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui.test)
implementation(libs.androidx.test.espresso.core)
implementation(libs.koin.test)
}
jvmMain.dependencies {

@ -1,12 +1,10 @@
package: name='com.google.samples.apps.nowinandroid' versionCode='8' versionName='0.1.2' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15'
sdkVersion:'21'
targetSdkVersion:'35'
minSdkVersion:'21'
targetSdkVersion:'34'
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
uses-permission: name='android.permission.POST_NOTIFICATIONS'
uses-permission: name='android.permission.WAKE_LOCK'
uses-permission: name='com.google.android.c2dm.permission.RECEIVE'
uses-permission: name='com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE'
uses-permission: name='android.permission.RECEIVE_BOOT_COMPLETED'
uses-permission: name='android.permission.FOREGROUND_SERVICE'
uses-permission: name='com.google.samples.apps.nowinandroid.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION'
@ -105,14 +103,12 @@ application-icon-640:'res/mipmap-anydpi-v26/ic_launcher.xml'
application-icon-65534:'res/mipmap-anydpi-v26/ic_launcher.xml'
application: label='Now in Android' icon='res/mipmap-anydpi-v26/ic_launcher.xml'
launchable-activity: name='com.google.samples.apps.nowinandroid.MainActivity' label='' icon=''
uses-library-not-required:'android.ext.adservices'
uses-library-not-required:'androidx.window.extensions'
uses-library-not-required:'androidx.window.sidecar'
feature-group: label=''
uses-feature: name='android.hardware.faketouch'
uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
main
other-activities
other-receivers
other-services
supports-screens: 'small' 'normal' 'large' 'xlarge'

@ -34,6 +34,7 @@ import androidx.compose.ui.test.performScrollToNode
import androidx.test.espresso.Espresso
import androidx.test.espresso.NoActivityResumedException
import com.google.samples.apps.nowinandroid.MainActivity
import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.rules.GrantPostNotificationsPermissionRule
@ -50,7 +51,8 @@ import nowinandroid.shared.generated.resources.Res
import nowinandroid.shared.generated.resources.app_name
import org.junit.Rule
import org.junit.Test
import javax.inject.Inject
import org.koin.test.KoinTest
import org.koin.test.inject
import nowinandroid.feature.bookmarks.generated.resources.Res as BookmarksR
import nowinandroid.feature.foryou.generated.resources.Res as FeatureForyouR
import nowinandroid.feature.search.generated.resources.Res as FeatureSearchR
@ -58,13 +60,7 @@ import nowinandroid.feature.settings.generated.resources.Res as SettingsR
/**
* Tests all the navigation flows that are handled by the navigation library.
*/
class NavigationTest {
/**
* Manages the components' state and is used to perform injection on your test
*/
// @get:Rule(order = 0)
// val hiltRule = HiltAndroidRule(this)
class NavigationTest : KoinTest {
/**
* Grant [android.Manifest.permission.POST_NOTIFICATIONS] permission.
@ -78,11 +74,8 @@ class NavigationTest {
@get:Rule(order = 2)
val composeTestRule = createAndroidComposeRule<MainActivity>()
@Inject
lateinit var topicsRepository: TopicsRepository
@Inject
lateinit var newsRepository: NewsRepository
private val topicsRepository: TopicsRepository by inject()
private val newsRepository: NewsRepository by inject()
// The strings used for matching in these tests
private val navigateUp by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_navigate_up)
@ -95,9 +88,6 @@ class NavigationTest {
private val brand by composeTestRule.stringResource(SettingsR.string.feature_settings_brand_android)
private val ok by composeTestRule.stringResource(SettingsR.string.feature_settings_dismiss_dialog_button_text)
// @Before
// fun setup() = hiltRule.inject()
@Test
fun firstScreen_isForYou() {
composeTestRule.apply {

@ -27,22 +27,23 @@ import com.google.samples.apps.nowinandroid.util.ProfileVerifierLogger
import org.koin.android.ext.android.inject
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.androix.startup.KoinStartup.onKoinStartup
import org.koin.androix.startup.KoinStartup
import org.koin.core.annotation.KoinExperimentalAPI
import org.koin.dsl.koinConfiguration
/**
* [Application] class for NiA
*/
class NiaApplication : Application(), SingletonImageLoader.Factory {
@OptIn(KoinExperimentalAPI::class)
class NiaApplication : Application(), SingletonImageLoader.Factory, KoinStartup {
init {
onKoinStartup {
androidContext(this@NiaApplication)
androidLogger()
modules(
jankStatsModule,
appModules,
)
}
override fun onKoinStartup() = koinConfiguration {
androidContext(this@NiaApplication)
androidLogger()
modules(
jankStatsModule,
appModules,
)
}
private val profileVerifierLogger: ProfileVerifierLogger by inject()

@ -54,7 +54,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavDestination.Companion.hierarchy
@ -65,6 +64,7 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopAp
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.LocalGradientColors
import com.google.samples.apps.nowinandroid.core.ui.collectAsStateWithLifecycle
import com.google.samples.apps.nowinandroid.feature.settings.SettingsDialog
import com.google.samples.apps.nowinandroid.navigation.NiaNavHost
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination

@ -25,7 +25,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.util.trace
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions
@ -33,6 +32,7 @@ import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourc
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.feature.bookmarks.navigation.navigateToBookmarks
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouBaseRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.navigateToForYou
import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests
import com.google.samples.apps.nowinandroid.feature.search.navigation.navigateToSearch
@ -156,7 +156,7 @@ class NiaAppState(
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id) {
popUpTo<ForYouBaseRoute> {
saveState = true
}
// Avoid multiple copies of the same destination when

@ -32,20 +32,22 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.google.samples.apps.nowinandroid.core.ui.collectAsStateWithLifecycle
import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.topic.TopicDetailPlaceholder
import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicRoute
import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic
import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import org.koin.compose.viewmodel.koinViewModel
import kotlin.uuid.ExperimentalUuidApi
@ -99,6 +101,8 @@ internal fun InterestsListDetailScreen(
// listDetailNavigator.navigateBack()
// }
val coroutineScope = rememberCoroutineScope()
var nestedNavHostStartRoute by remember {
val route = selectedTopicId?.let { TopicRoute(id = it) } ?: TopicPlaceholderRoute
mutableStateOf(route)
@ -125,7 +129,9 @@ internal fun InterestsListDetailScreen(
nestedNavHostStartRoute = TopicRoute(id = topicId)
nestedNavKey = Uuid.random()
}
listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
coroutineScope.launch {
listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
}
}
ListDetailPaneScaffold(
@ -149,7 +155,11 @@ internal fun InterestsListDetailScreen(
) {
topicScreen(
showBackButton = !listDetailNavigator.isListPaneVisible(),
onBackClick = listDetailNavigator::navigateBack,
onBackClick = {
coroutineScope.launch {
listDetailNavigator.navigateBack()
}
},
onTopicClick = ::onTopicClickShowDetailPane,
)
composable<TopicPlaceholderRoute> {

@ -22,11 +22,14 @@ import com.google.samples.apps.nowinandroid.configureGradleManagedDevices
import com.google.samples.apps.nowinandroid.configureKotlinAndroid
import com.google.samples.apps.nowinandroid.configurePrintApksTask
import com.google.samples.apps.nowinandroid.libs
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
@ -87,7 +90,11 @@ private fun Project.configureComposeMultiplatformApp() {
}
// Add JVM target for desktop
jvm()
jvm {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
// Configure iOS targets
listOf(
@ -118,8 +125,19 @@ private fun Project.configureComposeMultiplatformApp() {
// Fixes Cannot locate tasks that match ':core:model:testClasses' as task 'testClasses'
// not found in project ':core:model'. Some candidates are: 'jsTestClasses', 'jvmTestClasses'.
project.tasks.create("testClasses") {
project.tasks.register("testClasses") {
dependsOn("allTests")
}
}
// Set Java compilation compatibility for JVM target to match Kotlin JVM target (11).
// Only apply --release to non-Android Java tasks, since AGP manages bootclasspath itself.
project.tasks.withType<JavaCompile>().configureEach {
sourceCompatibility = JavaVersion.VERSION_11.toString()
targetCompatibility = JavaVersion.VERSION_11.toString()
// Android tasks are named like "compileDebugJavaWithJavac"; KMP JVM tasks like "compileJvmMainJava"
if (!name.endsWith("JavaWithJavac")) {
options.release.set(11)
}
}
}

@ -39,6 +39,7 @@ class CmpFeatureConventionPlugin : Plugin<Project> {
"com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner"
}
testOptions.animationsDisabled = true
testOptions.unitTests.isIncludeAndroidResources = true
configureGradleManagedDevices(this)
}

@ -31,13 +31,14 @@ internal fun configureGradleManagedDevices(
val pixel6 = DeviceConfig("Pixel 6", 31, "aosp")
val pixelC = DeviceConfig("Pixel C", 30, "aosp-atd")
val allDevices = listOf(pixel4, pixel6, pixelC)
val ciDevices = listOf(pixel4, pixelC)
val deviceConfigs = listOf(pixel4, pixel6, pixelC)
val ciDeviceConfigs = listOf(pixel4, pixelC)
commonExtension.testOptions {
managedDevices {
@Suppress("DEPRECATION")
devices {
allDevices.forEach { deviceConfig ->
deviceConfigs.forEach { deviceConfig ->
maybeCreate(deviceConfig.taskName, ManagedVirtualDevice::class.java).apply {
device = deviceConfig.device
apiLevel = deviceConfig.apiLevel
@ -47,7 +48,8 @@ internal fun configureGradleManagedDevices(
}
groups {
maybeCreate("ci").apply {
ciDevices.forEach { deviceConfig ->
ciDeviceConfigs.forEach { deviceConfig ->
@Suppress("DEPRECATION")
targetDevices.add(devices[deviceConfig.taskName])
}
}

@ -29,7 +29,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/**

@ -16,10 +16,13 @@
package com.google.samples.apps.nowinandroid
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@ -35,7 +38,11 @@ internal fun Project.configureKotlinMultiplatform() {
// https://kotlinlang.org/docs/whatsnew1820.html#new-approach-to-source-set-hierarchy
applyDefaultHierarchyTemplate()
jvm()
jvm {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
androidTarget()
// SqlDelight does not support wasm yet
// https://github.com/cashapp/sqldelight/pull/4965/files
@ -101,8 +108,19 @@ internal fun Project.configureKotlinMultiplatform() {
// Fixes Cannot locate tasks that match ':core:model:testClasses' as task 'testClasses'
// not found in project ':core:model'. Some candidates are: 'jsTestClasses', 'jvmTestClasses'.
project.tasks.create("testClasses") {
project.tasks.register("testClasses") {
dependsOn("allTests")
}
}
// Set Java compilation compatibility for JVM target to match Kotlin JVM target (11).
// Only apply --release to non-Android Java tasks, since AGP manages bootclasspath itself.
project.tasks.withType<JavaCompile>().configureEach {
sourceCompatibility = JavaVersion.VERSION_11.toString()
targetCompatibility = JavaVersion.VERSION_11.toString()
// Android tasks are named like "compileDebugJavaWithJavac"; KMP JVM tasks like "compileJvmMainJava"
if (!name.endsWith("JavaWithJavac")) {
options.release.set(11)
}
}
}

@ -36,7 +36,7 @@ android {
kotlin {
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
moduleName = "composeApp"
outputModuleName.set("composeApp")
browser {
commonWebpackConfig {
outputFileName = "composeApp.js"

@ -25,7 +25,6 @@ import androidx.compose.ui.unit.dp
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.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -36,7 +35,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class BackgroundScreenshotTests {

@ -25,7 +25,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaButto
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaOutlinedButton
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -36,7 +35,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class ButtonScreenshotTests {

@ -35,7 +35,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilte
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -46,7 +45,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class FilterChipScreenshotTests {

@ -24,7 +24,6 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -35,7 +34,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class IconButtonScreenshotTests {

@ -26,7 +26,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaOverl
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -37,7 +36,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class LoadingWheelScreenshotTests {

@ -34,7 +34,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -45,7 +44,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class NavigationScreenshotTests {

@ -32,7 +32,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTabRo
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -43,7 +42,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class TabsScreenshotTests {

@ -29,7 +29,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopic
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -40,7 +39,7 @@ import org.robolectric.annotation.LooperMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class TagScreenshotTests {

@ -31,7 +31,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions
import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiTheme
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -43,7 +42,7 @@ import org.robolectric.annotation.LooperMode
@OptIn(ExperimentalMaterial3Api::class)
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(application = HiltTestApplication::class, qualifiers = "480dpi")
@Config(qualifiers = "480dpi")
@LooperMode(LooperMode.Mode.PAUSED)
class TopAppBarScreenshotTests {

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save