diff --git a/.idea/copyright/The_Android_Open_Source_Project.xml b/.idea/copyright/The_Android_Open_Source_Project.xml
new file mode 100644
index 000000000..74acd98d8
--- /dev/null
+++ b/.idea/copyright/The_Android_Open_Source_Project.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 000000000..c2494651f
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/build-logic/README.md b/build-logic/README.md
index 45fd95f91..093e5d857 100644
--- a/build-logic/README.md
+++ b/build-logic/README.md
@@ -29,12 +29,12 @@ setup.
Current list of convention plugins:
-- [`nowinandroid.spotless`](convention/src/main/kotlin/nowinandroid.spotless.gradle.kts):
+- [`nowinandroid.spotless`](convention/src/main/kotlin/SpotlessConventionPlugin.kt):
Configures spotless.
-- [`nowinandroid.android.application`](convention/src/main/kotlin/nowinandroid.android.application.gradle.kts),
- [`nowinandroid.android.library`](convention/src/main/kotlin/nowinandroid.android.library.gradle.kts),
- [`nowinandroid.android.test`](convention/src/main/kotlin/nowinandroid.android.test.gradle.kts):
+- [`nowinandroid.android.application`](convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt),
+ [`nowinandroid.android.library`](convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt),
+ [`nowinandroid.android.test`](convention/src/main/kotlin/AndroidTestConventionPlugin.kt):
Configures common Android and Kotlin options.
-- [`nowinandroid.android.application.compose`](convention/src/main/kotlin/nowinandroid.android.application.compose.gradle.kts),
- [`nowinandroid.android.library.compose`](convention/src/main/kotlin/nowinandroid.android.library.gradle.kts):
+- [`nowinandroid.android.application.compose`](convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt),
+ [`nowinandroid.android.library.compose`](convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt):
Configures Jetpack Compose options
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
index ab9e700ec..9a5baaa41 100644
--- a/build-logic/convention/build.gradle.kts
+++ b/build-logic/convention/build.gradle.kts
@@ -30,3 +30,44 @@ dependencies {
implementation(libs.kotlin.gradlePlugin)
implementation(libs.spotless.gradlePlugin)
}
+
+gradlePlugin {
+ plugins {
+ register("androidApplicationCompose") {
+ id = "nowinandroid.android.application.compose"
+ implementationClass = "AndroidApplicationComposeConventionPlugin"
+ }
+ register("androidApplication") {
+ id = "nowinandroid.android.application"
+ implementationClass = "AndroidApplicationConventionPlugin"
+ }
+ register("androidApplicationJacoco") {
+ id = "nowinandroid.android.application.jacoco"
+ implementationClass = "AndroidApplicationJacocoConventionPlugin"
+ }
+ register("androidLibraryCompose") {
+ id = "nowinandroid.android.library.compose"
+ implementationClass = "AndroidLibraryComposeConventionPlugin"
+ }
+ register("androidLibrary") {
+ id = "nowinandroid.android.library"
+ implementationClass = "AndroidLibraryConventionPlugin"
+ }
+ register("androidFeature") {
+ id = "nowinandroid.android.feature"
+ implementationClass = "AndroidFeatureConventionPlugin"
+ }
+ register("androidLibraryJacoco") {
+ id = "nowinandroid.android.library.jacoco"
+ implementationClass = "AndroidLibraryJacocoConventionPlugin"
+ }
+ register("androidTest") {
+ id = "nowinandroid.android.test"
+ implementationClass = "AndroidTestConventionPlugin"
+ }
+ register("spotless") {
+ id = "nowinandroid.spotless"
+ implementationClass = "SpotlessConventionPlugin"
+ }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt
new file mode 100644
index 000000000..ea40d8c25
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
+import com.google.samples.apps.nowinandroid.configureAndroidCompose
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.getByType
+
+class AndroidApplicationComposeConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ pluginManager.apply("com.android.application")
+ val extension = extensions.getByType()
+ configureAndroidCompose(extension)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
new file mode 100644
index 000000000..698bf7a79
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
+import com.google.samples.apps.nowinandroid.configureKotlinAndroid
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+
+class AndroidApplicationConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("com.android.application")
+ apply("org.jetbrains.kotlin.android")
+ }
+
+ extensions.configure {
+ configureKotlinAndroid(this)
+ defaultConfig.targetSdk = 32
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationJacocoConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationJacocoConventionPlugin.kt
new file mode 100644
index 000000000..4c3acc520
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationJacocoConventionPlugin.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.api.variant.ApplicationAndroidComponentsExtension
+import com.google.samples.apps.nowinandroid.configureJacoco
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.getByType
+
+class AndroidApplicationJacocoConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("org.gradle.jacoco")
+ apply("com.android.application")
+ }
+ val extension = extensions.getByType()
+ configureJacoco(extension)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
new file mode 100644
index 000000000..9545bfb12
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.gradle.LibraryExtension
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.getByType
+
+class AndroidFeatureConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ pluginManager.apply {
+ apply("com.android.library")
+ apply("org.jetbrains.kotlin.android")
+ apply("org.jetbrains.kotlin.kapt")
+ }
+ extensions.configure {
+ defaultConfig {
+ testInstrumentationRunner =
+ "com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner"
+ }
+ }
+
+ val libs = extensions.getByType().named("libs")
+
+ dependencies {
+ add("implementation", project(":core-model"))
+ add("implementation", project(":core-ui"))
+ add("implementation", project(":core-data"))
+ add("implementation", project(":core-common"))
+ add("implementation", project(":core-navigation"))
+
+ add("testImplementation", project(":core-testing"))
+ add("androidTestImplementation", project(":core-testing"))
+
+ add("implementation", libs.findLibrary("coil.kt").get())
+ add("implementation", libs.findLibrary("coil.kt.compose").get())
+
+ add("implementation", libs.findLibrary("androidx.hilt.navigation.compose").get())
+ add("implementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get())
+
+ add("implementation", libs.findLibrary("kotlinx.coroutines.android").get())
+
+ add("implementation", libs.findLibrary("hilt.android").get())
+ add("kapt", libs.findLibrary("hilt.compiler").get())
+
+ // TODO : Remove this dependency once we upgrade to Android Studio Dolphin b/228889042
+ // These dependencies are currently necessary to render Compose previews
+ add(
+ "debugImplementation",
+ libs.findLibrary("androidx.customview.poolingcontainer").get()
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
new file mode 100644
index 000000000..ee6192e05
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.gradle.LibraryExtension
+import com.google.samples.apps.nowinandroid.configureAndroidCompose
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.getByType
+
+class AndroidLibraryComposeConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ pluginManager.apply("com.android.library")
+ val extension = extensions.getByType()
+ configureAndroidCompose(extension)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
new file mode 100644
index 000000000..f9247b6f7
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.gradle.LibraryExtension
+import com.google.samples.apps.nowinandroid.configureKotlinAndroid
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.getByType
+
+class AndroidLibraryConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("com.android.library")
+ apply("org.jetbrains.kotlin.android")
+ }
+
+ extensions.configure {
+ configureKotlinAndroid(this)
+ defaultConfig.targetSdk = 32
+ }
+
+ val libs = extensions.getByType().named("libs")
+ dependencies {
+ configurations.configureEach {
+ resolutionStrategy {
+ force(libs.findLibrary("junit4").get())
+ // Temporary workaround for https://issuetracker.google.com/174733673
+ force("org.objenesis:objenesis:2.6")
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryJacocoConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryJacocoConventionPlugin.kt
new file mode 100644
index 000000000..86ca091c3
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryJacocoConventionPlugin.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.api.variant.LibraryAndroidComponentsExtension
+import com.google.samples.apps.nowinandroid.configureJacoco
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.getByType
+
+class AndroidLibraryJacocoConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("org.gradle.jacoco")
+ apply("com.android.library")
+ }
+ val extension = extensions.getByType()
+ configureJacoco(extension)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt
new file mode 100644
index 000000000..8d446505c
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidTestConventionPlugin.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.gradle.TestExtension
+import com.google.samples.apps.nowinandroid.configureKotlinAndroid
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+
+class AndroidTestConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("com.android.test")
+ apply("org.jetbrains.kotlin.android")
+ }
+
+ extensions.configure {
+ configureKotlinAndroid(this)
+ defaultConfig.targetSdk = 31
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
new file mode 100644
index 000000000..eaf907ce2
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.diffplug.gradle.spotless.SpotlessExtension
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.getByType
+
+class SpotlessConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ pluginManager.apply("com.diffplug.spotless")
+ val libs = extensions.getByType().named("libs")
+
+ extensions.configure {
+ kotlin {
+ target("**/*.kt")
+ targetExclude("**/build/**/*.kt")
+ ktlint(libs.findVersion("ktlint").get().toString()).userData(mapOf("android" to "true"))
+ licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
+ }
+ format("kts") {
+ target("**/*.kts")
+ targetExclude("**/build/**/*.kts")
+ // Look for the first line that doesn't have a block comment (assumed to be the license)
+ licenseHeaderFile(rootProject.file("spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)")
+ }
+ format("xml") {
+ target("**/*.xml")
+ targetExclude("**/build/**/*.xml")
+ // Look for the first XML tag that isn't a comment (