Merge remote-tracking branch 'origin/main' into gradle-dependencies-cleanup

pull/1856/head
Simon Marquis 2 weeks ago
commit f75a2e1c59

@ -1,58 +0,0 @@
# 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.

@ -0,0 +1 @@
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.

@ -22,7 +22,7 @@ plugins {
alias(libs.plugins.nowinandroid.android.application.jacoco) alias(libs.plugins.nowinandroid.android.application.jacoco)
alias(libs.plugins.nowinandroid.android.application.firebase) alias(libs.plugins.nowinandroid.android.application.firebase)
alias(libs.plugins.nowinandroid.hilt) 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.baselineprofile)
alias(libs.plugins.roborazzi) alias(libs.plugins.roborazzi)
alias(libs.plugins.kotlin.serialization) alias(libs.plugins.kotlin.serialization)

@ -14,28 +14,6 @@
* limitations under the License. * 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 * 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 * 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.hilt) apply false
alias(libs.plugins.ksp) apply false alias(libs.plugins.ksp) apply false
alias(libs.plugins.roborazzi) 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.room) apply false
alias(libs.plugins.module.graph) apply true // Plugin applied to allow module graph generation alias(libs.plugins.module.graph) apply true // Plugin applied to allow module graph generation
} }

@ -36,7 +36,7 @@ firebaseCrashlyticsPlugin = "3.0.6"
firebasePerfPlugin = "2.0.1" firebasePerfPlugin = "2.0.1"
gmsPlugin = "4.4.2" gmsPlugin = "4.4.2"
googleOss = "17.1.0" googleOss = "17.1.0"
googleOssPlugin = "0.10.7" googleOssPlugin = "0.10.8"
hilt = "2.56" hilt = "2.56"
hiltExt = "1.2.0" hiltExt = "1.2.0"
jacoco = "0.8.12" jacoco = "0.8.12"
@ -54,7 +54,6 @@ retrofit = "2.11.0"
robolectric = "4.14.1" robolectric = "4.14.1"
roborazzi = "1.39.0" roborazzi = "1.39.0"
room = "2.7.2" room = "2.7.2"
secrets = "2.0.1"
truth = "1.4.4" truth = "1.4.4"
turbine = "1.2.0" turbine = "1.2.0"
@ -116,7 +115,6 @@ firebase-cloud-messaging = { module = "com.google.firebase:firebase-messaging" }
firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" } firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" }
firebase-performance = { module = "com.google.firebase:firebase-perf" } firebase-performance = { module = "com.google.firebase:firebase-perf" }
google-oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", version.ref = "googleOss" } google-oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", version.ref = "googleOss" }
google-oss-licenses-plugin = { module = "com.google.android.gms:oss-licenses-plugin", version.ref = "googleOssPlugin" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" } hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" }
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" }
@ -176,10 +174,10 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
module-graph = { id = "com.jraska.module.graph.assertion", version.ref = "moduleGraph" } module-graph = { id = "com.jraska.module.graph.assertion", version.ref = "moduleGraph" }
google-osslicenses = { id = "com.google.android.gms.oss-licenses-plugin", version.ref = "googleOssPlugin" }
protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" }
roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" } roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" }
room = { id = "androidx.room", version.ref = "room" } room = { id = "androidx.room", version.ref = "room" }
secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" }
# Plugins defined by this project # Plugins defined by this project
nowinandroid-android-application = { id = "nowinandroid.android.application" } nowinandroid-android-application = { id = "nowinandroid.android.application" }

Loading…
Cancel
Save