diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml
index 0ca4d7536..8679fef93 100644
--- a/.github/workflows/Build.yaml
+++ b/.github/workflows/Build.yaml
@@ -1,6 +1,7 @@
name: Build
on:
+ workflow_dispatch:
push:
branches:
- main
@@ -29,16 +30,19 @@ jobs:
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'zulu'
- java-version: 17
+ java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
+ build-scan-publish: true
+ build-scan-terms-of-use-url: "https://gradle.com/terms-of-service"
+ build-scan-terms-of-use-agree: "yes"
- name: Check build-logic
run: ./gradlew :build-logic:convention:check
@@ -73,6 +77,28 @@ jobs:
disable_globbing: true
commit_message: "🤖 Updates baselines for Dependency Guard"
+ - name: Update Graphs
+ run: ./gradlew graphUpdate
+
+ - name: Check Graphs
+ id: graphs_verify
+ run: git add -- '**/README.md' && git diff --cached --quiet --exit-code -- '**/README.md'
+
+ - name: Prevent updating graphs if this is a fork
+ id: checkfork_graphs
+ continue-on-error: false
+ if: steps.graphs_verify.outcome == 'failure' && github.event.pull_request.head.repo.full_name != github.repository
+ run: |
+ echo "::error::Check Graphs failed, please update graphs with: ./gradlew graphUpdate" && exit 1
+
+ - name: Push new graphs if available
+ if: steps.graphs_verify.outcome == 'failure' && github.event_name == 'pull_request'
+ uses: stefanzweifel/git-auto-commit-action@v5
+ with:
+ file_pattern: '**/README.md'
+ disable_globbing: true
+ commit_message: "🤖 Updates graphs"
+
- name: Run all local screenshot tests (Roborazzi)
id: screenshotsverify
continue-on-error: true
@@ -107,7 +133,7 @@ jobs:
run: ./gradlew testDemoDebug :lint:test
- name: Build all build type and flavor permutations
- run: ./gradlew :app:assemble
+ run: ./gradlew :app:assemble -PminifyWithR8=false
- name: Upload build outputs (APKs)
uses: actions/upload-artifact@v4
@@ -139,11 +165,26 @@ jobs:
name: lint-reports
path: '**/build/reports/lint-results-*.html'
- - name: Upload lint reports (SARIF)
- if: ${{ !cancelled() && hashFiles('**/*.sarif') != '' }}
+ - name: Upload lint reports (SARIF) for app module
+ if: ${{ !cancelled() && hashFiles('app/**/*.sarif') != '' }}
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: './app/'
+ category: app
+
+ - name: Upload lint reports (SARIF) for app-nia-catalog module
+ if: ${{ !cancelled() && hashFiles('app-nia-catalog/**/*.sarif') != '' }}
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: './app-nia-catalog/'
+ category: app-nia-catalog
+
+ - name: Upload lint reports (SARIF) for lint module
+ if: ${{ !cancelled() && hashFiles('lint/**/*.sarif') != '' }}
uses: github/codeql-action/upload-sarif@v3
with:
- sarif_file: './'
+ sarif_file: './lint/'
+ category: lint
- name: Check badging
run: ./gradlew :app:checkProdReleaseBadging
@@ -180,16 +221,19 @@ jobs:
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'zulu'
- java-version: 17
+ java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
+ build-scan-publish: true
+ build-scan-terms-of-use-url: "https://gradle.com/terms-of-service"
+ build-scan-terms-of-use-agree: "yes"
- name: AVD cache
uses: actions/cache@v4
diff --git a/.github/workflows/NightlyBaselineProfiles.yaml b/.github/workflows/NightlyBaselineProfiles.yaml
index 6e7354476..43d4b73fa 100644
--- a/.github/workflows/NightlyBaselineProfiles.yaml
+++ b/.github/workflows/NightlyBaselineProfiles.yaml
@@ -1,6 +1,7 @@
name: NightlyBaselineProfiles
on:
+ workflow_dispatch:
schedule:
- cron: '42 4 * * *'
@@ -39,6 +40,9 @@ jobs:
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
+ build-scan-publish: true
+ build-scan-terms-of-use-url: "https://gradle.com/terms-of-service"
+ build-scan-terms-of-use-agree: "yes"
- name: Setup Android SDK
uses: android-actions/setup-android@v3
diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml
index b952ccb50..4c764a51d 100644
--- a/.github/workflows/Release.yml
+++ b/.github/workflows/Release.yml
@@ -1,6 +1,7 @@
name: GitHub Release with APKs
on:
+ workflow_dispatch:
push:
tags:
- 'v*'
@@ -36,6 +37,9 @@ jobs:
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
+ build-scan-publish: true
+ build-scan-terms-of-use-url: "https://gradle.com/terms-of-service"
+ build-scan-terms-of-use-agree: "yes"
- name: Setup Android SDK
uses: android-actions/setup-android@v3
@@ -75,4 +79,4 @@ jobs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: app/build/outputs/apk/demo/release/app-demo-release.apk
asset_name: app-demo-release.apk
- asset_content_type: application/vnd.android.package-archive
+ asset_content_type: application/vnd.android.package-archive
diff --git a/AGENT.md b/AGENT.md
new file mode 120000
index 000000000..47dc3e3d8
--- /dev/null
+++ b/AGENT.md
@@ -0,0 +1 @@
+AGENTS.md
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 000000000..efb39ef19
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,58 @@
+# Now in Android Project
+
+Now in Android is a native Android mobile application written in Kotlin. It provides regular news
+about Android development. Users can choose to follow topics, be notified when new content is
+available, and bookmark items.
+
+## Architecture
+
+This project is a modern Android application that follows the official architecture guidance from Google. It is a reactive, single-activity app that uses the following:
+
+- **UI:** Built entirely with Jetpack Compose, including Material 3 components and adaptive layouts for different screen sizes.
+- **State Management:** Unidirectional Data Flow (UDF) is implemented using Kotlin Coroutines and `Flow`s. `ViewModel`s act as state holders, exposing UI state as streams of data.
+- **Dependency Injection:** Hilt is used for dependency injection throughout the app, simplifying the management of dependencies and improving testability.
+- **Navigation:** Navigation is handled by Jetpack Navigation 2 for Compose, allowing for a declarative and type-safe way to navigate between screens.
+- **Data:** The data layer is implemented using the repository pattern.
+ - **Local Data:** Room and DataStore are used for local data persistence.
+ - **Remote Data:** Retrofit and OkHttp are used for fetching data from the network.
+- **Background Processing:** WorkManager is used for deferrable background tasks.
+
+## Modules
+
+The main Android app lives in the `app/` folder. Feature modules live in `feature/` and core and shared modules in `core/`.
+
+## Commands to Build & Test
+
+The app and Android libraries have two product flavors: `demo` and `prod`, and two build types: `debug` and `release`.
+
+- Build: `./gradlew assemble{Variant}`. Typically `assembleDemoDebug`.
+- Fix linting/formatting: `./gradlew --init-script gradle/init.gradle.kts spotlessApply`
+- Run local tests: `./gradlew {variant}Test`
+- Run single test: `./gradlew {variant}Test --tests "com.example.myapp.MyTestClass"`
+- Run local screenshot tests: `./gradlew verifyRoborazziDemoDebug`
+
+### Instrumented tests
+
+- Gradle-managed devices to run on device tests: `./gradlew pixel6api31aospDebugAndroidTest`. Also `pixel4api30aospatdDebugAndroidTest` and `pixelcapi30aospatdDebugAndroidTest`.
+
+### Creating tests
+
+#### Instrumented tests
+
+- Tests for UI features should only use `ComposeTestRule` with a `ComponentActivity`.
+- Bigger tests live in the `:app` module and they can start activities like `MainActivity`.
+
+#### Local tests
+
+- [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) for most assertions
+- [cashapp/turbine](https://github.com/cashapp/turbine) for complex coroutine tests
+- [google/truth](https://github.com/google/truth) for assertions
+
+## Continuous integration
+
+- The workflows are defined in `.github/workflows/*.yaml` and they contain various checks.
+- Screenshot tests are generated by CI, so they shouldn't be checked into the repo from a workstation.
+
+## Version control and code location
+
+- The project uses git and is hosted in https://github.com/android/nowinandroid.
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 000000000..db0882010
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1 @@
+* @dturner
diff --git a/app-nia-catalog/README.md b/app-nia-catalog/README.md
index cf6d05f4f..8fd8dcb8d 100644
--- a/app-nia-catalog/README.md
+++ b/app-nia-catalog/README.md
@@ -1,3 +1,58 @@
-# :app-nia-catalog module
-## Dependency graph
-
+# `:app-nia-catalog`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:model[model]:::jvm-library
+ :core:ui[ui]:::android-library
+ end
+ :app-nia-catalog[app-nia-catalog]:::android-application
+
+ :app-nia-catalog -.-> :core:designsystem
+ :app-nia-catalog -.-> :core:ui
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt
index 04a864e86..5606bcd1d 100644
--- a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt
+++ b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt
@@ -1,7 +1,7 @@
androidx.activity:activity-compose:1.9.3
androidx.activity:activity-ktx:1.9.3
androidx.activity:activity:1.9.3
-androidx.annotation:annotation-experimental:1.4.1
+androidx.annotation:annotation-experimental:1.5.1
androidx.annotation:annotation-jvm:1.9.1
androidx.annotation:annotation:1.9.1
androidx.appcompat:appcompat-resources:1.6.1
@@ -9,97 +9,111 @@ androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0
androidx.autofill:autofill:1.0.0
androidx.browser:browser:1.8.0
-androidx.collection:collection-jvm:1.5.0-beta01
-androidx.collection:collection-ktx:1.5.0-beta01
-androidx.collection:collection:1.5.0-beta01
-androidx.compose.animation:animation-android:1.8.0-alpha07
-androidx.compose.animation:animation-core-android:1.8.0-alpha07
-androidx.compose.animation:animation-core:1.8.0-alpha07
-androidx.compose.animation:animation:1.8.0-alpha07
-androidx.compose.foundation:foundation-android:1.8.0-alpha07
-androidx.compose.foundation:foundation-layout-android:1.8.0-alpha07
-androidx.compose.foundation:foundation-layout:1.8.0-alpha07
-androidx.compose.foundation:foundation:1.8.0-alpha07
-androidx.compose.material3.adaptive:adaptive-android:1.0.0
-androidx.compose.material3.adaptive:adaptive:1.0.0
-androidx.compose.material3:material3-adaptive-navigation-suite-android:1.3.1
-androidx.compose.material3:material3-adaptive-navigation-suite:1.3.1
-androidx.compose.material3:material3-android:1.3.1
-androidx.compose.material3:material3:1.3.1
-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.7.6
-androidx.compose.material:material-ripple:1.7.6
-androidx.compose.runtime:runtime-android:1.8.0-alpha07
-androidx.compose.runtime:runtime-saveable-android:1.8.0-alpha07
-androidx.compose.runtime:runtime-saveable:1.8.0-alpha07
-androidx.compose.runtime:runtime:1.8.0-alpha07
-androidx.compose.ui:ui-android:1.8.0-alpha07
-androidx.compose.ui:ui-geometry-android:1.8.0-alpha07
-androidx.compose.ui:ui-geometry:1.8.0-alpha07
-androidx.compose.ui:ui-graphics-android:1.8.0-alpha07
-androidx.compose.ui:ui-graphics:1.8.0-alpha07
-androidx.compose.ui:ui-text-android:1.8.0-alpha07
-androidx.compose.ui:ui-text:1.8.0-alpha07
-androidx.compose.ui:ui-tooling-preview-android:1.8.0-alpha07
-androidx.compose.ui:ui-tooling-preview:1.8.0-alpha07
-androidx.compose.ui:ui-unit-android:1.8.0-alpha07
-androidx.compose.ui:ui-unit:1.8.0-alpha07
-androidx.compose.ui:ui-util-android:1.8.0-alpha07
-androidx.compose.ui:ui-util:1.8.0-alpha07
-androidx.compose.ui:ui:1.8.0-alpha07
-androidx.compose:compose-bom:2024.12.01
+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.10.0-alpha02
+androidx.compose.animation:animation-core-android:1.10.0-alpha02
+androidx.compose.animation:animation-core:1.10.0-alpha02
+androidx.compose.animation:animation:1.10.0-alpha02
+androidx.compose.foundation:foundation-android:1.10.0-alpha02
+androidx.compose.foundation:foundation-layout-android:1.10.0-alpha02
+androidx.compose.foundation:foundation-layout:1.10.0-alpha02
+androidx.compose.foundation:foundation:1.10.0-alpha02
+androidx.compose.material3.adaptive:adaptive-android:1.2.0-beta01
+androidx.compose.material3.adaptive:adaptive:1.2.0-beta01
+androidx.compose.material3:material3-adaptive-navigation-suite-android:1.5.0-alpha03
+androidx.compose.material3:material3-adaptive-navigation-suite:1.5.0-alpha03
+androidx.compose.material3:material3-android:1.5.0-alpha03
+androidx.compose.material3:material3:1.5.0-alpha03
+androidx.compose.material:material-icons-core-android:1.7.8
+androidx.compose.material:material-icons-core:1.7.8
+androidx.compose.material:material-icons-extended-android:1.7.8
+androidx.compose.material:material-icons-extended:1.7.8
+androidx.compose.material:material-ripple-android:1.10.0-alpha02
+androidx.compose.material:material-ripple:1.10.0-alpha02
+androidx.compose.runtime:runtime-android:1.10.0-alpha02
+androidx.compose.runtime:runtime-annotation-android:1.10.0-alpha02
+androidx.compose.runtime:runtime-annotation:1.10.0-alpha02
+androidx.compose.runtime:runtime-saveable-android:1.10.0-alpha02
+androidx.compose.runtime:runtime-saveable:1.10.0-alpha02
+androidx.compose.runtime:runtime:1.10.0-alpha02
+androidx.compose.ui:ui-android:1.10.0-alpha02
+androidx.compose.ui:ui-geometry-android:1.10.0-alpha02
+androidx.compose.ui:ui-geometry:1.10.0-alpha02
+androidx.compose.ui:ui-graphics-android:1.10.0-alpha02
+androidx.compose.ui:ui-graphics:1.10.0-alpha02
+androidx.compose.ui:ui-text-android:1.10.0-alpha02
+androidx.compose.ui:ui-text:1.10.0-alpha02
+androidx.compose.ui:ui-tooling-preview-android:1.10.0-alpha02
+androidx.compose.ui:ui-tooling-preview:1.10.0-alpha02
+androidx.compose.ui:ui-unit-android:1.10.0-alpha02
+androidx.compose.ui:ui-unit:1.10.0-alpha02
+androidx.compose.ui:ui-util-android:1.10.0-alpha02
+androidx.compose.ui:ui-util:1.10.0-alpha02
+androidx.compose.ui:ui:1.10.0-alpha02
+androidx.compose:compose-bom-alpha:2025.08.01
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.16.0
+androidx.core:core-viewtree:1.0.0
+androidx.core:core:1.16.0
androidx.customview:customview-poolingcontainer:1.0.0
androidx.customview:customview:1.0.0
+androidx.documentfile:documentfile:1.0.0
+androidx.dynamicanimation:dynamicanimation:1.0.0
androidx.emoji2:emoji2:1.4.0
androidx.exifinterface:exifinterface:1.3.7
androidx.fragment:fragment:1.5.1
androidx.graphics:graphics-path:1.0.1
+androidx.graphics:graphics-shapes-android:1.0.1
+androidx.graphics:graphics-shapes:1.0.1
androidx.interpolator:interpolator:1.0.0
-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-ktx:2.8.7
-androidx.lifecycle:lifecycle-livedata-core:2.8.7
-androidx.lifecycle:lifecycle-livedata: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.legacy:legacy-support-core-utils:1.0.0
+androidx.lifecycle:lifecycle-common-java8:2.10.0-alpha03
+androidx.lifecycle:lifecycle-common-jvm:2.10.0-alpha03
+androidx.lifecycle:lifecycle-common:2.10.0-alpha03
+androidx.lifecycle:lifecycle-livedata-core-ktx:2.10.0-alpha03
+androidx.lifecycle:lifecycle-livedata-core:2.10.0-alpha03
+androidx.lifecycle:lifecycle-livedata:2.10.0-alpha03
+androidx.lifecycle:lifecycle-process:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-compose-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-compose:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-ktx-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-ktx:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-ktx:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-savedstate:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel:2.10.0-alpha03
androidx.loader:loader:1.0.0
+androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-beta01
+androidx.print:print:1.0.0
androidx.profileinstaller:profileinstaller:1.4.0
-androidx.savedstate:savedstate-ktx:1.2.1
-androidx.savedstate:savedstate:1.2.1
+androidx.savedstate:savedstate-android:1.4.0-alpha03
+androidx.savedstate:savedstate-compose-android:1.4.0-alpha03
+androidx.savedstate:savedstate-compose:1.4.0-alpha03
+androidx.savedstate:savedstate-ktx:1.4.0-alpha03
+androidx.savedstate:savedstate:1.4.0-alpha03
androidx.startup:startup-runtime:1.1.1
androidx.tracing:tracing-ktx:1.3.0-alpha02
androidx.tracing:tracing:1.3.0-alpha02
+androidx.transition:transition:1.6.0
androidx.vectordrawable:vectordrawable-animated:1.1.0
androidx.vectordrawable:vectordrawable:1.1.0
androidx.versionedparcelable:versionedparcelable:1.1.1
androidx.viewpager:viewpager:1.0.0
-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
+androidx.window:window-core-android:1.4.0
+androidx.window:window-core:1.4.0
+androidx.window:window:1.4.0
com.google.accompanist:accompanist-drawablepainter:0.32.0
com.google.code.findbugs:jsr305:3.0.2
-com.google.dagger:dagger-lint-aar:2.54
-com.google.dagger:dagger:2.54
-com.google.dagger:hilt-android:2.54
-com.google.dagger:hilt-core:2.54
+com.google.dagger:dagger-lint-aar:2.57.2
+com.google.dagger:dagger:2.57.2
+com.google.dagger:hilt-android:2.57.2
+com.google.dagger:hilt-core:2.57.2
com.google.guava:listenablefuture:1.0
com.squareup.okhttp3:okhttp:4.12.0
com.squareup.okio:okio-jvm:3.9.0
@@ -110,15 +124,18 @@ io.coil-kt:coil-compose:2.7.0
io.coil-kt:coil:2.7.0
jakarta.inject:jakarta.inject-api:2.0.1
javax.inject:javax.inject:1
-org.jetbrains.kotlin:kotlin-stdlib-common:2.1.0
+org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0
-org.jetbrains.kotlin:kotlin-stdlib:2.1.0
+org.jetbrains.kotlin:kotlin-stdlib:2.2.21
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1
org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1
org.jetbrains.kotlinx:kotlinx-datetime:0.6.1
+org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.3
+org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.3
+org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3
org.jetbrains:annotations:23.0.0
org.jspecify:jspecify:1.0.0
diff --git a/app/README.md b/app/README.md
index a3fb4572a..3fb136547 100644
--- a/app/README.md
+++ b/app/README.md
@@ -1,3 +1,134 @@
-# :app module
-## Dependency graph
-
+# `:app`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:domain[domain]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:bookmarks[bookmarks]:::android-feature
+ :feature:foryou[foryou]:::android-feature
+ :feature:interests[interests]:::android-feature
+ :feature:search[search]:::android-feature
+ :feature:settings[settings]:::android-feature
+ :feature:topic[topic]:::android-feature
+ end
+ subgraph :sync
+ direction TB
+ :sync:work[work]:::android-library
+ end
+ :benchmarks[benchmarks]:::android-test
+ :app[app]:::android-application
+
+ :app -.->|baselineProfile| :benchmarks
+ :app -.-> :core:analytics
+ :app -.-> :core:common
+ :app -.-> :core:data
+ :app -.-> :core:designsystem
+ :app -.-> :core:model
+ :app -.-> :core:ui
+ :app -.-> :feature:bookmarks
+ :app -.-> :feature:foryou
+ :app -.-> :feature:interests
+ :app -.-> :feature:search
+ :app -.-> :feature:settings
+ :app -.-> :feature:topic
+ :app -.-> :sync:work
+ :benchmarks -.->|testedApks| :app
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:domain --> :core:data
+ :core:domain --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:bookmarks -.-> :core:data
+ :feature:bookmarks -.-> :core:designsystem
+ :feature:bookmarks -.-> :core:ui
+ :feature:foryou -.-> :core:data
+ :feature:foryou -.-> :core:designsystem
+ :feature:foryou -.-> :core:domain
+ :feature:foryou -.-> :core:notifications
+ :feature:foryou -.-> :core:ui
+ :feature:interests -.-> :core:data
+ :feature:interests -.-> :core:designsystem
+ :feature:interests -.-> :core:domain
+ :feature:interests -.-> :core:ui
+ :feature:search -.-> :core:data
+ :feature:search -.-> :core:designsystem
+ :feature:search -.-> :core:domain
+ :feature:search -.-> :core:ui
+ :feature:settings -.-> :core:data
+ :feature:settings -.-> :core:designsystem
+ :feature:settings -.-> :core:ui
+ :feature:topic -.-> :core:data
+ :feature:topic -.-> :core:designsystem
+ :feature:topic -.-> :core:ui
+ :sync:work -.-> :core:analytics
+ :sync:work -.-> :core:data
+ :sync:work -.-> :core:notifications
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 05212a28f..09005606b 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -22,7 +22,7 @@ plugins {
alias(libs.plugins.nowinandroid.android.application.jacoco)
alias(libs.plugins.nowinandroid.android.application.firebase)
alias(libs.plugins.nowinandroid.hilt)
- id("com.google.android.gms.oss-licenses-plugin")
+ alias(libs.plugins.google.osslicenses)
alias(libs.plugins.baselineprofile)
alias(libs.plugins.roborazzi)
alias(libs.plugins.kotlin.serialization)
@@ -43,9 +43,11 @@ android {
applicationIdSuffix = NiaBuildType.DEBUG.applicationIdSuffix
}
release {
- isMinifyEnabled = true
+ isMinifyEnabled = providers.gradleProperty("minifyWithR8")
+ .map(String::toBooleanStrict).getOrElse(true)
applicationIdSuffix = NiaBuildType.RELEASE.applicationIdSuffix
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro")
// To publish on the Play store a private signing key is required, but to allow anyone
// who clones the code to sign and run the release variant, use the debug signing key.
@@ -61,11 +63,7 @@ android {
excludes.add("/META-INF/{AL2.0,LGPL2.1}")
}
}
- testOptions {
- unitTests {
- isIncludeAndroidResources = true
- }
- }
+ testOptions.unitTests.isIncludeAndroidResources = true
namespace = "com.google.samples.apps.nowinandroid"
}
@@ -86,6 +84,7 @@ dependencies {
implementation(projects.sync.work)
implementation(libs.androidx.activity.compose)
+ implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material3.adaptive)
implementation(libs.androidx.compose.material3.adaptive.layout)
implementation(libs.androidx.compose.material3.adaptive.navigation)
diff --git a/app/dependencies/prodReleaseRuntimeClasspath.txt b/app/dependencies/prodReleaseRuntimeClasspath.txt
index 6fca688a1..f4f1e35c8 100644
--- a/app/dependencies/prodReleaseRuntimeClasspath.txt
+++ b/app/dependencies/prodReleaseRuntimeClasspath.txt
@@ -1,7 +1,7 @@
-androidx.activity:activity-compose:1.9.3
-androidx.activity:activity-ktx:1.9.3
-androidx.activity:activity:1.9.3
-androidx.annotation:annotation-experimental:1.4.1
+androidx.activity:activity-compose:1.10.1
+androidx.activity:activity-ktx:1.10.1
+androidx.activity:activity:1.10.1
+androidx.annotation:annotation-experimental:1.5.1
androidx.annotation:annotation-jvm:1.9.1
androidx.annotation:annotation:1.9.1
androidx.appcompat:appcompat-resources:1.7.0
@@ -10,60 +10,63 @@ androidx.arch.core:core-common:2.2.0
androidx.arch.core:core-runtime:2.2.0
androidx.autofill:autofill:1.0.0
androidx.browser:browser:1.8.0
-androidx.collection:collection-jvm:1.5.0-beta01
-androidx.collection:collection-ktx:1.5.0-beta01
-androidx.collection:collection:1.5.0-beta01
-androidx.compose.animation:animation-android:1.8.0-alpha07
-androidx.compose.animation:animation-core-android:1.8.0-alpha07
-androidx.compose.animation:animation-core:1.8.0-alpha07
-androidx.compose.animation:animation:1.8.0-alpha07
-androidx.compose.foundation:foundation-android:1.8.0-alpha07
-androidx.compose.foundation:foundation-layout-android:1.8.0-alpha07
-androidx.compose.foundation:foundation-layout:1.8.0-alpha07
-androidx.compose.foundation:foundation:1.8.0-alpha07
-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-navigation-android:1.0.0
-androidx.compose.material3.adaptive:adaptive-navigation:1.0.0
-androidx.compose.material3.adaptive:adaptive:1.0.0
-androidx.compose.material3:material3-adaptive-navigation-suite-android:1.3.1
-androidx.compose.material3:material3-adaptive-navigation-suite:1.3.1
-androidx.compose.material3:material3-android:1.3.1
-androidx.compose.material3:material3-window-size-class-android:1.3.1
-androidx.compose.material3:material3-window-size-class:1.3.1
-androidx.compose.material3:material3:1.3.1
-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.7.6
-androidx.compose.material:material-ripple:1.7.6
-androidx.compose.runtime:runtime-android:1.8.0-alpha07
-androidx.compose.runtime:runtime-saveable-android:1.8.0-alpha07
-androidx.compose.runtime:runtime-saveable:1.8.0-alpha07
-androidx.compose.runtime:runtime-tracing:1.8.0-alpha07
-androidx.compose.runtime:runtime:1.8.0-alpha07
-androidx.compose.ui:ui-android:1.8.0-alpha07
-androidx.compose.ui:ui-geometry-android:1.8.0-alpha07
-androidx.compose.ui:ui-geometry:1.8.0-alpha07
-androidx.compose.ui:ui-graphics-android:1.8.0-alpha07
-androidx.compose.ui:ui-graphics:1.8.0-alpha07
-androidx.compose.ui:ui-text-android:1.8.0-alpha07
-androidx.compose.ui:ui-text:1.8.0-alpha07
-androidx.compose.ui:ui-tooling-preview-android:1.8.0-alpha07
-androidx.compose.ui:ui-tooling-preview:1.8.0-alpha07
-androidx.compose.ui:ui-unit-android:1.8.0-alpha07
-androidx.compose.ui:ui-unit:1.8.0-alpha07
-androidx.compose.ui:ui-util-android:1.8.0-alpha07
-androidx.compose.ui:ui-util:1.8.0-alpha07
-androidx.compose.ui:ui:1.8.0-alpha07
-androidx.compose:compose-bom:2024.12.01
+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.10.0-alpha02
+androidx.compose.animation:animation-core-android:1.10.0-alpha02
+androidx.compose.animation:animation-core:1.10.0-alpha02
+androidx.compose.animation:animation:1.10.0-alpha02
+androidx.compose.foundation:foundation-android:1.10.0-alpha02
+androidx.compose.foundation:foundation-layout-android:1.10.0-alpha02
+androidx.compose.foundation:foundation-layout:1.10.0-alpha02
+androidx.compose.foundation:foundation:1.10.0-alpha02
+androidx.compose.material3.adaptive:adaptive-android:1.2.0-beta01
+androidx.compose.material3.adaptive:adaptive-layout-android:1.2.0-beta01
+androidx.compose.material3.adaptive:adaptive-layout:1.2.0-beta01
+androidx.compose.material3.adaptive:adaptive-navigation-android:1.2.0-beta01
+androidx.compose.material3.adaptive:adaptive-navigation:1.2.0-beta01
+androidx.compose.material3.adaptive:adaptive:1.2.0-beta01
+androidx.compose.material3:material3-adaptive-navigation-suite-android:1.5.0-alpha03
+androidx.compose.material3:material3-adaptive-navigation-suite:1.5.0-alpha03
+androidx.compose.material3:material3-android:1.5.0-alpha03
+androidx.compose.material3:material3-window-size-class-android:1.5.0-alpha03
+androidx.compose.material3:material3-window-size-class:1.5.0-alpha03
+androidx.compose.material3:material3:1.5.0-alpha03
+androidx.compose.material:material-icons-core-android:1.7.8
+androidx.compose.material:material-icons-core:1.7.8
+androidx.compose.material:material-icons-extended-android:1.7.8
+androidx.compose.material:material-icons-extended:1.7.8
+androidx.compose.material:material-ripple-android:1.10.0-alpha02
+androidx.compose.material:material-ripple:1.10.0-alpha02
+androidx.compose.runtime:runtime-android:1.10.0-alpha02
+androidx.compose.runtime:runtime-annotation-android:1.10.0-alpha02
+androidx.compose.runtime:runtime-annotation:1.10.0-alpha02
+androidx.compose.runtime:runtime-saveable-android:1.10.0-alpha02
+androidx.compose.runtime:runtime-saveable:1.10.0-alpha02
+androidx.compose.runtime:runtime-tracing:1.10.0-alpha02
+androidx.compose.runtime:runtime:1.10.0-alpha02
+androidx.compose.ui:ui-android:1.10.0-alpha02
+androidx.compose.ui:ui-geometry-android:1.10.0-alpha02
+androidx.compose.ui:ui-geometry:1.10.0-alpha02
+androidx.compose.ui:ui-graphics-android:1.10.0-alpha02
+androidx.compose.ui:ui-graphics:1.10.0-alpha02
+androidx.compose.ui:ui-text-android:1.10.0-alpha02
+androidx.compose.ui:ui-text:1.10.0-alpha02
+androidx.compose.ui:ui-tooling-preview-android:1.10.0-alpha02
+androidx.compose.ui:ui-tooling-preview:1.10.0-alpha02
+androidx.compose.ui:ui-unit-android:1.10.0-alpha02
+androidx.compose.ui:ui-unit:1.10.0-alpha02
+androidx.compose.ui:ui-util-android:1.10.0-alpha02
+androidx.compose.ui:ui-util:1.10.0-alpha02
+androidx.compose.ui:ui:1.10.0-alpha02
+androidx.compose:compose-bom-alpha:2025.08.01
androidx.concurrent:concurrent-futures-ktx:1.1.0
androidx.concurrent:concurrent-futures:1.1.0
-androidx.core:core-ktx:1.15.0
+androidx.core:core-ktx:1.16.0
androidx.core:core-splashscreen:1.0.1
-androidx.core:core:1.15.0
+androidx.core:core-viewtree:1.0.0
+androidx.core:core:1.16.0
androidx.cursoradapter:cursoradapter:1.0.0
androidx.customview:customview-poolingcontainer:1.0.0
androidx.customview:customview:1.0.0
@@ -79,37 +82,41 @@ androidx.datastore:datastore-preferences:1.1.1
androidx.datastore:datastore:1.1.1
androidx.documentfile:documentfile:1.0.0
androidx.drawerlayout:drawerlayout:1.0.0
+androidx.dynamicanimation:dynamicanimation:1.0.0
androidx.emoji2:emoji2-views-helper:1.4.0
androidx.emoji2:emoji2:1.4.0
androidx.exifinterface:exifinterface:1.3.7
androidx.fragment:fragment:1.5.4
androidx.graphics:graphics-path:1.0.1
+androidx.graphics:graphics-shapes-android:1.0.1
+androidx.graphics:graphics-shapes:1.0.1
androidx.hilt:hilt-common:1.2.0
androidx.hilt:hilt-navigation-compose:1.2.0
androidx.hilt:hilt-navigation:1.2.0
androidx.hilt:hilt-work:1.2.0
androidx.interpolator:interpolator:1.0.0
androidx.legacy:legacy-support-core-utils:1.0.0
-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-ktx:2.8.7
-androidx.lifecycle:lifecycle-livedata-core:2.8.7
-androidx.lifecycle:lifecycle-livedata: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-service:2.8.7
-androidx.lifecycle:lifecycle-viewmodel-android:2.8.7
-androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.7
-androidx.lifecycle:lifecycle-viewmodel-compose: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.lifecycle:lifecycle-common-java8:2.10.0-alpha03
+androidx.lifecycle:lifecycle-common-jvm:2.10.0-alpha03
+androidx.lifecycle:lifecycle-common:2.10.0-alpha03
+androidx.lifecycle:lifecycle-livedata-core-ktx:2.10.0-alpha03
+androidx.lifecycle:lifecycle-livedata-core:2.10.0-alpha03
+androidx.lifecycle:lifecycle-livedata:2.10.0-alpha03
+androidx.lifecycle:lifecycle-process:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-compose-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-compose:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-ktx-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime-ktx:2.10.0-alpha03
+androidx.lifecycle:lifecycle-runtime:2.10.0-alpha03
+androidx.lifecycle:lifecycle-service:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-compose-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-ktx:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel-savedstate:2.10.0-alpha03
+androidx.lifecycle:lifecycle-viewmodel:2.10.0-alpha03
androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-beta01
@@ -123,25 +130,32 @@ androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05
androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05
androidx.profileinstaller:profileinstaller:1.4.1
androidx.resourceinspection:resourceinspection-annotation:1.0.1
-androidx.room:room-common:2.6.1
-androidx.room:room-ktx:2.6.1
-androidx.room:room-runtime:2.6.1
-androidx.savedstate:savedstate-ktx:1.2.1
-androidx.savedstate:savedstate:1.2.1
-androidx.sqlite:sqlite-framework:2.4.0
-androidx.sqlite:sqlite:2.4.0
+androidx.room:room-common-jvm:2.8.3
+androidx.room:room-common:2.8.3
+androidx.room:room-ktx:2.8.3
+androidx.room:room-runtime-android:2.8.3
+androidx.room:room-runtime:2.8.3
+androidx.savedstate:savedstate-android:1.4.0-alpha03
+androidx.savedstate:savedstate-compose-android:1.4.0-alpha03
+androidx.savedstate:savedstate-compose:1.4.0-alpha03
+androidx.savedstate:savedstate-ktx:1.4.0-alpha03
+androidx.savedstate:savedstate:1.4.0-alpha03
+androidx.sqlite:sqlite-android:2.6.1
+androidx.sqlite:sqlite-framework-android:2.6.1
+androidx.sqlite:sqlite-framework:2.6.1
+androidx.sqlite:sqlite:2.6.1
androidx.startup:startup-runtime:1.1.1
androidx.tracing:tracing-ktx:1.3.0-alpha02
androidx.tracing:tracing-perfetto:1.0.0
androidx.tracing:tracing:1.3.0-alpha02
+androidx.transition:transition:1.6.0
androidx.vectordrawable:vectordrawable-animated:1.1.0
androidx.vectordrawable:vectordrawable:1.1.0
androidx.versionedparcelable:versionedparcelable:1.1.1
androidx.viewpager:viewpager:1.0.0
-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
+androidx.window:window-core-android:1.4.0
+androidx.window:window-core:1.4.0
+androidx.window:window:1.4.0
androidx.work:work-runtime-ktx:2.10.0
androidx.work:work-runtime:2.10.0
com.caverock:androidsvg-aar:1.4
@@ -164,10 +178,10 @@ com.google.android.gms:play-services-oss-licenses:17.1.0
com.google.android.gms:play-services-stats:17.0.2
com.google.android.gms:play-services-tasks:18.2.0
com.google.code.findbugs:jsr305:3.0.2
-com.google.dagger:dagger-lint-aar:2.54
-com.google.dagger:dagger:2.54
-com.google.dagger:hilt-android:2.54
-com.google.dagger:hilt-core:2.54
+com.google.dagger:dagger-lint-aar:2.57.2
+com.google.dagger:dagger:2.57.2
+com.google.dagger:hilt-android:2.57.2
+com.google.dagger:hilt-core:2.57.2
com.google.errorprone:error_prone_annotations:2.26.0
com.google.firebase:firebase-abt:21.1.1
com.google.firebase:firebase-analytics:22.1.2
@@ -212,10 +226,10 @@ javax.inject:javax.inject:1
org.checkerframework:checker-qual:3.12.0
org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.9.22
org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22
-org.jetbrains.kotlin:kotlin-stdlib-common:2.1.0
+org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0
-org.jetbrains.kotlin:kotlin-stdlib:2.1.0
+org.jetbrains.kotlin:kotlin-stdlib:2.2.21
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1
diff --git a/app/prodRelease-badging.txt b/app/prodRelease-badging.txt
index 0d770604e..640949857 100644
--- a/app/prodRelease-badging.txt
+++ b/app/prodRelease-badging.txt
@@ -1,5 +1,5 @@
package: name='com.google.samples.apps.nowinandroid' versionCode='8' versionName='0.1.2' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15'
-sdkVersion:'21'
+minSdkVersion:'23'
targetSdkVersion:'35'
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
@@ -105,9 +105,9 @@ 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'
+uses-library-not-required:'android.ext.adservices'
feature-group: label=''
uses-feature: name='android.hardware.faketouch'
uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 000000000..24a0b4a16
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,2 @@
+# Repackage classes into the default package to reduce the size of descriptors.
+-repackageclasses
diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt
index 77f72e5fc..4975e5d65 100644
--- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt
+++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt
@@ -66,7 +66,7 @@ class NiaApplication : Application(), ImageLoaderFactory {
private fun setStrictModePolicy() {
if (isDebuggable()) {
StrictMode.setThreadPolicy(
- Builder().detectAll().penaltyLog().penaltyDeath().build(),
+ Builder().detectAll().penaltyLog().build(),
)
}
}
diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt
index f27b90cbe..b237684ef 100644
--- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt
+++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt
@@ -21,7 +21,9 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.consumeWindowInsets
+import androidx.compose.foundation.layout.exclude
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
@@ -166,8 +168,7 @@ internal fun NiaApp(
)
},
label = { Text(stringResource(destination.iconTextId)) },
- modifier =
- Modifier
+ modifier = Modifier
.testTag("NiaNavItem")
.then(if (hasUnread) Modifier.notificationDot() else Modifier),
)
@@ -182,7 +183,16 @@ internal fun NiaApp(
containerColor = Color.Transparent,
contentColor = MaterialTheme.colorScheme.onBackground,
contentWindowInsets = WindowInsets(0, 0, 0, 0),
- snackbarHost = { SnackbarHost(snackbarHostState) },
+ snackbarHost = {
+ SnackbarHost(
+ snackbarHostState,
+ modifier = Modifier.windowInsetsPadding(
+ WindowInsets.safeDrawing.exclude(
+ WindowInsets.ime,
+ ),
+ ),
+ )
+ },
) { padding ->
Column(
Modifier
@@ -211,7 +221,7 @@ internal fun NiaApp(
actionIconContentDescription = stringResource(
id = settingsR.string.feature_settings_top_app_bar_action_icon_description,
),
- colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
+ colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
),
onActionClick = { onTopAppBarActionClick() },
diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt
index 669c6300a..c0f425c65 100644
--- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt
+++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt
@@ -17,47 +17,53 @@
package com.google.samples.apps.nowinandroid.ui.interests2pane
import androidx.activity.compose.BackHandler
-import androidx.annotation.Keep
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.material3.LocalMinimumInteractiveComponentSize
+import androidx.compose.material3.VerticalDragHandle
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.WindowAdaptiveInfo
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.adaptive.layout.AnimatedPane
-import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
+import androidx.compose.material3.adaptive.layout.PaneExpansionAnchor
import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem
import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective
+import androidx.compose.material3.adaptive.layout.defaultDragHandleSemantics
+import androidx.compose.material3.adaptive.layout.rememberPaneExpansionState
+import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior
+import androidx.compose.material3.adaptive.navigation.NavigableListDetailPaneScaffold
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator
+import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldPredictiveBackHandler
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.saveable.Saver
-import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
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.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.TopicScreen
+import com.google.samples.apps.nowinandroid.feature.topic.TopicViewModel
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 java.util.UUID
+import kotlin.math.max
@Serializable internal object TopicPlaceholderRoute
-// TODO: Remove @Keep when https://issuetracker.google.com/353898971 is fixed
-@Keep
-@Serializable internal object DetailPaneNavHostRoute
-
fun NavGraphBuilder.interestsListDetailScreen() {
composable {
InterestsListDetailScreen()
@@ -93,70 +99,139 @@ internal fun InterestsListDetailScreen(
},
),
)
- BackHandler(listDetailNavigator.canNavigateBack()) {
- listDetailNavigator.navigateBack()
+ val coroutineScope = rememberCoroutineScope()
+
+ val paneExpansionState = rememberPaneExpansionState(
+ anchors = listOf(
+ PaneExpansionAnchor.Proportion(0f),
+ PaneExpansionAnchor.Proportion(0.5f),
+ PaneExpansionAnchor.Proportion(1f),
+ ),
+ )
+
+ ThreePaneScaffoldPredictiveBackHandler(
+ listDetailNavigator,
+ BackNavigationBehavior.PopUntilScaffoldValueChange,
+ )
+ BackHandler(
+ paneExpansionState.currentAnchor == PaneExpansionAnchor.Proportion(0f) &&
+ listDetailNavigator.isListPaneVisible() &&
+ listDetailNavigator.isDetailPaneVisible(),
+ ) {
+ coroutineScope.launch {
+ paneExpansionState.animateTo(PaneExpansionAnchor.Proportion(1f))
+ }
}
- var nestedNavHostStartRoute by remember {
+ var topicRoute by remember {
val route = selectedTopicId?.let { TopicRoute(id = it) } ?: TopicPlaceholderRoute
mutableStateOf(route)
}
- var nestedNavKey by rememberSaveable(
- stateSaver = Saver({ it.toString() }, UUID::fromString),
- ) {
- mutableStateOf(UUID.randomUUID())
- }
- val nestedNavController = key(nestedNavKey) {
- rememberNavController()
- }
fun onTopicClickShowDetailPane(topicId: String) {
onTopicClick(topicId)
- if (listDetailNavigator.isDetailPaneVisible()) {
- // If the detail pane was visible, then use the nestedNavController navigate call
- // directly
- nestedNavController.navigateToTopic(topicId) {
- popUpTo()
+ topicRoute = TopicRoute(id = topicId)
+ coroutineScope.launch {
+ listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
+ }
+ if (paneExpansionState.currentAnchor == PaneExpansionAnchor.Proportion(1f)) {
+ coroutineScope.launch {
+ paneExpansionState.animateTo(PaneExpansionAnchor.Proportion(0f))
}
- } else {
- // Otherwise, recreate the NavHost entirely, and start at the new destination
- nestedNavHostStartRoute = TopicRoute(id = topicId)
- nestedNavKey = UUID.randomUUID()
}
- listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
}
- ListDetailPaneScaffold(
- value = listDetailNavigator.scaffoldValue,
- directive = listDetailNavigator.scaffoldDirective,
+ val mutableInteractionSource = remember { MutableInteractionSource() }
+ val minPaneWidth = 300.dp
+
+ NavigableListDetailPaneScaffold(
+ navigator = listDetailNavigator,
listPane = {
AnimatedPane {
- InterestsRoute(
- onTopicClick = ::onTopicClickShowDetailPane,
- highlightSelectedTopic = listDetailNavigator.isDetailPaneVisible(),
- )
+ Box(
+ modifier = Modifier.clipToBounds()
+ .layout { measurable, constraints ->
+ val width = max(minPaneWidth.roundToPx(), constraints.maxWidth)
+ val placeable = measurable.measure(
+ constraints.copy(
+ minWidth = minPaneWidth.roundToPx(),
+ maxWidth = width,
+ ),
+ )
+ layout(constraints.maxWidth, placeable.height) {
+ placeable.placeRelative(
+ x = 0,
+ y = 0,
+ )
+ }
+ },
+ ) {
+ InterestsRoute(
+ onTopicClick = ::onTopicClickShowDetailPane,
+ shouldHighlightSelectedTopic = listDetailNavigator.isDetailPaneVisible(),
+ )
+ }
}
},
detailPane = {
AnimatedPane {
- key(nestedNavKey) {
- NavHost(
- navController = nestedNavController,
- startDestination = nestedNavHostStartRoute,
- route = DetailPaneNavHostRoute::class,
- ) {
- topicScreen(
- showBackButton = !listDetailNavigator.isListPaneVisible(),
- onBackClick = listDetailNavigator::navigateBack,
- onTopicClick = ::onTopicClickShowDetailPane,
- )
- composable {
- TopicDetailPlaceholder()
+ Box(
+ modifier = Modifier.clipToBounds()
+ .layout { measurable, constraints ->
+ val width = max(minPaneWidth.roundToPx(), constraints.maxWidth)
+ val placeable = measurable.measure(
+ constraints.copy(
+ minWidth = minPaneWidth.roundToPx(),
+ maxWidth = width,
+ ),
+ )
+ layout(constraints.maxWidth, placeable.height) {
+ placeable.placeRelative(
+ x = constraints.maxWidth -
+ max(constraints.maxWidth, placeable.width),
+ y = 0,
+ )
+ }
+ },
+ ) {
+ AnimatedContent(topicRoute) { route ->
+ when (route) {
+ is TopicRoute -> {
+ TopicScreen(
+ showBackButton = !listDetailNavigator.isListPaneVisible(),
+ onBackClick = {
+ coroutineScope.launch {
+ listDetailNavigator.navigateBack()
+ }
+ },
+ onTopicClick = ::onTopicClickShowDetailPane,
+ viewModel = hiltViewModel(
+ key = route.id,
+ ) { factory ->
+ factory.create(route.id)
+ },
+ )
+ }
+ is TopicPlaceholderRoute -> {
+ TopicDetailPlaceholder()
+ }
}
}
}
}
},
+ paneExpansionState = paneExpansionState,
+ paneExpansionDragHandle = {
+ VerticalDragHandle(
+ modifier = Modifier.paneExpansionDraggable(
+ state = paneExpansionState,
+ minTouchTargetSize = LocalMinimumInteractiveComponentSize.current,
+ interactionSource = mutableInteractionSource,
+ semanticsProperties = paneExpansionState.defaultDragHandleSemantics(),
+ ),
+ interactionSource = mutableInteractionSource,
+ )
+ },
)
}
diff --git a/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png
index 2e6d1037c..7a49b2c32 100644
Binary files a/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/compactWidth_compactHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png
index 1acb34aba..ab20746cb 100644
Binary files a/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/compactWidth_expandedHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png
index d52c844a3..926ce00f1 100644
Binary files a/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/compactWidth_mediumHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationBar.png
index e6e574347..d793bed51 100644
Binary files a/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/expandedWidth_compactHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png
index 222fc21aa..b6f89e516 100644
Binary files a/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/expandedWidth_expandedHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png
index a33ad8863..2bf46ca4f 100644
Binary files a/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/expandedWidth_mediumHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/insets_snackbar_compact_medium.png b/app/src/testDemo/screenshots/insets_snackbar_compact_medium.png
index 4e741bdcc..e95e700ba 100644
Binary files a/app/src/testDemo/screenshots/insets_snackbar_compact_medium.png and b/app/src/testDemo/screenshots/insets_snackbar_compact_medium.png differ
diff --git a/app/src/testDemo/screenshots/insets_snackbar_compact_medium_noSnackbar.png b/app/src/testDemo/screenshots/insets_snackbar_compact_medium_noSnackbar.png
index 2e76d3a68..db6488e34 100644
Binary files a/app/src/testDemo/screenshots/insets_snackbar_compact_medium_noSnackbar.png and b/app/src/testDemo/screenshots/insets_snackbar_compact_medium_noSnackbar.png differ
diff --git a/app/src/testDemo/screenshots/insets_snackbar_expanded_expanded.png b/app/src/testDemo/screenshots/insets_snackbar_expanded_expanded.png
index d39df7b79..becfe5715 100644
Binary files a/app/src/testDemo/screenshots/insets_snackbar_expanded_expanded.png and b/app/src/testDemo/screenshots/insets_snackbar_expanded_expanded.png differ
diff --git a/app/src/testDemo/screenshots/insets_snackbar_medium_medium.png b/app/src/testDemo/screenshots/insets_snackbar_medium_medium.png
index ec6377143..578ff0b6d 100644
Binary files a/app/src/testDemo/screenshots/insets_snackbar_medium_medium.png and b/app/src/testDemo/screenshots/insets_snackbar_medium_medium.png differ
diff --git a/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationBar.png b/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationBar.png
index fdbf9ee8b..64cf8f32f 100644
Binary files a/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationBar.png and b/app/src/testDemo/screenshots/mediumWidth_compactHeight_showsNavigationBar.png differ
diff --git a/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png
index 882e62760..679846fc1 100644
Binary files a/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/mediumWidth_expandedHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png b/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png
index 8ffe73e86..b8ddeb12b 100644
Binary files a/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png and b/app/src/testDemo/screenshots/mediumWidth_mediumHeight_showsNavigationRail.png differ
diff --git a/app/src/testDemo/screenshots/snackbar_compact_medium.png b/app/src/testDemo/screenshots/snackbar_compact_medium.png
index 3f67285a3..ad12a4173 100644
Binary files a/app/src/testDemo/screenshots/snackbar_compact_medium.png and b/app/src/testDemo/screenshots/snackbar_compact_medium.png differ
diff --git a/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png b/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png
index 893d43d19..bc466edcb 100644
Binary files a/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png and b/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png differ
diff --git a/app/src/testDemo/screenshots/snackbar_expanded_expanded.png b/app/src/testDemo/screenshots/snackbar_expanded_expanded.png
index b429a7315..fc98037a6 100644
Binary files a/app/src/testDemo/screenshots/snackbar_expanded_expanded.png and b/app/src/testDemo/screenshots/snackbar_expanded_expanded.png differ
diff --git a/app/src/testDemo/screenshots/snackbar_medium_medium.png b/app/src/testDemo/screenshots/snackbar_medium_medium.png
index 00e9e3051..1dfc73e5a 100644
Binary files a/app/src/testDemo/screenshots/snackbar_medium_medium.png and b/app/src/testDemo/screenshots/snackbar_medium_medium.png differ
diff --git a/benchmarks/README.md b/benchmarks/README.md
new file mode 100644
index 000000000..657ad5422
--- /dev/null
+++ b/benchmarks/README.md
@@ -0,0 +1,134 @@
+# `:benchmarks`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:domain[domain]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:bookmarks[bookmarks]:::android-feature
+ :feature:foryou[foryou]:::android-feature
+ :feature:interests[interests]:::android-feature
+ :feature:search[search]:::android-feature
+ :feature:settings[settings]:::android-feature
+ :feature:topic[topic]:::android-feature
+ end
+ subgraph :sync
+ direction TB
+ :sync:work[work]:::android-library
+ end
+ :benchmarks[benchmarks]:::android-test
+ :app[app]:::android-application
+
+ :app -.->|baselineProfile| :benchmarks
+ :app -.-> :core:analytics
+ :app -.-> :core:common
+ :app -.-> :core:data
+ :app -.-> :core:designsystem
+ :app -.-> :core:model
+ :app -.-> :core:ui
+ :app -.-> :feature:bookmarks
+ :app -.-> :feature:foryou
+ :app -.-> :feature:interests
+ :app -.-> :feature:search
+ :app -.-> :feature:settings
+ :app -.-> :feature:topic
+ :app -.-> :sync:work
+ :benchmarks -.->|testedApks| :app
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:domain --> :core:data
+ :core:domain --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:bookmarks -.-> :core:data
+ :feature:bookmarks -.-> :core:designsystem
+ :feature:bookmarks -.-> :core:ui
+ :feature:foryou -.-> :core:data
+ :feature:foryou -.-> :core:designsystem
+ :feature:foryou -.-> :core:domain
+ :feature:foryou -.-> :core:notifications
+ :feature:foryou -.-> :core:ui
+ :feature:interests -.-> :core:data
+ :feature:interests -.-> :core:designsystem
+ :feature:interests -.-> :core:domain
+ :feature:interests -.-> :core:ui
+ :feature:search -.-> :core:data
+ :feature:search -.-> :core:designsystem
+ :feature:search -.-> :core:domain
+ :feature:search -.-> :core:ui
+ :feature:settings -.-> :core:data
+ :feature:settings -.-> :core:designsystem
+ :feature:settings -.-> :core:ui
+ :feature:topic -.-> :core:data
+ :feature:topic -.-> :core:designsystem
+ :feature:topic -.-> :core:ui
+ :sync:work -.-> :core:analytics
+ :sync:work -.-> :core:data
+ :sync:work -.-> :core:notifications
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts
index e36f021b0..258993913 100644
--- a/benchmarks/build.gradle.kts
+++ b/benchmarks/build.gradle.kts
@@ -45,8 +45,8 @@ android {
)
}
- testOptions.managedDevices.devices {
- create("pixel6Api33") {
+ testOptions.managedDevices.localDevices {
+ create("pixel6Api33") {
device = "Pixel 6"
apiLevel = 33
systemImageSource = "aosp"
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
index 6d0237010..166b54907 100644
--- a/build-logic/convention/build.gradle.kts
+++ b/build-logic/convention/build.gradle.kts
@@ -37,7 +37,7 @@ kotlin {
}
dependencies {
- compileOnly(libs.android.gradlePlugin)
+ compileOnly(libs.android.gradleApiPlugin)
compileOnly(libs.android.tools.common)
compileOnly(libs.compose.gradlePlugin)
compileOnly(libs.firebase.crashlytics.gradlePlugin)
@@ -114,5 +114,9 @@ gradlePlugin {
id = libs.plugins.nowinandroid.jvm.library.get().pluginId
implementationClass = "JvmLibraryConventionPlugin"
}
+ register("root") {
+ id = libs.plugins.nowinandroid.root.get().pluginId
+ implementationClass = "RootPlugin"
+ }
}
}
diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
index 1ab3a2ca0..f45d664b7 100644
--- a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
@@ -16,7 +16,6 @@
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
-import com.android.build.gradle.BaseExtension
import com.google.samples.apps.nowinandroid.configureBadgingTasks
import com.google.samples.apps.nowinandroid.configureGradleManagedDevices
import com.google.samples.apps.nowinandroid.configureKotlinAndroid
@@ -44,7 +43,7 @@ class AndroidApplicationConventionPlugin : Plugin {
}
extensions.configure {
configurePrintApksTask(this)
- configureBadgingTasks(extensions.getByType(), this)
+ configureBadgingTasks(extensions.getByType(), this)
}
}
}
diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
index 1af5523c5..343bd4859 100644
--- a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import com.android.build.gradle.LibraryExtension
+import com.android.build.api.dsl.LibraryExtension
import com.google.samples.apps.nowinandroid.configureGradleManagedDevices
import com.google.samples.apps.nowinandroid.libs
import org.gradle.api.Plugin
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
index 19fabf549..63a992b05 100644
--- a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import com.android.build.gradle.LibraryExtension
+import com.android.build.api.dsl.LibraryExtension
import com.google.samples.apps.nowinandroid.configureAndroidCompose
import org.gradle.api.Plugin
import org.gradle.api.Project
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
index 3fe727410..0f6fde884 100644
--- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.variant.LibraryAndroidComponentsExtension
-import com.android.build.gradle.LibraryExtension
import com.google.samples.apps.nowinandroid.configureFlavors
import com.google.samples.apps.nowinandroid.configureGradleManagedDevices
import com.google.samples.apps.nowinandroid.configureKotlinAndroid
@@ -37,7 +37,8 @@ class AndroidLibraryConventionPlugin : Plugin {
extensions.configure {
configureKotlinAndroid(this)
- defaultConfig.targetSdk = 35
+ testOptions.targetSdk = 35
+ lint.targetSdk = 35
defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testOptions.animationsDisabled = true
configureFlavors(this)
diff --git a/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt
index 67933f77d..49c2eecec 100644
--- a/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import com.android.build.gradle.TestExtension
+import com.android.build.api.dsl.TestExtension
import com.google.samples.apps.nowinandroid.configureGradleManagedDevices
import com.google.samples.apps.nowinandroid.configureKotlinAndroid
import org.gradle.api.Plugin
diff --git a/build-logic/convention/src/main/kotlin/RootPlugin.kt b/build-logic/convention/src/main/kotlin/RootPlugin.kt
new file mode 100644
index 000000000..b704adf76
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/RootPlugin.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2025 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.
+ */
+
+import com.google.samples.apps.nowinandroid.configureGraphTasks
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class RootPlugin : Plugin {
+ override fun apply(target: Project) {
+ require(target.path == ":")
+ target.subprojects { configureGraphTasks() }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt
index ed2a5289b..3d050d86b 100644
--- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt
+++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt
@@ -42,13 +42,6 @@ internal fun Project.configureAndroidCompose(
"implementation"(libs.findLibrary("androidx-compose-ui-tooling-preview").get())
"debugImplementation"(libs.findLibrary("androidx-compose-ui-tooling").get())
}
-
- testOptions {
- unitTests {
- // For Robolectric
- isIncludeAndroidResources = true
- }
- }
}
extensions.configure {
diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt
index 886c70625..229388001 100644
--- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt
+++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt
@@ -18,8 +18,8 @@ package com.google.samples.apps.nowinandroid
import com.android.SdkConstants
import com.android.build.api.artifact.SingleArtifact
+import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
-import com.android.build.gradle.BaseExtension
import com.google.common.truth.Truth.assertWithMessage
import org.gradle.api.DefaultTask
import org.gradle.api.Project
@@ -110,7 +110,7 @@ private fun String.capitalized() = replaceFirstChar {
}
fun Project.configureBadgingTasks(
- baseExtension: BaseExtension,
+ baseExtension: ApplicationExtension,
componentsExtension: ApplicationAndroidComponentsExtension,
) {
// Registers a callback to be called, when a new variant is configured
diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Graph.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Graph.kt
new file mode 100644
index 000000000..439a50181
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Graph.kt
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2025 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
+
+import com.android.utils.associateWithNotNull
+import com.google.samples.apps.nowinandroid.PluginType.Unknown
+import org.gradle.api.DefaultTask
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.provider.MapProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.CacheableTask
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.PathSensitive
+import org.gradle.api.tasks.PathSensitivity.NONE
+import org.gradle.api.tasks.TaskAction
+import org.gradle.kotlin.dsl.assign
+import org.gradle.kotlin.dsl.register
+import org.gradle.kotlin.dsl.withType
+import kotlin.text.RegexOption.DOT_MATCHES_ALL
+
+/**
+ * Generates module dependency graphs with `graphDump` task, and update the corresponding `README.md` file with `graphUpdate`.
+ *
+ * This is not an optimal implementation and could be improved if needed:
+ * - [Graph.invoke] is **recursively** searching through dependent projects (although in practice it will never reach a stack overflow).
+ * - [Graph.invoke] is entirely re-executed for all projects, without re-using intermediate values.
+ * - [Graph.invoke] is always executed during Gradle's Configuration phase (but takes in general less than 1 ms for a project).
+ *
+ * The resulting graphs can be configured with `graph.ignoredProjects` and `graph.supportedConfigurations` properties.
+ */
+private class Graph(
+ private val root: Project,
+ private val dependencies: MutableMap>> = mutableMapOf(),
+ private val plugins: MutableMap = mutableMapOf(),
+ private val seen: MutableSet = mutableSetOf(),
+) {
+
+ private val ignoredProjects = root.providers.gradleProperty("graph.ignoredProjects")
+ .map { it.split(",").toSet() }
+ .orElse(emptySet())
+ private val supportedConfigurations =
+ root.providers.gradleProperty("graph.supportedConfigurations")
+ .map { it.split(",").toSet() }
+ .orElse(setOf("api", "implementation", "baselineProfile", "testedApks"))
+
+ operator fun invoke(project: Project = root): Graph {
+ if (project.path in seen) return this
+ seen += project.path
+ plugins.putIfAbsent(
+ project,
+ PluginType.entries.firstOrNull { project.pluginManager.hasPlugin(it.id) } ?: Unknown,
+ )
+ dependencies.compute(project) { _, u -> u.orEmpty() }
+ project.configurations
+ .matching { it.name in supportedConfigurations.get() }
+ .associateWithNotNull { it.dependencies.withType().ifEmpty { null } }
+ .flatMap { (c, value) -> value.map { dep -> c to project.project(dep.path) } }
+ .filter { (_, p) -> p.path !in ignoredProjects.get() }
+ .forEach { (configuration: Configuration, projectDependency: Project) ->
+ dependencies.compute(project) { _, u -> u.orEmpty() + (configuration to projectDependency) }
+ invoke(projectDependency)
+ }
+ return this
+ }
+
+ fun dependencies(): Map>> = dependencies
+ .mapKeys { it.key.path }
+ .mapValues { it.value.mapTo(mutableSetOf()) { (c, p) -> c.name to p.path } }
+
+ fun plugins() = plugins.mapKeys { it.key.path }
+}
+
+/**
+ * Declaration order is important, as only the first match will be retained.
+ */
+internal enum class PluginType(val id: String, val ref: String, val style: String) {
+ AndroidApplication(
+ id = "nowinandroid.android.application",
+ ref = "android-application",
+ style = "fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidFeature(
+ id = "nowinandroid.android.feature",
+ ref = "android-feature",
+ style = "fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidLibrary(
+ id = "nowinandroid.android.library",
+ ref = "android-library",
+ style = "fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidTest(
+ id = "nowinandroid.android.test",
+ ref = "android-test",
+ style = "fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ Jvm(
+ id = "nowinandroid.jvm.library",
+ ref = "jvm-library",
+ style = "fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ Unknown(
+ id = "?",
+ ref = "unknown",
+ style = "fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000",
+ ),
+}
+
+internal fun Project.configureGraphTasks() {
+ if (!buildFile.exists()) return // Ignore root modules without build file
+ val dumpTask = tasks.register("graphDump") {
+ val graph = Graph(this@configureGraphTasks).invoke()
+ projectPath = this@configureGraphTasks.path
+ dependencies = graph.dependencies()
+ plugins = graph.plugins()
+ output = this@configureGraphTasks.layout.buildDirectory.file("mermaid/graph.txt")
+ legend = this@configureGraphTasks.layout.buildDirectory.file("mermaid/legend.txt")
+ }
+ tasks.register("graphUpdate") {
+ projectPath = this@configureGraphTasks.path
+ input = dumpTask.flatMap { it.output }
+ legend = dumpTask.flatMap { it.legend }
+ output = this@configureGraphTasks.layout.projectDirectory.file("README.md")
+ }
+}
+
+@CacheableTask
+private abstract class GraphDumpTask : DefaultTask() {
+
+ @get:Input
+ abstract val projectPath: Property
+
+ @get:Input
+ abstract val dependencies: MapProperty>>
+
+ @get:Input
+ abstract val plugins: MapProperty
+
+ @get:OutputFile
+ abstract val output: RegularFileProperty
+
+ @get:OutputFile
+ abstract val legend: RegularFileProperty
+
+ override fun getDescription() = "Dumps project dependencies to a mermaid file."
+
+ @TaskAction
+ operator fun invoke() {
+ output.get().asFile.writeText(mermaid())
+ legend.get().asFile.writeText(legend())
+ logger.lifecycle(output.get().asFile.toPath().toUri().toString())
+ }
+
+ private fun mermaid() = buildString {
+ val dependencies: Set = dependencies.get()
+ .flatMapTo(mutableSetOf()) { (project, entries) -> entries.map { it.toDependency(project) } }
+ // FrontMatter configuration (not supported yet on GitHub.com)
+ appendLine(
+ // language=YAML
+ """
+ ---
+ config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+ ---
+ """.trimIndent(),
+ )
+ // Graph declaration
+ appendLine("graph TB")
+ // Nodes and subgraphs (limited to a single nested layer)
+ val (rootProjects, nestedProjects) = dependencies
+ .map { listOf(it.project, it.dependency) }.flatten().toSet()
+ .plus(projectPath.get()) // Special case when this specific module has no other dependency
+ .groupBy { it.substringBeforeLast(":") }
+ .entries.partition { it.key.isEmpty() }
+ nestedProjects.sortedByDescending { it.value.size }.forEach { (group, projects) ->
+ appendLine(" subgraph $group")
+ appendLine(" direction TB")
+ projects.sorted().forEach {
+ appendLine(it.alias(indent = 4, plugins.get().getValue(it)))
+ }
+ appendLine(" end")
+ }
+ rootProjects.flatMap { it.value }.sortedDescending().forEach {
+ appendLine(it.alias(indent = 2, plugins.get().getValue(it)))
+ }
+ // Links
+ if (dependencies.isNotEmpty()) appendLine()
+ dependencies
+ .sortedWith(compareBy({ it.project }, { it.dependency }, { it.configuration }))
+ .forEach { appendLine(it.link(indent = 2)) }
+ // Classes
+ appendLine()
+ PluginType.entries.forEach { appendLine(it.classDef()) }
+ }
+
+ private fun legend() = buildString {
+ appendLine("graph TB")
+ listOf(
+ "application" to PluginType.AndroidApplication,
+ "feature" to PluginType.AndroidFeature,
+ "library" to PluginType.AndroidLibrary,
+ "jvm" to PluginType.Jvm,
+ ).forEach { (name, type) ->
+ appendLine(name.alias(indent = 2, type))
+ }
+ appendLine()
+ listOf(
+ Dependency("application", "implementation", "feature"),
+ Dependency("library", "api", "jvm"),
+ ).forEach {
+ appendLine(it.link(indent = 2))
+ }
+ appendLine()
+ PluginType.entries.forEach { appendLine(it.classDef()) }
+ }
+
+ private class Dependency(val project: String, val configuration: String, val dependency: String)
+
+ private fun Pair.toDependency(project: String) =
+ Dependency(project, configuration = first, dependency = second)
+
+ private fun String.alias(indent: Int, pluginType: PluginType): String = buildString {
+ append(" ".repeat(indent))
+ append(this@alias)
+ append("[").append(substringAfterLast(":")).append("]:::")
+ append(pluginType.ref)
+ }
+
+ private fun Dependency.link(indent: Int) = buildString {
+ append(" ".repeat(indent))
+ append(project).append(" ")
+ append(
+ when (configuration) {
+ "api" -> "-->"
+ "implementation" -> "-.->"
+ else -> "-.->|$configuration|"
+ },
+ )
+ append(" ").append(dependency)
+ }
+
+ private fun PluginType.classDef() = "classDef $ref $style;"
+}
+
+@CacheableTask
+private abstract class GraphUpdateTask : DefaultTask() {
+
+ @get:Input
+ abstract val projectPath: Property
+
+ @get:InputFile
+ @get:PathSensitive(NONE)
+ abstract val input: RegularFileProperty
+
+ @get:InputFile
+ @get:PathSensitive(NONE)
+ abstract val legend: RegularFileProperty
+
+ @get:OutputFile
+ abstract val output: RegularFileProperty
+
+ override fun getDescription() = "Updates Markdown file with the corresponding dependency graph."
+
+ @TaskAction
+ operator fun invoke() = with(output.get().asFile) {
+ if (!exists()) {
+ createNewFile()
+ writeText(
+ """
+ # `${projectPath.get()}`
+
+ ## Module dependency graph
+
+
+
+ """.trimIndent(),
+ )
+ }
+ val mermaid = input.get().asFile.readText().trimTrailingNewLines()
+ val legend = legend.get().asFile.readText().trimTrailingNewLines()
+ val regex = """()(.*?)()""".toRegex(DOT_MATCHES_ALL)
+ val text = readText().replace(regex) { match ->
+ val (start, _, end) = match.destructured
+ """
+ |$start
+ |```mermaid
+ |$mermaid
+ |```
+ |
+ |📋 Graph legend
+ |
+ |```mermaid
+ |$legend
+ |```
+ |
+ |
+ |$end
+ """.trimMargin()
+ }
+ writeText(text)
+ }
+
+ private fun String.trimTrailingNewLines() = lines()
+ .dropLastWhile(String::isBlank)
+ .joinToString(System.lineSeparator())
+}
diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt
index 8a41dbfcc..2ac96e556 100644
--- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt
+++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt
@@ -23,7 +23,6 @@ import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
-import org.gradle.kotlin.dsl.provideDelegate
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension
@@ -39,7 +38,7 @@ internal fun Project.configureKotlinAndroid(
compileSdk = 35
defaultConfig {
- minSdk = 21
+ minSdk = 23
}
compileOptions {
@@ -78,14 +77,16 @@ internal fun Project.configureKotlinJvm() {
private inline fun Project.configureKotlin() = configure {
// Treat all Kotlin warnings as errors (disabled by default)
// Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties
- val warningsAsErrors: String? by project
+ val warningsAsErrors = providers.gradleProperty("warningsAsErrors").map {
+ it.toBoolean()
+ }.orElse(false)
when (this) {
is KotlinAndroidProjectExtension -> compilerOptions
is KotlinJvmProjectExtension -> compilerOptions
else -> TODO("Unsupported project extension $this ${T::class}")
}.apply {
jvmTarget = JvmTarget.JVM_11
- allWarningsAsErrors = warningsAsErrors.toBoolean()
+ allWarningsAsErrors = warningsAsErrors
freeCompilerArgs.add(
// Enable experimental coroutines APIs, including Flow
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
diff --git a/build.gradle.kts b/build.gradle.kts
index b7989bab4..594f7f92e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -14,28 +14,6 @@
* limitations under the License.
*/
-buildscript {
- repositories {
- google {
- content {
- includeGroupByRegex("com\\.android.*")
- includeGroupByRegex("com\\.google.*")
- includeGroupByRegex("androidx.*")
- }
- }
- mavenCentral()
-
- // This is used only for internal Google builds.
- maven { url = uri("../nowinandroid-prebuilts/m2repository") }
- }
- dependencies {
- classpath(libs.google.oss.licenses.plugin) {
- exclude(group = "com.google.protobuf")
- }
- }
-
-}
-
/*
* By listing all the plugins used throughout all subprojects in the root project build script, it
* ensures that the build script classpath remains the same for all projects. This avoids potential
@@ -58,7 +36,7 @@ plugins {
alias(libs.plugins.hilt) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.roborazzi) apply false
- alias(libs.plugins.secrets) apply false
+ alias(libs.plugins.google.osslicenses) apply false
alias(libs.plugins.room) apply false
- alias(libs.plugins.module.graph) apply true // Plugin applied to allow module graph generation
+ alias(libs.plugins.nowinandroid.root)
}
diff --git a/core/analytics/README.md b/core/analytics/README.md
index d2bcd1ea7..f6dab3bcc 100644
--- a/core/analytics/README.md
+++ b/core/analytics/README.md
@@ -1,3 +1,48 @@
-# :core:analytics module
-## Dependency graph
-
+# `:core:analytics`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/common/README.md b/core/common/README.md
index 96558bcc6..2f3865a8e 100644
--- a/core/common/README.md
+++ b/core/common/README.md
@@ -1,3 +1,48 @@
-# :core:common module
-## Dependency graph
-
+# `:core:common`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::jvm-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/data-test/README.md b/core/data-test/README.md
index 977ee10e4..b36f5b66d 100644
--- a/core/data-test/README.md
+++ b/core/data-test/README.md
@@ -1,3 +1,73 @@
-# :core:data-test module
-## Dependency graph
-
+# `:core:data-test`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:data-test[data-test]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:data-test --> :core:data
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/data/README.md b/core/data/README.md
index 5d30f1638..0b84940d2 100644
--- a/core/data/README.md
+++ b/core/data/README.md
@@ -1,3 +1,71 @@
-# :core:data module
-## Dependency graph
-
+# `:core:data`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts
index 8c839fa8e..c47d4ee58 100644
--- a/core/data/build.gradle.kts
+++ b/core/data/build.gradle.kts
@@ -22,11 +22,7 @@ plugins {
android {
namespace = "com.google.samples.apps.nowinandroid.core.data"
- testOptions {
- unitTests {
- isIncludeAndroidResources = true
- }
- }
+ testOptions.unitTests.isIncludeAndroidResources = true
}
dependencies {
diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt
index c7dfd99d0..ac2b5c8af 100644
--- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt
+++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt
@@ -24,9 +24,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.model.data.UserData
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
import kotlinx.datetime.Clock
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
import org.junit.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
class UserNewsResourceTest {
diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt
index a3e373918..1c3ec012a 100644
--- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt
+++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt
@@ -36,7 +36,7 @@ class TestNewsResourceDao : NewsResourceDao {
private val entitiesStateFlow = MutableStateFlow(emptyList())
- internal var topicCrossReferences: List = listOf()
+ internal var topicCrossReferences: List = emptyList()
override fun getNewsResources(
useFilterTopicIds: Boolean,
diff --git a/core/database/README.md b/core/database/README.md
index 855eab53e..d050c6dbc 100644
--- a/core/database/README.md
+++ b/core/database/README.md
@@ -1,3 +1,51 @@
-# :core:database module
-## Dependency graph
-
+# `:core:database`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:database[database]:::android-library
+ :core:model[model]:::jvm-library
+ end
+
+ :core:database --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt b/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt
index 9450a24ad..5aed1d1c2 100644
--- a/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt
+++ b/core/database/src/main/kotlin/com/google/samples/apps/nowinandroid/core/database/model/NewsResourceEntity.kt
@@ -49,5 +49,5 @@ fun NewsResourceEntity.asExternalModel() = NewsResource(
headerImageUrl = headerImageUrl,
publishDate = publishDate,
type = type,
- topics = listOf(),
+ topics = emptyList(),
)
diff --git a/core/datastore-proto/README.md b/core/datastore-proto/README.md
index 19ed58239..859e39756 100644
--- a/core/datastore-proto/README.md
+++ b/core/datastore-proto/README.md
@@ -1,3 +1,48 @@
-# :core:datastore-proto module
-## Dependency graph
-
+# `:core:datastore-proto`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:datastore-proto[datastore-proto]:::android-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/datastore-test/README.md b/core/datastore-test/README.md
index 99cf13f1f..6de8718e8 100644
--- a/core/datastore-test/README.md
+++ b/core/datastore-test/README.md
@@ -1,3 +1,58 @@
-# :core:datastore-test module
-## Dependency graph
-
+# `:core:datastore-test`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::jvm-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:datastore-test[datastore-test]:::android-library
+ :core:model[model]:::jvm-library
+ end
+
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:datastore-test -.-> :core:common
+ :core:datastore-test -.-> :core:datastore
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/datastore/README.md b/core/datastore/README.md
index 4785c5885..744f60f43 100644
--- a/core/datastore/README.md
+++ b/core/datastore/README.md
@@ -1,3 +1,55 @@
-# :core:datastore module
-## Dependency graph
-
+# `:core:datastore`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::jvm-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:model[model]:::jvm-library
+ end
+
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/designsystem/README.md b/core/designsystem/README.md
index d1778cb14..3194165fd 100644
--- a/core/designsystem/README.md
+++ b/core/designsystem/README.md
@@ -1,3 +1,48 @@
-# :core:designsystem module
-## Dependency graph
-
+# `:core:designsystem`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:designsystem[designsystem]:::android-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts
index aac2ddb8f..8a138082b 100644
--- a/core/designsystem/build.gradle.kts
+++ b/core/designsystem/build.gradle.kts
@@ -22,6 +22,7 @@ plugins {
android {
namespace = "com.google.samples.apps.nowinandroid.core.designsystem"
+ testOptions.unitTests.isIncludeAndroidResources = true
}
dependencies {
diff --git a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt
index f85c65677..ece8e0259 100644
--- a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt
+++ b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt
@@ -45,7 +45,7 @@ fun NiaTopAppBar(
actionIcon: ImageVector,
actionIconContentDescription: String,
modifier: Modifier = Modifier,
- colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors(),
+ colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(),
onNavigationClick: () -> Unit = {},
onActionClick: () -> Unit = {},
) {
diff --git a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt
index 82d769863..289f09ce4 100644
--- a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt
+++ b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2025 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.
@@ -22,6 +22,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.text.style.LineHeightStyle.Alignment
import androidx.compose.ui.text.style.LineHeightStyle.Trim
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.sp
/**
@@ -33,30 +35,40 @@ internal val NiaTypography = Typography(
fontSize = 57.sp,
lineHeight = 64.sp,
letterSpacing = (-0.25).sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
displayMedium = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 45.sp,
lineHeight = 52.sp,
letterSpacing = 0.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
displaySmall = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 36.sp,
lineHeight = 44.sp,
letterSpacing = 0.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
headlineLarge = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 32.sp,
lineHeight = 40.sp,
letterSpacing = 0.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
headlineMedium = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 28.sp,
lineHeight = 36.sp,
letterSpacing = 0.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
headlineSmall = TextStyle(
fontWeight = FontWeight.Normal,
@@ -67,6 +79,8 @@ internal val NiaTypography = Typography(
alignment = Alignment.Bottom,
trim = Trim.None,
),
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
titleLarge = TextStyle(
fontWeight = FontWeight.Bold,
@@ -77,18 +91,24 @@ internal val NiaTypography = Typography(
alignment = Alignment.Bottom,
trim = Trim.LastLineBottom,
),
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
titleMedium = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
lineHeight = 24.sp,
letterSpacing = 0.1.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
titleSmall = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
lineHeight = 20.sp,
letterSpacing = 0.1.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
// Default text style
bodyLarge = TextStyle(
@@ -100,18 +120,24 @@ internal val NiaTypography = Typography(
alignment = Alignment.Center,
trim = Trim.None,
),
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
bodyMedium = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 14.sp,
lineHeight = 20.sp,
letterSpacing = 0.25.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
bodySmall = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 12.sp,
lineHeight = 16.sp,
letterSpacing = 0.4.sp,
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
// Used for Button
labelLarge = TextStyle(
@@ -123,6 +149,8 @@ internal val NiaTypography = Typography(
alignment = Alignment.Center,
trim = Trim.LastLineBottom,
),
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
// Used for Navigation items
labelMedium = TextStyle(
@@ -134,6 +162,8 @@ internal val NiaTypography = Typography(
alignment = Alignment.Center,
trim = Trim.LastLineBottom,
),
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
// Used for Tag
labelSmall = TextStyle(
@@ -145,5 +175,7 @@ internal val NiaTypography = Typography(
alignment = Alignment.Center,
trim = Trim.LastLineBottom,
),
+ textDirection = TextDirection.Ltr,
+ textAlign = TextAlign.Left,
),
)
diff --git a/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_androidTheme_notDynamic.png
index d217e1116..86fce156f 100644
Binary files a/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_dynamic.png
index d217e1116..86fce156f 100644
Binary files a/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_notDynamic.png
index d217e1116..86fce156f 100644
Binary files a/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/IconButton/IconButton_dark_defaultTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/IconButton/IconButton_light_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/IconButton/IconButton_light_androidTheme_notDynamic.png
index d217e1116..86fce156f 100644
Binary files a/core/designsystem/src/test/screenshots/IconButton/IconButton_light_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/IconButton/IconButton_light_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_dynamic.png
index d217e1116..86fce156f 100644
Binary files a/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_notDynamic.png
index d217e1116..86fce156f 100644
Binary files a/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/IconButton/IconButton_light_defaultTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_1000.png b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_1000.png
index 316d899d2..b88567a42 100644
Binary files a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_1000.png and b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_1000.png differ
diff --git a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_115.png b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_115.png
index 4705b9beb..3bca04850 100644
Binary files a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_115.png and b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_115.png differ
diff --git a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_20.png b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_20.png
index 203a2ea2e..a209731e4 100644
Binary files a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_20.png and b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_20.png differ
diff --git a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_724.png b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_724.png
index 50a822621..d5e563544 100644
Binary files a/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_724.png and b/core/designsystem/src/test/screenshots/LoadingWheel/LoadingWheel_animation_724.png differ
diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_androidTheme_notDynamic.png
index 5e2a27c65..0940873c6 100644
Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_dynamic.png
index efb1f8756..3575ac09f 100644
Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_notDynamic.png
index 160a72d61..44bb3b5c6 100644
Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_dark_defaultTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png
index b4b4842c3..16df296d5 100644
Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_fontScale2.png differ
diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_light_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_light_androidTheme_notDynamic.png
index c3200091b..9409b984d 100644
Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_light_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_light_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_dynamic.png
index 877c45cd0..233f86b35 100644
Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_notDynamic.png
index 9fd6fc843..590c878a0 100644
Binary files a/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Navigation/Navigation_light_defaultTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Tag/Tag_dark_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Tag/Tag_dark_androidTheme_notDynamic.png
index 2a065eb57..4897d2a70 100644
Binary files a/core/designsystem/src/test/screenshots/Tag/Tag_dark_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Tag/Tag_dark_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_dynamic.png
index c532a307e..2e5bcbbbd 100644
Binary files a/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_notDynamic.png
index 61d3321b8..dcb18ab95 100644
Binary files a/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Tag/Tag_dark_defaultTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Tag/Tag_fontScale2.png b/core/designsystem/src/test/screenshots/Tag/Tag_fontScale2.png
index 7cfdbb2a7..59a1aabd0 100644
Binary files a/core/designsystem/src/test/screenshots/Tag/Tag_fontScale2.png and b/core/designsystem/src/test/screenshots/Tag/Tag_fontScale2.png differ
diff --git a/core/designsystem/src/test/screenshots/Tag/Tag_light_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Tag/Tag_light_androidTheme_notDynamic.png
index fc29b6e11..c9f6523f3 100644
Binary files a/core/designsystem/src/test/screenshots/Tag/Tag_light_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Tag/Tag_light_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_dynamic.png
index ed825ba71..fb1023ece 100644
Binary files a/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_notDynamic.png
index 8acc6b0a8..224f34303 100644
Binary files a/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/Tag/Tag_light_defaultTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_androidTheme_notDynamic.png
index 3617feab1..727910474 100644
Binary files a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_dynamic.png
index 418e0f88d..2c09fedc3 100644
Binary files a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_notDynamic.png
index 921698d22..cd52d5494 100644
Binary files a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_dark_defaultTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_fontScale2.png b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_fontScale2.png
index 497561ef7..9e275f470 100644
Binary files a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_fontScale2.png and b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_fontScale2.png differ
diff --git a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_androidTheme_notDynamic.png b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_androidTheme_notDynamic.png
index 4988252e5..64034e77e 100644
Binary files a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_androidTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_androidTheme_notDynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_dynamic.png b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_dynamic.png
index 6ab40ebf9..24116fcd2 100644
Binary files a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_dynamic.png and b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_dynamic.png differ
diff --git a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_notDynamic.png b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_notDynamic.png
index d9d014a18..3f01e8743 100644
Binary files a/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_notDynamic.png and b/core/designsystem/src/test/screenshots/TopAppBar/TopAppBar_light_defaultTheme_notDynamic.png differ
diff --git a/core/domain/README.md b/core/domain/README.md
index cc6905846..b23877337 100644
--- a/core/domain/README.md
+++ b/core/domain/README.md
@@ -1,3 +1,74 @@
-# :core:domain module
-## Dependency graph
-
+# `:core:domain`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:domain[domain]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:domain --> :core:data
+ :core:domain --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/model/README.md b/core/model/README.md
index efd0eec76..9cd7659a8 100644
--- a/core/model/README.md
+++ b/core/model/README.md
@@ -1,3 +1,48 @@
-# :core:model module
-## Dependency graph
-
+# `:core:model`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:model[model]:::jvm-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/network/README.md b/core/network/README.md
index 516aa2d38..d52be6270 100644
--- a/core/network/README.md
+++ b/core/network/README.md
@@ -1,3 +1,53 @@
-# :core:network module
-## Dependency graph
-
+# `:core:network`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::jvm-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ end
+
+ :core:network --> :core:common
+ :core:network --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts
index d12482a56..edc28ea23 100644
--- a/core/network/build.gradle.kts
+++ b/core/network/build.gradle.kts
@@ -14,12 +14,15 @@
* limitations under the License.
*/
+import com.android.build.api.variant.BuildConfigField
+import java.io.StringReader
+import java.util.Properties
+
plugins {
alias(libs.plugins.nowinandroid.android.library)
alias(libs.plugins.nowinandroid.android.library.jacoco)
alias(libs.plugins.nowinandroid.hilt)
id("kotlinx-serialization")
- id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
}
android {
@@ -27,15 +30,7 @@ android {
buildConfig = true
}
namespace = "com.google.samples.apps.nowinandroid.core.network"
- testOptions {
- unitTests {
- isIncludeAndroidResources = true
- }
- }
-}
-
-secrets {
- defaultPropertiesFileName = "secrets.defaults.properties"
+ testOptions.unitTests.isIncludeAndroidResources = true
}
dependencies {
@@ -52,3 +47,19 @@ dependencies {
testImplementation(libs.kotlinx.coroutines.test)
}
+
+val backendUrl = providers.fileContents(
+ isolated.rootProject.projectDirectory.file("local.properties")
+).asText.map { text ->
+ val properties = Properties()
+ properties.load(StringReader(text))
+ properties["BACKEND_URL"]
+}.orElse("http://example.com")
+
+androidComponents {
+ onVariants {
+ it.buildConfigFields!!.put("BACKEND_URL", backendUrl.map { value ->
+ BuildConfigField(type = "String", value = """"$value"""", comment = null)
+ })
+ }
+}
diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt
index 7b66af796..92e8e9ffa 100644
--- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt
+++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/model/NetworkNewsResource.kt
@@ -16,6 +16,7 @@
package com.google.samples.apps.nowinandroid.core.network.model
+import android.annotation.SuppressLint
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
@@ -23,6 +24,7 @@ import kotlinx.serialization.Serializable
/**
* Network representation of [NewsResource] when fetched from /newsresources
*/
+@SuppressLint("UnsafeOptInUsageError")
@Serializable
data class NetworkNewsResource(
val id: String,
@@ -32,5 +34,5 @@ data class NetworkNewsResource(
val headerImageUrl: String,
val publishDate: Instant,
val type: String,
- val topics: List = listOf(),
+ val topics: List = emptyList(),
)
diff --git a/core/notifications/README.md b/core/notifications/README.md
index 8f5607bdf..d184a6672 100644
--- a/core/notifications/README.md
+++ b/core/notifications/README.md
@@ -1,3 +1,53 @@
-# :core:notifications module
-## Dependency graph
-
+# `:core:notifications`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::jvm-library
+ :core:model[model]:::jvm-library
+ :core:notifications[notifications]:::android-library
+ end
+
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/screenshot-testing/README.md b/core/screenshot-testing/README.md
index 9bd4f1f9c..793651023 100644
--- a/core/screenshot-testing/README.md
+++ b/core/screenshot-testing/README.md
@@ -1,3 +1,51 @@
-# :core:screenshot-testing module
-## Dependency graph
-
+# `:core:screenshot-testing`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:designsystem[designsystem]:::android-library
+ :core:screenshot-testing[screenshot-testing]:::android-library
+ end
+
+ :core:screenshot-testing -.-> :core:designsystem
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/testing/README.md b/core/testing/README.md
index 5a35d379b..d5925b1a5 100644
--- a/core/testing/README.md
+++ b/core/testing/README.md
@@ -1,3 +1,77 @@
-# :core:testing module
-## Dependency graph
-
+# `:core:testing`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:testing[testing]:::android-library
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:testing --> :core:analytics
+ :core:testing --> :core:common
+ :core:testing --> :core:data
+ :core:testing --> :core:model
+ :core:testing --> :core:notifications
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/ui/README.md b/core/ui/README.md
index 38e514d01..c6b365553 100644
--- a/core/ui/README.md
+++ b/core/ui/README.md
@@ -1,3 +1,55 @@
-# :core:ui module
-## Dependency graph
-
+# `:core:ui`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:model[model]:::jvm-library
+ :core:ui[ui]:::android-library
+ end
+
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md
index a9766c68d..5cda61b69 100644
--- a/docs/ModularizationLearningJourney.md
+++ b/docs/ModularizationLearningJourney.md
@@ -85,7 +85,57 @@ how you can organize your project. In general, you should strive for low couplin
## Types of modules in Now in Android
-
+```mermaid
+graph TB
+ subgraph :core
+ direction TB
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:topic[topic]:::android-feature
+ :feature:foryou[foryou]:::android-feature
+ :feature:interests[interests]:::android-feature
+ :feature:foo[...]:::android-feature
+
+ end
+ :app[app]:::android-application
+
+ :app -.-> :feature:foryou
+ :app -.-> :feature:interests
+ :app -.-> :feature:topic
+ :core:data ---> :core:database
+ :core:data ---> :core:network
+ :core:database ---> :core:model
+ :core:network ---> :core:model
+ :core:ui ---> :core:model
+ :feature:topic -.-> :core:data
+ :feature:topic -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application:::android-application -. implementation .-> feature:::android-feature
+ library:::android-library -- api --> jvm:::jvm-library
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
**Top tip**: A module graph (shown above) can be useful during modularization planning for
visualizing dependencies between modules.
@@ -233,6 +283,9 @@ Using the above modularization strategy, the Now in Android app has the followin
+Each module has its own `README.md` file containing a module graph (e.g. [`:app` module graph](../app/README.md#module-dependency-graph)).
+When modules dependencies change, module graphs are automatically updated by the [Build.yaml](../.github/workflows/Build.yaml) workflow.
+You can also manually update the graphs by running the `graphUpdate` task.
## Modularization in Now in Android
diff --git a/docs/images/graphs/dep_graph_app.svg b/docs/images/graphs/dep_graph_app.svg
deleted file mode 100644
index 8e5d9d429..000000000
--- a/docs/images/graphs/dep_graph_app.svg
+++ /dev/null
@@ -1,305 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_app_nia_catalog.svg b/docs/images/graphs/dep_graph_app_nia_catalog.svg
deleted file mode 100644
index 151ee63ad..000000000
--- a/docs/images/graphs/dep_graph_app_nia_catalog.svg
+++ /dev/null
@@ -1,45 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_analytics.svg b/docs/images/graphs/dep_graph_core_analytics.svg
deleted file mode 100644
index 45f1c1eb0..000000000
--- a/docs/images/graphs/dep_graph_core_analytics.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_common.svg b/docs/images/graphs/dep_graph_core_common.svg
deleted file mode 100644
index 91033eaa0..000000000
--- a/docs/images/graphs/dep_graph_core_common.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_data.svg b/docs/images/graphs/dep_graph_core_data.svg
deleted file mode 100644
index ab91bafb2..000000000
--- a/docs/images/graphs/dep_graph_core_data.svg
+++ /dev/null
@@ -1,97 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_data_test.svg b/docs/images/graphs/dep_graph_core_data_test.svg
deleted file mode 100644
index b9736c859..000000000
--- a/docs/images/graphs/dep_graph_core_data_test.svg
+++ /dev/null
@@ -1,105 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_database.svg b/docs/images/graphs/dep_graph_core_database.svg
deleted file mode 100644
index e82d46436..000000000
--- a/docs/images/graphs/dep_graph_core_database.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_datastore.svg b/docs/images/graphs/dep_graph_core_datastore.svg
deleted file mode 100644
index f7502e55b..000000000
--- a/docs/images/graphs/dep_graph_core_datastore.svg
+++ /dev/null
@@ -1,33 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_datastore_proto.svg b/docs/images/graphs/dep_graph_core_datastore_proto.svg
deleted file mode 100644
index 7fcfb8358..000000000
--- a/docs/images/graphs/dep_graph_core_datastore_proto.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_datastore_test.svg b/docs/images/graphs/dep_graph_core_datastore_test.svg
deleted file mode 100644
index 37521a05f..000000000
--- a/docs/images/graphs/dep_graph_core_datastore_test.svg
+++ /dev/null
@@ -1,45 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_designsystem.svg b/docs/images/graphs/dep_graph_core_designsystem.svg
deleted file mode 100644
index 737140876..000000000
--- a/docs/images/graphs/dep_graph_core_designsystem.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_domain.svg b/docs/images/graphs/dep_graph_core_domain.svg
deleted file mode 100644
index fe3740d2f..000000000
--- a/docs/images/graphs/dep_graph_core_domain.svg
+++ /dev/null
@@ -1,109 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_model.svg b/docs/images/graphs/dep_graph_core_model.svg
deleted file mode 100644
index 125684a08..000000000
--- a/docs/images/graphs/dep_graph_core_model.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_network.svg b/docs/images/graphs/dep_graph_core_network.svg
deleted file mode 100644
index 3022a86ee..000000000
--- a/docs/images/graphs/dep_graph_core_network.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_notifications.svg b/docs/images/graphs/dep_graph_core_notifications.svg
deleted file mode 100644
index d96d28769..000000000
--- a/docs/images/graphs/dep_graph_core_notifications.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_screenshot_testing.svg b/docs/images/graphs/dep_graph_core_screenshot_testing.svg
deleted file mode 100644
index a7d58b0ea..000000000
--- a/docs/images/graphs/dep_graph_core_screenshot_testing.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_testing.svg b/docs/images/graphs/dep_graph_core_testing.svg
deleted file mode 100644
index d441858e5..000000000
--- a/docs/images/graphs/dep_graph_core_testing.svg
+++ /dev/null
@@ -1,121 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_core_ui.svg b/docs/images/graphs/dep_graph_core_ui.svg
deleted file mode 100644
index 2cd972357..000000000
--- a/docs/images/graphs/dep_graph_core_ui.svg
+++ /dev/null
@@ -1,33 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_feature_bookmarks.svg b/docs/images/graphs/dep_graph_feature_bookmarks.svg
deleted file mode 100644
index 0391eb39c..000000000
--- a/docs/images/graphs/dep_graph_feature_bookmarks.svg
+++ /dev/null
@@ -1,133 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_feature_foryou.svg b/docs/images/graphs/dep_graph_feature_foryou.svg
deleted file mode 100644
index 63a154a87..000000000
--- a/docs/images/graphs/dep_graph_feature_foryou.svg
+++ /dev/null
@@ -1,149 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_feature_interests.svg b/docs/images/graphs/dep_graph_feature_interests.svg
deleted file mode 100644
index 2de1fc61f..000000000
--- a/docs/images/graphs/dep_graph_feature_interests.svg
+++ /dev/null
@@ -1,149 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_feature_search.svg b/docs/images/graphs/dep_graph_feature_search.svg
deleted file mode 100644
index 7f8f29777..000000000
--- a/docs/images/graphs/dep_graph_feature_search.svg
+++ /dev/null
@@ -1,149 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_feature_settings.svg b/docs/images/graphs/dep_graph_feature_settings.svg
deleted file mode 100644
index 3f0d35df2..000000000
--- a/docs/images/graphs/dep_graph_feature_settings.svg
+++ /dev/null
@@ -1,133 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_feature_topic.svg b/docs/images/graphs/dep_graph_feature_topic.svg
deleted file mode 100644
index b7c7dd26c..000000000
--- a/docs/images/graphs/dep_graph_feature_topic.svg
+++ /dev/null
@@ -1,133 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_sync_sync_test.svg b/docs/images/graphs/dep_graph_sync_sync_test.svg
deleted file mode 100644
index 7a083ba54..000000000
--- a/docs/images/graphs/dep_graph_sync_sync_test.svg
+++ /dev/null
@@ -1,121 +0,0 @@
-
diff --git a/docs/images/graphs/dep_graph_sync_work.svg b/docs/images/graphs/dep_graph_sync_work.svg
deleted file mode 100644
index c649f2397..000000000
--- a/docs/images/graphs/dep_graph_sync_work.svg
+++ /dev/null
@@ -1,109 +0,0 @@
-
diff --git a/docs/images/modularization-graph.drawio.png b/docs/images/modularization-graph.drawio.png
deleted file mode 100644
index fb5bc375b..000000000
Binary files a/docs/images/modularization-graph.drawio.png and /dev/null differ
diff --git a/feature/bookmarks/README.md b/feature/bookmarks/README.md
index 54cbf91d0..2a2ebe214 100644
--- a/feature/bookmarks/README.md
+++ b/feature/bookmarks/README.md
@@ -1,3 +1,83 @@
-# :feature:bookmarks module
-## Dependency graph
-
+# `:feature:bookmarks`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:bookmarks[bookmarks]:::android-feature
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:bookmarks -.-> :core:data
+ :feature:bookmarks -.-> :core:designsystem
+ :feature:bookmarks -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/foryou/README.md b/feature/foryou/README.md
index 0f08cb827..7cd42863d 100644
--- a/feature/foryou/README.md
+++ b/feature/foryou/README.md
@@ -1,3 +1,88 @@
-# :feature:foryou module
-## Dependency graph
-
+# `:feature:foryou`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:domain[domain]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:foryou[foryou]:::android-feature
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:domain --> :core:data
+ :core:domain --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:foryou -.-> :core:data
+ :feature:foryou -.-> :core:designsystem
+ :feature:foryou -.-> :core:domain
+ :feature:foryou -.-> :core:notifications
+ :feature:foryou -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/foryou/build.gradle.kts b/feature/foryou/build.gradle.kts
index 59f6844cf..de1af7540 100644
--- a/feature/foryou/build.gradle.kts
+++ b/feature/foryou/build.gradle.kts
@@ -23,6 +23,7 @@ plugins {
android {
namespace = "com.google.samples.apps.nowinandroid.feature.foryou"
+ testOptions.unitTests.isIncludeAndroidResources = true
}
dependencies {
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenLoading_foldable.png b/feature/foryou/src/test/screenshots/ForYouScreenLoading_foldable.png
index a699345c2..538c9032c 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenLoading_foldable.png and b/feature/foryou/src/test/screenshots/ForYouScreenLoading_foldable.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenLoading_phone.png b/feature/foryou/src/test/screenshots/ForYouScreenLoading_phone.png
index 30c8fdad7..afd7dd708 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenLoading_phone.png and b/feature/foryou/src/test/screenshots/ForYouScreenLoading_phone.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenLoading_tablet.png b/feature/foryou/src/test/screenshots/ForYouScreenLoading_tablet.png
index f54966dbc..1c197e8f0 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenLoading_tablet.png and b/feature/foryou/src/test/screenshots/ForYouScreenLoading_tablet.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_foldable.png b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_foldable.png
index 3990aee3f..e4ecf6d95 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_foldable.png and b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_foldable.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_tablet.png b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_tablet.png
index 3b735462f..53891bdc1 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_tablet.png and b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_tablet.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_foldable.png b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_foldable.png
index 0da7e19ac..ba669e8f8 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_foldable.png and b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_foldable.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_phone.png b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_phone.png
index a7b775315..1498f9b7b 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_phone.png and b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_phone.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_tablet.png b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_tablet.png
index e7f0cc050..e92ae0481 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_tablet.png and b/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_tablet.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_foldable.png b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_foldable.png
index f5d68fce2..3ae1bee94 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_foldable.png and b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_foldable.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone.png b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone.png
index b04c632c3..0938678b2 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone.png and b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone_dark.png b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone_dark.png
index 6c4d66b28..084d031a5 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone_dark.png and b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone_dark.png differ
diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_tablet.png b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_tablet.png
index f7c20a890..35f59e54c 100644
Binary files a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_tablet.png and b/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_tablet.png differ
diff --git a/feature/interests/README.md b/feature/interests/README.md
index 90a4fbc9c..529f8abe7 100644
--- a/feature/interests/README.md
+++ b/feature/interests/README.md
@@ -1,3 +1,87 @@
-# :feature:interests module
-## Dependency graph
-
+# `:feature:interests`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:domain[domain]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:interests[interests]:::android-feature
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:domain --> :core:data
+ :core:domain --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:interests -.-> :core:data
+ :feature:interests -.-> :core:designsystem
+ :feature:interests -.-> :core:domain
+ :feature:interests -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt b/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt
index 468550878..9b18ac89b 100644
--- a/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt
+++ b/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt
@@ -38,7 +38,7 @@ import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent
fun InterestsRoute(
onTopicClick: (String) -> Unit,
modifier: Modifier = Modifier,
- highlightSelectedTopic: Boolean = false,
+ shouldHighlightSelectedTopic: Boolean = false,
viewModel: InterestsViewModel = hiltViewModel(),
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
@@ -50,7 +50,7 @@ fun InterestsRoute(
viewModel.onTopicClick(it)
onTopicClick(it)
},
- highlightSelectedTopic = highlightSelectedTopic,
+ shouldHighlightSelectedTopic = shouldHighlightSelectedTopic,
modifier = modifier,
)
}
@@ -61,7 +61,7 @@ internal fun InterestsScreen(
followTopic: (String, Boolean) -> Unit,
onTopicClick: (String) -> Unit,
modifier: Modifier = Modifier,
- highlightSelectedTopic: Boolean = false,
+ shouldHighlightSelectedTopic: Boolean = false,
) {
Column(
modifier = modifier,
@@ -70,7 +70,6 @@ internal fun InterestsScreen(
when (uiState) {
InterestsUiState.Loading ->
NiaLoadingWheel(
- modifier = modifier,
contentDesc = stringResource(id = R.string.feature_interests_loading),
)
@@ -80,8 +79,7 @@ internal fun InterestsScreen(
onTopicClick = onTopicClick,
onFollowButtonClick = followTopic,
selectedTopicId = uiState.selectedTopicId,
- highlightSelectedTopic = highlightSelectedTopic,
- modifier = modifier,
+ shouldHighlightSelectedTopic = shouldHighlightSelectedTopic,
)
is InterestsUiState.Empty -> InterestsEmptyScreen()
diff --git a/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/TabContent.kt b/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/TabContent.kt
index 83058c12e..133c2bedd 100644
--- a/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/TabContent.kt
+++ b/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/TabContent.kt
@@ -49,7 +49,7 @@ fun TopicsTabContent(
modifier: Modifier = Modifier,
withBottomSpacer: Boolean = true,
selectedTopicId: String? = null,
- highlightSelectedTopic: Boolean = false,
+ shouldHighlightSelectedTopic: Boolean = false,
) {
Box(
modifier = modifier
@@ -66,7 +66,7 @@ fun TopicsTabContent(
topics.forEach { followableTopic ->
val topicId = followableTopic.topic.id
item(key = topicId) {
- val isSelected = highlightSelectedTopic && topicId == selectedTopicId
+ val isSelected = shouldHighlightSelectedTopic && topicId == selectedTopicId
InterestsItem(
name = followableTopic.topic.name,
following = followableTopic.isFollowed,
@@ -75,6 +75,7 @@ fun TopicsTabContent(
onClick = { onTopicClick(topicId) },
onFollowButtonClick = { onFollowButtonClick(topicId, it) },
isSelected = isSelected,
+ modifier = Modifier.fillMaxWidth(),
)
}
}
diff --git a/feature/search/README.md b/feature/search/README.md
index e205970f0..d8160a627 100644
--- a/feature/search/README.md
+++ b/feature/search/README.md
@@ -1,3 +1,87 @@
-# :feature:search module
-## Dependency graph
-
+# `:feature:search`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:domain[domain]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:search[search]:::android-feature
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:domain --> :core:data
+ :core:domain --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:search -.-> :core:data
+ :feature:search -.-> :core:designsystem
+ :feature:search -.-> :core:domain
+ :feature:search -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/settings/README.md b/feature/settings/README.md
index 7a4df04fe..26c65eba0 100644
--- a/feature/settings/README.md
+++ b/feature/settings/README.md
@@ -1,3 +1,83 @@
-# :feature:settings module
-## Dependency graph
-
+# `:feature:settings`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:settings[settings]:::android-feature
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:settings -.-> :core:data
+ :feature:settings -.-> :core:designsystem
+ :feature:settings -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/topic/README.md b/feature/topic/README.md
index 84588929c..8f88be578 100644
--- a/feature/topic/README.md
+++ b/feature/topic/README.md
@@ -1,3 +1,83 @@
-# :feature:topic module
-## Dependency graph
-
+# `:feature:topic`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:designsystem[designsystem]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ :core:ui[ui]:::android-library
+ end
+ subgraph :feature
+ direction TB
+ :feature:topic[topic]:::android-feature
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :core:ui --> :core:analytics
+ :core:ui --> :core:designsystem
+ :core:ui --> :core:model
+ :feature:topic -.-> :core:data
+ :feature:topic -.-> :core:designsystem
+ :feature:topic -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt
index ba8baad14..8865da463 100644
--- a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt
+++ b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt
@@ -16,10 +16,8 @@
package com.google.samples.apps.nowinandroid.feature.topic
-import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import androidx.navigation.toRoute
import com.google.samples.apps.nowinandroid.core.data.repository.NewsResourceQuery
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
@@ -29,7 +27,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
import com.google.samples.apps.nowinandroid.core.result.Result
import com.google.samples.apps.nowinandroid.core.result.asResult
-import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicRoute
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
@@ -38,18 +38,14 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
-import javax.inject.Inject
-@HiltViewModel
-class TopicViewModel @Inject constructor(
- savedStateHandle: SavedStateHandle,
+@HiltViewModel(assistedFactory = TopicViewModel.Factory::class)
+class TopicViewModel @AssistedInject constructor(
private val userDataRepository: UserDataRepository,
topicsRepository: TopicsRepository,
userNewsResourceRepository: UserNewsResourceRepository,
+ @Assisted val topicId: String,
) : ViewModel() {
-
- val topicId = savedStateHandle.toRoute().id
-
val topicUiState: StateFlow = topicUiState(
topicId = topicId,
userDataRepository = userDataRepository,
@@ -89,6 +85,13 @@ class TopicViewModel @Inject constructor(
userDataRepository.setNewsResourceViewed(newsResourceId, viewed)
}
}
+
+ @AssistedFactory
+ interface Factory {
+ fun create(
+ topicId: String,
+ ): TopicViewModel
+ }
}
private fun topicUiState(
diff --git a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt
index fabb82b10..69059c81d 100644
--- a/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt
+++ b/feature/topic/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/navigation/TopicNavigation.kt
@@ -16,11 +16,14 @@
package com.google.samples.apps.nowinandroid.feature.topic.navigation
+import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptionsBuilder
import androidx.navigation.compose.composable
+import androidx.navigation.toRoute
import com.google.samples.apps.nowinandroid.feature.topic.TopicScreen
+import com.google.samples.apps.nowinandroid.feature.topic.TopicViewModel
import kotlinx.serialization.Serializable
@Serializable data class TopicRoute(val id: String)
@@ -36,11 +39,17 @@ fun NavGraphBuilder.topicScreen(
onBackClick: () -> Unit,
onTopicClick: (String) -> Unit,
) {
- composable {
+ composable { entry ->
+ val id = entry.toRoute().id
TopicScreen(
showBackButton = showBackButton,
onBackClick = onBackClick,
onTopicClick = onTopicClick,
+ viewModel = hiltViewModel(
+ key = id,
+ ) { factory ->
+ factory.create(id)
+ },
)
}
}
diff --git a/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt b/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt
index 34f21a59a..58242110d 100644
--- a/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt
+++ b/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt
@@ -16,8 +16,6 @@
package com.google.samples.apps.nowinandroid.feature.topic
-import androidx.lifecycle.SavedStateHandle
-import androidx.navigation.testing.invoke
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
@@ -26,7 +24,6 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepo
import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
-import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicRoute
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
@@ -37,22 +34,13 @@ import kotlinx.datetime.Instant
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
import kotlin.test.assertEquals
import kotlin.test.assertIs
/**
* To learn more about how this test handles Flows created with stateIn, see
* https://developer.android.com/kotlin/flow/test#statein
- *
- * These tests use Robolectric because the subject under test (the ViewModel) uses
- * `SavedStateHandle.toRoute` which has a dependency on `android.os.Bundle`.
- *
- * TODO: Remove Robolectric if/when AndroidX Navigation API is updated to remove Android dependency.
- * * See b/340966212.
*/
-@RunWith(RobolectricTestRunner::class)
class TopicViewModelTest {
@get:Rule
@@ -70,12 +58,10 @@ class TopicViewModelTest {
@Before
fun setup() {
viewModel = TopicViewModel(
- savedStateHandle = SavedStateHandle(
- route = TopicRoute(id = testInputTopics[0].topic.id),
- ),
userDataRepository = userDataRepository,
topicsRepository = topicsRepository,
userNewsResourceRepository = userNewsResourceRepository,
+ topicId = testInputTopics[0].topic.id,
)
}
diff --git a/generateModuleGraphs.sh b/generateModuleGraphs.sh
deleted file mode 100755
index 5307d2932..000000000
--- a/generateModuleGraphs.sh
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2024 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.
-#
-#
-# Script to generate dependency graphs for each of the modules. The --exclude-module parameter can
-# be used to exclude modules which are not part of the root dependency graph (and which, if included
-# would cause the script to fail.
-#
-# Usage: generateModuleGraphs.sh --exclude-module :benchmarks --exclude-module :lint --exclude-module :ui-test-hilt-manifest
-
-# Check if the dot command is available
-if ! command -v dot &> /dev/null
-then
- echo "The 'dot' command is not found. This is required to generate SVGs from the Graphviz files."
- echo "Installation instructions:"
- echo " - On macOS: You can install Graphviz using Homebrew with the command: 'brew install graphviz'"
- echo " - On Ubuntu: You can install Graphviz using APT with the command: 'sudo apt install graphviz'"
- echo " - Others: Visit https://graphviz.org/download/"
- exit 1
-fi
-
-# Check if the svgo command is available
-if ! command -v svgo &> /dev/null
-then
- echo "The 'svgo' command is not found. This is required to cleanup and compress SVGs."
- echo "Installation instructions available at https://github.com/svg/svgo."
- exit 1
-fi
-
-# Check for a version of grep which supports Perl regex.
-# On MacOS the OS installed grep doesn't support Perl regex so check for the existence of the
-# GNU version instead which is prefixed with 'g' to distinguish it from the OS installed version.
- if grep -P "" /dev/null > /dev/null 2>&1; then
- GREP_COMMAND=grep
-elif command -v ggrep &> /dev/null; then
- GREP_COMMAND=ggrep
-else
- echo "You don't have a version of 'grep' installed which supports Perl regular expressions."
- echo "On MacOS you can install one using Homebrew with the command: 'brew install grep'"
- exit 1
-fi
-
-# Initialize an array to store excluded modules
-excluded_modules=()
-
-# Parse command-line arguments for excluded modules
-while [[ $# -gt 0 ]]; do
- case "$1" in
- --exclude-module)
- excluded_modules+=("$2")
- shift # Past argument
- shift # Past value
- ;;
- *)
- echo "Unknown parameter passed: $1"
- exit 1
- ;;
- esac
-done
-
-# Get the module paths
-module_paths=$(${GREP_COMMAND} -oP 'include\("\K[^"]+' settings.gradle.kts)
-
-# Ensure the output directory exists
-mkdir -p docs/images/graphs/
-
-# Function to check and create a README.md for modules which don't have one.
-check_and_create_readme() {
- local module_path="$1"
- local file_name="$2"
-
- local readme_path="${module_path:1}" # Remove leading colon
- readme_path=${readme_path//:/\/} # Replace colons with slashes
- readme_path="${readme_path}/README.md" #Append the filename
-
- # Check if README.md exists and create it if not
- if [[ ! -f "$readme_path" ]]; then
- echo "Creating README.md for ${module_path}"
-
- # Determine the depth of the module based on the number of colons
- local depth=$(awk -F: '{print NF-1}' <<< "${module_path}")
-
- # Construct the relative image path with the correct number of "../"
- local relative_image_path="../"
- for ((i=1; i<$depth; i++)); do
- relative_image_path+="../"
- done
- relative_image_path+="docs/images/graphs/${file_name}.svg"
-
- echo "# ${module_path} module" > "$readme_path"
- echo "## Dependency graph" >> "$readme_path"
- echo "" >> "$readme_path"
- fi
-}
-
-# Loop through each module path
-echo "$module_paths" | while read -r module_path; do
- # Check if the module is in the excluded list
- if [[ ! " ${excluded_modules[@]} " =~ " ${module_path} " ]]; then
- # Derive the filename from the module path
- file_name="dep_graph${module_path//:/_}" # Replace colons with underscores
- file_name="${file_name//-/_}" # Replace dashes with underscores
-
- check_and_create_readme "$module_path" "$file_name"
-
- # Generate the .gv file in a temporary location
- # /dev/null && printf '%s
-' "$PWD" ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -115,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -173,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -206,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 9b42019c7..e509b2dd8 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -70,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/lint/README.md b/lint/README.md
new file mode 100644
index 000000000..24d312242
--- /dev/null
+++ b/lint/README.md
@@ -0,0 +1,45 @@
+# `:lint`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ :lint[lint]:::unknown
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/secrets.defaults.properties b/secrets.defaults.properties
deleted file mode 100644
index 3b5457bd9..000000000
--- a/secrets.defaults.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-## This file provides default values to modules using the secrets-gradle-plugin. It is necessary
-# because the secrets properties file is not under source control so CI builds will fail without
-# default values.
-BACKEND_URL="http://example.com"
\ No newline at end of file
diff --git a/sync/sync-test/README.md b/sync/sync-test/README.md
index 78876290f..69f24aaea 100644
--- a/sync/sync-test/README.md
+++ b/sync/sync-test/README.md
@@ -1,3 +1,81 @@
-# :sync:sync-test module
-## Dependency graph
-
+# `:sync:sync-test`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ end
+ subgraph :sync
+ direction TB
+ :sync:sync-test[sync-test]:::android-library
+ :sync:work[work]:::android-library
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :sync:sync-test -.-> :core:data
+ :sync:sync-test -.-> :sync:work
+ :sync:work -.-> :core:analytics
+ :sync:work -.-> :core:data
+ :sync:work -.-> :core:notifications
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/sync/work/README.md b/sync/work/README.md
index 2fe66d616..91abef4d2 100644
--- a/sync/work/README.md
+++ b/sync/work/README.md
@@ -1,3 +1,78 @@
-# :sync:work module
-## Dependency graph
-
+# `:sync:work`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::jvm-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:datastore-proto[datastore-proto]:::android-library
+ :core:model[model]:::jvm-library
+ :core:network[network]:::android-library
+ :core:notifications[notifications]:::android-library
+ end
+ subgraph :sync
+ direction TB
+ :sync:work[work]:::android-library
+ end
+
+ :core:data -.-> :core:analytics
+ :core:data --> :core:common
+ :core:data --> :core:database
+ :core:data --> :core:datastore
+ :core:data --> :core:network
+ :core:data -.-> :core:notifications
+ :core:database --> :core:model
+ :core:datastore -.-> :core:common
+ :core:datastore --> :core:datastore-proto
+ :core:datastore --> :core:model
+ :core:network --> :core:common
+ :core:network --> :core:model
+ :core:notifications -.-> :core:common
+ :core:notifications --> :core:model
+ :sync:work -.-> :core:analytics
+ :sync:work -.-> :core:data
+ :sync:work -.-> :core:notifications
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/ui-test-hilt-manifest/README.md b/ui-test-hilt-manifest/README.md
new file mode 100644
index 000000000..eb4e4b1f7
--- /dev/null
+++ b/ui-test-hilt-manifest/README.md
@@ -0,0 +1,45 @@
+# `:ui-test-hilt-manifest`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ :ui-test-hilt-manifest[ui-test-hilt-manifest]:::android-library
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+