diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index 6bee0ddfb..5bf03b47a 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -25,9 +25,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v3 - - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties @@ -38,7 +35,10 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/gradle-build-action@v3 + uses: gradle/actions/setup-gradle@v3 + with: + validate-wrappers: true + gradle-home-cache-cleanup: true - name: Check build-logic run: ./gradlew check -p build-logic @@ -187,7 +187,10 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/gradle-build-action@v3 + uses: gradle/actions/setup-gradle@v3 + with: + validate-wrappers: true + gradle-home-cache-cleanup: true - name: Build projects and run instrumentation tests uses: reactivecircus/android-emulator-runner@v2 diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 2184a4c50..b18b41faa 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -19,10 +19,8 @@ jobs: ls /dev/kvm - name: Checkout - uses: actions/checkout@v4 - - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v3 + uses: actions/checkout@v4 - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties @@ -33,6 +31,12 @@ jobs: distribution: 'zulu' java-version: 17 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + validate-wrappers: true + gradle-home-cache-cleanup: true + - name: Install GMD image for baseline profile generation run: yes | "$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager "system-images;android-33;aosp_atd;x86_64" diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8568a6975..9b577a5bc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ plugins { alias(libs.plugins.nowinandroid.android.application.compose) alias(libs.plugins.nowinandroid.android.application.flavors) alias(libs.plugins.nowinandroid.android.application.jacoco) - alias(libs.plugins.nowinandroid.android.hilt) alias(libs.plugins.nowinandroid.android.application.firebase) + alias(libs.plugins.nowinandroid.hilt) id("com.google.android.gms.oss-licenses-plugin") alias(libs.plugins.baselineprofile) alias(libs.plugins.roborazzi) @@ -114,16 +114,14 @@ dependencies { kspTest(libs.hilt.compiler) testImplementation(projects.core.dataTest) - testImplementation(projects.core.testing) - testImplementation(projects.sync.syncTest) - testImplementation(libs.androidx.compose.ui.test) - testImplementation(libs.androidx.work.testing) testImplementation(libs.hilt.android.testing) + testImplementation(projects.sync.syncTest) testDemoImplementation(libs.robolectric) testDemoImplementation(libs.roborazzi) testDemoImplementation(projects.core.screenshotTesting) + androidTestImplementation(kotlin("test")) androidTestImplementation(projects.core.testing) androidTestImplementation(projects.core.dataTest) androidTestImplementation(projects.core.datastoreTest) diff --git a/app/dependencies/prodReleaseRuntimeClasspath.txt b/app/dependencies/prodReleaseRuntimeClasspath.txt index 6819c60d1..b909bcbc9 100644 --- a/app/dependencies/prodReleaseRuntimeClasspath.txt +++ b/app/dependencies/prodReleaseRuntimeClasspath.txt @@ -4,8 +4,8 @@ androidx.activity:activity:1.8.2 androidx.annotation:annotation-experimental:1.4.0 androidx.annotation:annotation-jvm:1.8.0 androidx.annotation:annotation:1.8.0 -androidx.appcompat:appcompat-resources:1.6.1 -androidx.appcompat:appcompat:1.6.1 +androidx.appcompat:appcompat-resources:1.7.0 +androidx.appcompat:appcompat:1.7.0 androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-runtime:2.2.0 androidx.autofill:autofill:1.0.0 @@ -75,7 +75,7 @@ androidx.drawerlayout:drawerlayout:1.0.0 androidx.emoji2:emoji2-views-helper:1.3.0 androidx.emoji2:emoji2:1.3.0 androidx.exifinterface:exifinterface:1.3.7 -androidx.fragment:fragment:1.5.1 +androidx.fragment:fragment:1.5.4 androidx.graphics:graphics-path:1.0.1 androidx.hilt:hilt-common:1.1.0 androidx.hilt:hilt-navigation-compose:1.2.0 @@ -83,26 +83,26 @@ androidx.hilt:hilt-navigation:1.2.0 androidx.hilt:hilt-work:1.1.0 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.8.0 -androidx.lifecycle:lifecycle-common-jvm:2.8.0 -androidx.lifecycle:lifecycle-common:2.8.0 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0 -androidx.lifecycle:lifecycle-livedata-core:2.8.0 -androidx.lifecycle:lifecycle-livedata:2.8.0 -androidx.lifecycle:lifecycle-process:2.8.0 -androidx.lifecycle:lifecycle-runtime-android:2.8.0 -androidx.lifecycle:lifecycle-runtime-compose-android:2.8.0 -androidx.lifecycle:lifecycle-runtime-compose:2.8.0 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.0 -androidx.lifecycle:lifecycle-runtime-ktx:2.8.0 -androidx.lifecycle:lifecycle-runtime:2.8.0 -androidx.lifecycle:lifecycle-service:2.8.0 -androidx.lifecycle:lifecycle-viewmodel-android:2.8.0 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.0 -androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -androidx.lifecycle:lifecycle-viewmodel:2.8.0 +androidx.lifecycle:lifecycle-common-java8:2.8.3 +androidx.lifecycle:lifecycle-common-jvm:2.8.3 +androidx.lifecycle:lifecycle-common:2.8.3 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.3 +androidx.lifecycle:lifecycle-livedata-core:2.8.3 +androidx.lifecycle:lifecycle-livedata:2.8.3 +androidx.lifecycle:lifecycle-process:2.8.3 +androidx.lifecycle:lifecycle-runtime-android:2.8.3 +androidx.lifecycle:lifecycle-runtime-compose-android:2.8.3 +androidx.lifecycle:lifecycle-runtime-compose:2.8.3 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.3 +androidx.lifecycle:lifecycle-runtime-ktx:2.8.3 +androidx.lifecycle:lifecycle-runtime:2.8.3 +androidx.lifecycle:lifecycle-service:2.8.3 +androidx.lifecycle:lifecycle-viewmodel-android:2.8.3 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.3 +androidx.lifecycle:lifecycle-viewmodel-compose:2.8.3 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.3 +androidx.lifecycle:lifecycle-viewmodel:2.8.3 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.metrics:metrics-performance:1.0.0-alpha04 @@ -140,59 +140,56 @@ androidx.work:work-runtime:2.9.0 com.caverock:androidsvg-aar:1.4 com.google.accompanist:accompanist-drawablepainter:0.32.0 com.google.accompanist:accompanist-permissions:0.34.0 -com.google.android.datatransport:transport-api:3.0.0 +com.google.android.datatransport:transport-api:3.1.0 com.google.android.datatransport:transport-backend-cct:3.1.9 com.google.android.datatransport:transport-runtime:3.1.9 com.google.android.gms:play-services-ads-identifier:18.0.0 com.google.android.gms:play-services-base:18.0.1 -com.google.android.gms:play-services-basement:18.1.0 -com.google.android.gms:play-services-cloud-messaging:17.0.1 -com.google.android.gms:play-services-measurement-api:21.4.0 -com.google.android.gms:play-services-measurement-base:21.4.0 -com.google.android.gms:play-services-measurement-impl:21.4.0 -com.google.android.gms:play-services-measurement-sdk-api:21.4.0 -com.google.android.gms:play-services-measurement-sdk:21.4.0 -com.google.android.gms:play-services-measurement:21.4.0 +com.google.android.gms:play-services-basement:18.4.0 +com.google.android.gms:play-services-cloud-messaging:17.2.0 +com.google.android.gms:play-services-measurement-api:22.0.2 +com.google.android.gms:play-services-measurement-base:22.0.2 +com.google.android.gms:play-services-measurement-impl:22.0.2 +com.google.android.gms:play-services-measurement-sdk-api:22.0.2 +com.google.android.gms:play-services-measurement-sdk:22.0.2 +com.google.android.gms:play-services-measurement:22.0.2 com.google.android.gms:play-services-oss-licenses:17.0.1 com.google.android.gms:play-services-stats:17.0.2 -com.google.android.gms:play-services-tasks:18.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.51.1 com.google.dagger:dagger:2.51.1 com.google.dagger:hilt-android:2.51.1 com.google.dagger:hilt-core:2.51.1 -com.google.errorprone:error_prone_annotations:2.11.0 +com.google.errorprone:error_prone_annotations:2.26.0 com.google.firebase:firebase-abt:21.1.1 -com.google.firebase:firebase-analytics-ktx:21.4.0 -com.google.firebase:firebase-analytics:21.4.0 +com.google.firebase:firebase-analytics:22.0.2 com.google.firebase:firebase-annotations:16.2.0 -com.google.firebase:firebase-bom:32.4.0 -com.google.firebase:firebase-common-ktx:20.4.2 -com.google.firebase:firebase-common:20.4.2 -com.google.firebase:firebase-components:17.1.5 -com.google.firebase:firebase-config:21.5.0 -com.google.firebase:firebase-crashlytics-ktx:18.5.0 -com.google.firebase:firebase-crashlytics:18.5.0 -com.google.firebase:firebase-datatransport:18.1.8 +com.google.firebase:firebase-bom:33.1.1 +com.google.firebase:firebase-common-ktx:21.0.0 +com.google.firebase:firebase-common:21.0.0 +com.google.firebase:firebase-components:18.0.0 +com.google.firebase:firebase-config-interop:16.0.1 +com.google.firebase:firebase-config:22.0.0 +com.google.firebase:firebase-crashlytics:19.0.2 +com.google.firebase:firebase-datatransport:18.2.0 com.google.firebase:firebase-encoders-json:18.0.1 com.google.firebase:firebase-encoders-proto:16.0.0 com.google.firebase:firebase-encoders:17.0.0 com.google.firebase:firebase-iid-interop:17.1.0 com.google.firebase:firebase-installations-interop:17.1.1 -com.google.firebase:firebase-installations:17.2.0 -com.google.firebase:firebase-measurement-connector:19.0.0 -com.google.firebase:firebase-messaging-ktx:23.3.0 -com.google.firebase:firebase-messaging:23.3.0 -com.google.firebase:firebase-perf-ktx:20.5.0 -com.google.firebase:firebase-perf:20.5.0 -com.google.firebase:firebase-sessions:1.1.0 +com.google.firebase:firebase-installations:18.0.0 +com.google.firebase:firebase-measurement-connector:20.0.1 +com.google.firebase:firebase-messaging:24.0.0 +com.google.firebase:firebase-perf:21.0.1 +com.google.firebase:firebase-sessions:2.0.2 com.google.firebase:protolite-well-known-types:18.0.0 com.google.guava:failureaccess:1.0.1 com.google.guava:guava:31.1-android com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava com.google.j2objc:j2objc-annotations:1.3 -com.google.protobuf:protobuf-javalite:4.26.0 -com.google.protobuf:protobuf-kotlin-lite:4.26.0 +com.google.protobuf:protobuf-javalite:4.26.1 +com.google.protobuf:protobuf-kotlin-lite:4.26.1 com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0 com.squareup.okhttp3:logging-interceptor:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 diff --git a/app/prodRelease-badging.txt b/app/prodRelease-badging.txt index 769e0a6e4..21b36a7fb 100644 --- a/app/prodRelease-badging.txt +++ b/app/prodRelease-badging.txt @@ -6,9 +6,9 @@ uses-permission: name='android.permission.ACCESS_NETWORK_STATE' uses-permission: name='android.permission.POST_NOTIFICATIONS' uses-permission: name='android.permission.WAKE_LOCK' uses-permission: name='com.google.android.c2dm.permission.RECEIVE' +uses-permission: name='com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE' uses-permission: name='android.permission.RECEIVE_BOOT_COMPLETED' uses-permission: name='android.permission.FOREGROUND_SERVICE' -uses-permission: name='com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE' uses-permission: name='com.google.samples.apps.nowinandroid.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION' application-label:'Now in Android' application-label-af:'Now in Android' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 9c7f3b935..5f4922bce 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,13 +1,3 @@ --dontwarn org.bouncycastle.jsse.BCSSLParameters --dontwarn org.bouncycastle.jsse.BCSSLSocket --dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider --dontwarn org.conscrypt.Conscrypt$Version --dontwarn org.conscrypt.Conscrypt --dontwarn org.conscrypt.ConscryptHostnameVerifier --dontwarn org.openjsse.javax.net.ssl.SSLParameters --dontwarn org.openjsse.javax.net.ssl.SSLSocket --dontwarn org.openjsse.net.ssl.OpenJSSE - # Fix for Retrofit issue https://github.com/square/retrofit/issues/3751 # Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items). -keep,allowobfuscation,allowshrinking interface retrofit2.Call @@ -16,4 +6,4 @@ # With R8 full mode generic signatures are stripped for classes that are not # kept. Suspend functions are wrapped in continuations where the type argument # is used. --keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation \ No newline at end of file +-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt index 93c674bcc..b15024cc7 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt @@ -16,13 +16,11 @@ package com.google.samples.apps.nowinandroid.ui -import androidx.annotation.StringRes import androidx.compose.ui.test.assertCountEquals import androidx.compose.ui.test.assertIsOn import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText -import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onNodeWithContentDescription @@ -47,7 +45,6 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import javax.inject.Inject -import kotlin.properties.ReadOnlyProperty import com.google.samples.apps.nowinandroid.feature.bookmarks.R as BookmarksR import com.google.samples.apps.nowinandroid.feature.foryou.R as FeatureForyouR import com.google.samples.apps.nowinandroid.feature.search.R as FeatureSearchR @@ -88,9 +85,6 @@ class NavigationTest { @Inject lateinit var topicsRepository: TopicsRepository - private fun AndroidComposeTestRule<*, *>.stringResource(@StringRes resId: Int) = - ReadOnlyProperty { _, _ -> activity.getString(resId) } - // The strings used for matching in these tests private val navigateUp by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_navigate_up) private val forYou by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_title) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/UiTestExtensions.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/UiTestExtensions.kt new file mode 100644 index 000000000..bdc09885d --- /dev/null +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/UiTestExtensions.kt @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package com.google.samples.apps.nowinandroid.ui + +import androidx.annotation.StringRes +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import kotlin.properties.ReadOnlyProperty + +fun AndroidComposeTestRule<*, *>.stringResource( + @StringRes resId: Int, +): ReadOnlyProperty = + ReadOnlyProperty { _, _ -> activity.getString(resId) } diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreenTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreenTest.kt new file mode 100644 index 000000000..21ac3e920 --- /dev/null +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreenTest.kt @@ -0,0 +1,228 @@ +/* + * 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. + */ + +package com.google.samples.apps.nowinandroid.ui.interests2pane + +import androidx.activity.compose.BackHandler +import androidx.compose.material3.adaptive.Posture +import androidx.compose.material3.adaptive.WindowAdaptiveInfo +import androidx.compose.ui.test.DeviceConfigurationOverride +import androidx.compose.ui.test.ForcedSize +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotDisplayed +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.test.espresso.Espresso +import androidx.window.core.layout.WindowSizeClass +import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository +import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme +import com.google.samples.apps.nowinandroid.core.model.data.Topic +import com.google.samples.apps.nowinandroid.ui.stringResource +import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity +import dagger.hilt.android.testing.BindValue +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import javax.inject.Inject +import kotlin.test.assertTrue +import com.google.samples.apps.nowinandroid.feature.topic.R as FeatureTopicR + +@HiltAndroidTest +class InterestsListDetailScreenTest { + @get:Rule(order = 0) + val hiltRule = HiltAndroidRule(this) + + @BindValue + @get:Rule(order = 1) + val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() + + @get:Rule(order = 2) + val composeTestRule = createAndroidComposeRule() + + @Inject + lateinit var topicsRepository: TopicsRepository + + // The strings used for matching in these tests. + private val placeholderText by composeTestRule.stringResource(FeatureTopicR.string.feature_topic_select_an_interest) + private val listPaneTag = "interests:topics" + + private val Topic.testTag + get() = "topic:${this.id}" + + // Overrides for device sizes. + private enum class TestDeviceConfig(widthDp: Float, heightDp: Float) { + Compact(412f, 915f), + Expanded(1200f, 840f), + ; + + val sizeOverride = DeviceConfigurationOverride.ForcedSize(DpSize(widthDp.dp, heightDp.dp)) + val adaptiveInfo = WindowAdaptiveInfo( + windowSizeClass = WindowSizeClass.compute(widthDp, heightDp), + windowPosture = Posture(), + ) + } + + @Before + fun setup() { + hiltRule.inject() + } + + /** Convenience function for getting all topics during tests, */ + private fun getTopics(): List = runBlocking { + topicsRepository.getTopics().first() + } + + @Test + fun expandedWidth_initialState_showsTwoPanesWithPlaceholder() { + composeTestRule.apply { + setContent { + with(TestDeviceConfig.Expanded) { + DeviceConfigurationOverride(override = sizeOverride) { + NiaTheme { + InterestsListDetailScreen(windowAdaptiveInfo = adaptiveInfo) + } + } + } + } + + onNodeWithTag(listPaneTag).assertIsDisplayed() + onNodeWithText(placeholderText).assertIsDisplayed() + } + } + + @Test + fun compactWidth_initialState_showsListPane() { + composeTestRule.apply { + setContent { + with(TestDeviceConfig.Compact) { + DeviceConfigurationOverride(override = sizeOverride) { + NiaTheme { + InterestsListDetailScreen(windowAdaptiveInfo = adaptiveInfo) + } + } + } + } + + onNodeWithTag(listPaneTag).assertIsDisplayed() + onNodeWithText(placeholderText).assertIsNotDisplayed() + } + } + + @Test + fun expandedWidth_topicSelected_updatesDetailPane() { + composeTestRule.apply { + setContent { + with(TestDeviceConfig.Expanded) { + DeviceConfigurationOverride(override = sizeOverride) { + NiaTheme { + InterestsListDetailScreen(windowAdaptiveInfo = adaptiveInfo) + } + } + } + } + + val firstTopic = getTopics().first() + onNodeWithText(firstTopic.name).performClick() + + onNodeWithTag(listPaneTag).assertIsDisplayed() + onNodeWithText(placeholderText).assertIsNotDisplayed() + onNodeWithTag(firstTopic.testTag).assertIsDisplayed() + } + } + + @Test + fun compactWidth_topicSelected_showsTopicDetailPane() { + composeTestRule.apply { + setContent { + with(TestDeviceConfig.Compact) { + DeviceConfigurationOverride(override = sizeOverride) { + NiaTheme { + InterestsListDetailScreen(windowAdaptiveInfo = adaptiveInfo) + } + } + } + } + + val firstTopic = getTopics().first() + onNodeWithText(firstTopic.name).performClick() + + onNodeWithTag(listPaneTag).assertIsNotDisplayed() + onNodeWithText(placeholderText).assertIsNotDisplayed() + onNodeWithTag(firstTopic.testTag).assertIsDisplayed() + } + } + + @Test + fun expandedWidth_backPressFromTopicDetail_leavesInterests() { + var unhandledBackPress = false + composeTestRule.apply { + setContent { + with(TestDeviceConfig.Expanded) { + DeviceConfigurationOverride(override = sizeOverride) { + NiaTheme { + // Back press should not be handled by the two pane layout, and thus + // "fall through" to this BackHandler. + BackHandler { + unhandledBackPress = true + } + InterestsListDetailScreen(windowAdaptiveInfo = adaptiveInfo) + } + } + } + } + + val firstTopic = getTopics().first() + onNodeWithText(firstTopic.name).performClick() + + Espresso.pressBack() + + assertTrue(unhandledBackPress) + } + } + + @Test + fun compactWidth_backPressFromTopicDetail_showsListPane() { + composeTestRule.apply { + setContent { + with(TestDeviceConfig.Compact) { + DeviceConfigurationOverride(override = sizeOverride) { + NiaTheme { + InterestsListDetailScreen(windowAdaptiveInfo = adaptiveInfo) + } + } + } + } + + val firstTopic = getTopics().first() + onNodeWithText(firstTopic.name).performClick() + + Espresso.pressBack() + + onNodeWithTag(listPaneTag).assertIsDisplayed() + onNodeWithText(placeholderText).assertIsNotDisplayed() + onNodeWithTag(firstTopic.testTag).assertIsNotDisplayed() + } + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index eb2e557d9..5b22f9865 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,11 +20,13 @@ + + + + + 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 1b5913b15..27f0c2e1e 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 @@ -18,11 +18,14 @@ package com.google.samples.apps.nowinandroid.ui.interests2pane import androidx.activity.compose.BackHandler 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.ThreePaneScaffoldDestinationItem +import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator import androidx.compose.runtime.Composable @@ -61,11 +64,13 @@ fun NavGraphBuilder.interestsListDetailScreen() { @Composable internal fun InterestsListDetailScreen( viewModel: Interests2PaneViewModel = hiltViewModel(), + windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(), ) { val selectedTopicId by viewModel.selectedTopicId.collectAsStateWithLifecycle() InterestsListDetailScreen( selectedTopicId = selectedTopicId, onTopicClick = viewModel::onTopicClick, + windowAdaptiveInfo = windowAdaptiveInfo, ) } @@ -74,8 +79,10 @@ internal fun InterestsListDetailScreen( internal fun InterestsListDetailScreen( selectedTopicId: String?, onTopicClick: (String) -> Unit, + windowAdaptiveInfo: WindowAdaptiveInfo, ) { val listDetailNavigator = rememberListDetailPaneScaffoldNavigator( + scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo), initialDestinationHistory = listOfNotNull( ThreePaneScaffoldDestinationItem(ListDetailPaneScaffoldRole.List), ThreePaneScaffoldDestinationItem(ListDetailPaneScaffoldRole.Detail).takeIf { diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/DeviceConfigurationOverrideWindowInsets.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/DeviceConfigurationOverrideWindowInsets.kt new file mode 100644 index 000000000..2fc88e561 --- /dev/null +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/DeviceConfigurationOverrideWindowInsets.kt @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package com.google.samples.apps.nowinandroid.ui + +import android.view.WindowInsets +import android.widget.FrameLayout +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.test.DeviceConfigurationOverride +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.children + +/** + * A [DeviceConfigurationOverride] that allows overriding the [windowInsets] available + * to the content under test. + */ +@Suppress("ktlint:standard:function-naming") +fun DeviceConfigurationOverride.Companion.WindowInsets( + windowInsets: WindowInsetsCompat, +): DeviceConfigurationOverride = DeviceConfigurationOverride { contentUnderTest -> + val currentContentUnderTest by rememberUpdatedState(contentUnderTest) + val currentWindowInsets by rememberUpdatedState(windowInsets) + AndroidView( + factory = { context -> + object : FrameLayout(context) { + override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets { + children.forEach { + it.dispatchApplyWindowInsets(currentWindowInsets.toWindowInsets()) + } + return WindowInsetsCompat.CONSUMED.toWindowInsets()!! + } + + /** + * Deprecated, but intercept the `requestApplyInsets` call via the deprecated + * method. + */ + @Deprecated("Deprecated in Java") + override fun requestFitSystemWindows() { + dispatchApplyWindowInsets(currentWindowInsets.toWindowInsets()!!) + } + }.apply { + addView( + ComposeView(context).apply { + setContent { + currentContentUnderTest() + } + }, + ) + } + }, + ) +} diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarInsetsScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarInsetsScreenshotTests.kt new file mode 100644 index 000000000..b9970effd --- /dev/null +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarInsetsScreenshotTests.kt @@ -0,0 +1,349 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.samples.apps.nowinandroid.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsBottomHeight +import androidx.compose.foundation.layout.windowInsetsEndWidth +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.layout.windowInsetsStartWidth +import androidx.compose.foundation.layout.windowInsetsTopHeight +import androidx.compose.material3.SnackbarDuration.Indefinite +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi +import androidx.compose.material3.adaptive.Posture +import androidx.compose.material3.adaptive.WindowAdaptiveInfo +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toAndroidRect +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.test.DeviceConfigurationOverride +import androidx.compose.ui.test.ForcedSize +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpRect +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.roundToIntRect +import androidx.core.graphics.Insets +import androidx.core.view.WindowInsetsCompat +import androidx.window.core.layout.WindowSizeClass +import com.github.takahirom.roborazzi.captureRoboImage +import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository +import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository +import com.google.samples.apps.nowinandroid.core.data.test.repository.FakeUserDataRepository +import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor +import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor +import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme +import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions +import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity +import dagger.hilt.android.testing.BindValue +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest +import dagger.hilt.android.testing.HiltTestApplication +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode +import org.robolectric.annotation.LooperMode +import java.util.TimeZone +import javax.inject.Inject + +/** + * Tests that the Snackbar is correctly displayed on different screen sizes. + */ +@RunWith(RobolectricTestRunner::class) +@GraphicsMode(GraphicsMode.Mode.NATIVE) +// Configure Robolectric to use a very large screen size that can fit all of the test sizes. +// This allows enough room to render the content under test without clipping or scaling. +@Config(application = HiltTestApplication::class, qualifiers = "w1000dp-h1000dp-480dpi") +@LooperMode(LooperMode.Mode.PAUSED) +@HiltAndroidTest +class SnackbarInsetsScreenshotTests { + + /** + * Manages the components' state and is used to perform injection on your test + */ + @get:Rule(order = 0) + val hiltRule = HiltAndroidRule(this) + + /** + * Create a temporary folder used to create a Data Store file. This guarantees that + * the file is removed in between each test, preventing a crash. + */ + @BindValue + @get:Rule(order = 1) + val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() + + /** + * Use a test activity to set the content on. + */ + @get:Rule(order = 2) + val composeTestRule = createAndroidComposeRule() + + @Inject + lateinit var networkMonitor: NetworkMonitor + + @Inject + lateinit var timeZoneMonitor: TimeZoneMonitor + + @Inject + lateinit var userDataRepository: FakeUserDataRepository + + @Inject + lateinit var topicsRepository: TopicsRepository + + @Inject + lateinit var userNewsResourceRepository: UserNewsResourceRepository + + @Before + fun setup() { + hiltRule.inject() + + // Configure user data + runBlocking { + userDataRepository.setShouldHideOnboarding(true) + + userDataRepository.setFollowedTopicIds( + setOf(topicsRepository.getTopics().first().first().id), + ) + } + } + + @Before + fun setTimeZone() { + // Make time zone deterministic in tests + TimeZone.setDefault(TimeZone.getTimeZone("UTC")) + } + + @Test + fun phone_noSnackbar() { + val snackbarHostState = SnackbarHostState() + testSnackbarScreenshotWithSize( + snackbarHostState, + 400.dp, + 500.dp, + "insets_snackbar_compact_medium_noSnackbar", + action = { }, + ) + } + + @Test + fun snackbarShown_phone() { + val snackbarHostState = SnackbarHostState() + testSnackbarScreenshotWithSize( + snackbarHostState, + 400.dp, + 500.dp, + "insets_snackbar_compact_medium", + ) { + snackbarHostState.showSnackbar( + "This is a test snackbar message", + actionLabel = "Action Label", + duration = Indefinite, + ) + } + } + + @Test + fun snackbarShown_foldable() { + val snackbarHostState = SnackbarHostState() + testSnackbarScreenshotWithSize( + snackbarHostState, + 600.dp, + 600.dp, + "insets_snackbar_medium_medium", + ) { + snackbarHostState.showSnackbar( + "This is a test snackbar message", + actionLabel = "Action Label", + duration = Indefinite, + ) + } + } + + @Test + fun snackbarShown_tablet() { + val snackbarHostState = SnackbarHostState() + testSnackbarScreenshotWithSize( + snackbarHostState, + 900.dp, + 900.dp, + "insets_snackbar_expanded_expanded", + ) { + snackbarHostState.showSnackbar( + "This is a test snackbar message", + actionLabel = "Action Label", + duration = Indefinite, + ) + } + } + + @OptIn(ExperimentalMaterial3AdaptiveApi::class) + private fun testSnackbarScreenshotWithSize( + snackbarHostState: SnackbarHostState, + width: Dp, + height: Dp, + screenshotName: String, + action: suspend () -> Unit, + ) { + lateinit var scope: CoroutineScope + composeTestRule.setContent { + CompositionLocalProvider( + // Replaces images with placeholders + LocalInspectionMode provides true, + ) { + scope = rememberCoroutineScope() + + DeviceConfigurationOverride( + DeviceConfigurationOverride.ForcedSize(DpSize(width, height)), + ) { + DeviceConfigurationOverride( + DeviceConfigurationOverride.WindowInsets( + WindowInsetsCompat.Builder() + .setInsets( + WindowInsetsCompat.Type.statusBars(), + DpRect( + left = 0.dp, + top = 64.dp, + right = 0.dp, + bottom = 0.dp, + ).toInsets(), + ) + .setInsets( + WindowInsetsCompat.Type.navigationBars(), + DpRect( + left = 64.dp, + top = 0.dp, + right = 64.dp, + bottom = 64.dp, + ).toInsets(), + ) + .build(), + ), + ) { + BoxWithConstraints(Modifier.testTag("root")) { + NiaTheme { + val appState = rememberNiaAppState( + networkMonitor = networkMonitor, + userNewsResourceRepository = userNewsResourceRepository, + timeZoneMonitor = timeZoneMonitor, + ) + NiaApp( + appState = appState, + snackbarHostState = snackbarHostState, + showSettingsDialog = false, + onSettingsDismissed = {}, + onTopAppBarActionClick = {}, + windowAdaptiveInfo = WindowAdaptiveInfo( + windowSizeClass = WindowSizeClass.compute( + maxWidth.value, + maxHeight.value, + ), + windowPosture = Posture(), + ), + ) + DebugVisibleWindowInsets() + } + } + } + } + } + } + + scope.launch { + action() + } + + composeTestRule.onNodeWithTag("root") + .captureRoboImage( + "src/testDemo/screenshots/$screenshotName.png", + roborazziOptions = DefaultRoborazziOptions, + ) + } +} + +@Composable +fun DebugVisibleWindowInsets( + modifier: Modifier = Modifier, + debugColor: Color = Color.Magenta.copy(alpha = 0.5f), +) { + Box(modifier = modifier.fillMaxSize()) { + Spacer( + modifier = Modifier + .align(Alignment.CenterStart) + .fillMaxHeight() + .windowInsetsStartWidth(WindowInsets.safeDrawing) + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical)) + .background(debugColor), + ) + Spacer( + modifier = Modifier + .align(Alignment.CenterEnd) + .fillMaxHeight() + .windowInsetsEndWidth(WindowInsets.safeDrawing) + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical)) + .background(debugColor), + ) + Spacer( + modifier = Modifier + .align(Alignment.TopCenter) + .fillMaxWidth() + .windowInsetsTopHeight(WindowInsets.safeDrawing) + .background(debugColor), + ) + Spacer( + modifier = Modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .windowInsetsBottomHeight(WindowInsets.safeDrawing) + .background(debugColor), + ) + } +} + +@Composable +private fun DpRect.toInsets() = toInsets(LocalDensity.current) + +private fun DpRect.toInsets(density: Density) = + Insets.of(with(density) { toRect() }.roundToIntRect().toAndroidRect()) diff --git a/app/src/testDemo/screenshots/insets_snackbar_compact_medium.png b/app/src/testDemo/screenshots/insets_snackbar_compact_medium.png new file mode 100644 index 000000000..aae785a47 Binary files /dev/null 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 new file mode 100644 index 000000000..d37f02c65 Binary files /dev/null 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 new file mode 100644 index 000000000..3d2c79256 Binary files /dev/null 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 new file mode 100644 index 000000000..3e7171bf4 Binary files /dev/null and b/app/src/testDemo/screenshots/insets_snackbar_medium_medium.png differ diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index dc478a829..c735fa4a0 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -89,9 +89,9 @@ gradlePlugin { id = "nowinandroid.android.test" implementationClass = "AndroidTestConventionPlugin" } - register("androidHilt") { - id = "nowinandroid.android.hilt" - implementationClass = "AndroidHiltConventionPlugin" + register("hilt") { + id = "nowinandroid.hilt" + implementationClass = "HiltConventionPlugin" } register("androidRoom") { id = "nowinandroid.android.room" diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt index 1aca52136..6d0f213d4 100644 --- a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt @@ -27,14 +27,10 @@ class AndroidFeatureConventionPlugin : Plugin { with(target) { pluginManager.apply { apply("nowinandroid.android.library") - apply("nowinandroid.android.hilt") + apply("nowinandroid.hilt") apply("org.jetbrains.kotlin.plugin.serialization") } extensions.configure { - defaultConfig { - testInstrumentationRunner = - "com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner" - } testOptions.animationsDisabled = true configureGradleManagedDevices(this) } diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt index be5b41d07..71d818c0c 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -40,6 +40,7 @@ class AndroidLibraryConventionPlugin : Plugin { extensions.configure { configureKotlinAndroid(this) defaultConfig.targetSdk = 34 + defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testOptions.animationsDisabled = true configureFlavors(this) configureGradleManagedDevices(this) @@ -52,6 +53,7 @@ class AndroidLibraryConventionPlugin : Plugin { disableUnnecessaryAndroidTests(target) } dependencies { + add("androidTestImplementation", kotlin("test")) add("testImplementation", kotlin("test")) add("implementation", libs.findLibrary("androidx.tracing.ktx").get()) diff --git a/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt similarity index 55% rename from build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt rename to build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt index fcb4f823e..a8228e5af 100644 --- a/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Android Open Source Project + * Copyright 2023 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. @@ -14,25 +14,28 @@ * limitations under the License. */ +import com.android.build.gradle.api.AndroidBasePlugin import com.google.samples.apps.nowinandroid.libs import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.dependencies -class AndroidHiltConventionPlugin : Plugin { +class HiltConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - with(pluginManager) { - apply("com.google.devtools.ksp") - apply("dagger.hilt.android.plugin") - } - + pluginManager.apply("com.google.devtools.ksp") dependencies { - "implementation"(libs.findLibrary("hilt.android").get()) - "ksp"(libs.findLibrary("hilt.compiler").get()) + add("ksp", libs.findLibrary("hilt.compiler").get()) + add("implementation", libs.findLibrary("hilt.core").get()) } + /** Add support for Android modules, based on [AndroidBasePlugin] */ + pluginManager.withPlugin("com.android.base") { + pluginManager.apply("dagger.hilt.android.plugin") + dependencies { + add("implementation", libs.findLibrary("hilt.android").get()) + } + } } } - } 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 c59d3ffb8..4447b8602 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 @@ -16,10 +16,10 @@ package com.google.samples.apps.nowinandroid +import com.android.SdkConstants import com.android.build.api.artifact.SingleArtifact import com.android.build.api.variant.ApplicationAndroidComponentsExtension import com.android.build.gradle.BaseExtension -import com.android.SdkConstants import com.google.common.truth.Truth.assertWithMessage import org.gradle.api.DefaultTask import org.gradle.api.Project @@ -36,6 +36,7 @@ import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction import org.gradle.configurationcache.extensions.capitalized +import org.gradle.kotlin.dsl.assign import org.gradle.kotlin.dsl.register import org.gradle.language.base.plugins.LifecycleBasePlugin import org.gradle.process.ExecOperations @@ -117,23 +118,20 @@ fun Project.configureBadgingTasks( val generateBadgingTaskName = "generate${capitalizedVariantName}Badging" val generateBadging = tasks.register(generateBadgingTaskName) { - apk.set( - variant.artifacts.get(SingleArtifact.APK_FROM_BUNDLE), - ) - aapt2Executable.set( - File( - baseExtension.sdkDirectory, - "${SdkConstants.FD_BUILD_TOOLS}/" + - "${baseExtension.buildToolsVersion}/" + - SdkConstants.FN_AAPT2, - ), + apk = variant.artifacts.get(SingleArtifact.APK_FROM_BUNDLE) + + aapt2Executable = File( + baseExtension.sdkDirectory, + "${SdkConstants.FD_BUILD_TOOLS}/" + + "${baseExtension.buildToolsVersion}/" + + SdkConstants.FN_AAPT2, ) - badging.set( - project.layout.buildDirectory.file( - "outputs/apk_from_bundle/${variant.name}/${variant.name}-badging.txt", - ), + + badging = project.layout.buildDirectory.file( + "outputs/apk_from_bundle/${variant.name}/${variant.name}-badging.txt", ) + } val updateBadgingTaskName = "update${capitalizedVariantName}Badging" @@ -144,17 +142,14 @@ fun Project.configureBadgingTasks( val checkBadgingTaskName = "check${capitalizedVariantName}Badging" tasks.register(checkBadgingTaskName) { - goldenBadging.set( - project.layout.projectDirectory.file("${variant.name}-badging.txt"), - ) - generatedBadging.set( - generateBadging.get().badging, - ) - this.updateBadgingTaskName.set(updateBadgingTaskName) + goldenBadging = project.layout.projectDirectory.file("${variant.name}-badging.txt") + + generatedBadging = generateBadging.get().badging + + this.updateBadgingTaskName = updateBadgingTaskName + + output = project.layout.buildDirectory.dir("intermediates/$checkBadgingTaskName") - output.set( - project.layout.buildDirectory.dir("intermediates/$checkBadgingTaskName"), - ) } } } diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Jacoco.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Jacoco.kt index 7820a978e..972d539c6 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Jacoco.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Jacoco.kt @@ -24,6 +24,7 @@ import org.gradle.api.file.Directory import org.gradle.api.file.RegularFile import org.gradle.api.provider.ListProperty import org.gradle.api.tasks.testing.Test +import org.gradle.kotlin.dsl.assign import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.withType @@ -66,9 +67,13 @@ internal fun Project.configureJacoco( val myObjFactory = project.objects val buildDir = layout.buildDirectory.get().asFile val allJars: ListProperty = myObjFactory.listProperty(RegularFile::class.java) - val allDirectories: ListProperty = myObjFactory.listProperty(Directory::class.java) + val allDirectories: ListProperty = + myObjFactory.listProperty(Directory::class.java) val reportTask = - tasks.register("create${variant.name.capitalize()}CombinedCoverageReport", JacocoReport::class) { + tasks.register( + "create${variant.name.capitalize()}CombinedCoverageReport", + JacocoReport::class, + ) { classDirectories.setFrom( allJars, @@ -76,23 +81,28 @@ internal fun Project.configureJacoco( dirs.map { dir -> myObjFactory.fileTree().setDir(dir).exclude(coverageExclusions) } - } + }, ) reports { - xml.required.set(true) - html.required.set(true) + xml.required = true + html.required = true } // TODO: This is missing files in src/debug/, src/prod, src/demo, src/demoDebug... - sourceDirectories.setFrom(files("$projectDir/src/main/java", "$projectDir/src/main/kotlin")) + sourceDirectories.setFrom( + files( + "$projectDir/src/main/java", + "$projectDir/src/main/kotlin", + ), + ) executionData.setFrom( project.fileTree("$buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest") .matching { include("**/*.exec") }, project.fileTree("$buildDir/outputs/code_coverage/${variant.name}AndroidTest") - .matching { include("**/*.ec") } - ) + .matching { include("**/*.ec") }, + ) } diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/PrintTestApks.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/PrintTestApks.kt index 8e88f5a53..271fc51b7 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/PrintTestApks.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/PrintTestApks.kt @@ -33,6 +33,7 @@ import org.gradle.api.tasks.Internal import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.assign import org.gradle.work.DisableCachingByDefault import java.io.File @@ -53,12 +54,12 @@ internal fun Project.configurePrintApksTask(extension: AndroidComponentsExtensio if (artifact != null && testSources != null) { tasks.register( "${variant.name}PrintTestApk", - PrintApkLocationTask::class.java + PrintApkLocationTask::class.java, ) { - apkFolder.set(artifact) - builtArtifactsLoader.set(loader) - variantName.set(variant.name) - sources.set(testSources) + apkFolder = artifact + builtArtifactsLoader = loader + variantName = variant.name + sources = testSources } } } @@ -100,4 +101,4 @@ internal abstract class PrintApkLocationTask : DefaultTask() { val apk = File(builtArtifacts.elements.single().outputFile).toPath() println(apk) } -} \ No newline at end of file +} diff --git a/core/analytics/build.gradle.kts b/core/analytics/build.gradle.kts index 023574e6f..72f7620b0 100644 --- a/core/analytics/build.gradle.kts +++ b/core/analytics/build.gradle.kts @@ -16,7 +16,7 @@ plugins { alias(libs.plugins.nowinandroid.android.library) alias(libs.plugins.nowinandroid.android.library.compose) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) } android { diff --git a/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/AnalyticsModule.kt b/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/AnalyticsModule.kt index 111130a79..41b035875 100644 --- a/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/AnalyticsModule.kt +++ b/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/AnalyticsModule.kt @@ -16,9 +16,9 @@ package com.google.samples.apps.nowinandroid.core.analytics +import com.google.firebase.Firebase import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.analytics.ktx.analytics -import com.google.firebase.ktx.Firebase +import com.google.firebase.analytics.analytics import dagger.Binds import dagger.Module import dagger.Provides @@ -35,8 +35,6 @@ internal abstract class AnalyticsModule { companion object { @Provides @Singleton - fun provideFirebaseAnalytics(): FirebaseAnalytics { - return Firebase.analytics - } + fun provideFirebaseAnalytics(): FirebaseAnalytics = Firebase.analytics } } diff --git a/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/FirebaseAnalyticsHelper.kt b/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/FirebaseAnalyticsHelper.kt index 5a4b7f362..cedab6732 100644 --- a/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/FirebaseAnalyticsHelper.kt +++ b/core/analytics/src/prod/kotlin/com/google/samples/apps/nowinandroid/core/analytics/FirebaseAnalyticsHelper.kt @@ -17,7 +17,7 @@ package com.google.samples.apps.nowinandroid.core.analytics import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.analytics.ktx.logEvent +import com.google.firebase.analytics.logEvent import javax.inject.Inject /** diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index 51ae627dc..f1aa9771c 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -14,16 +14,12 @@ * limitations under the License. */ plugins { - alias(libs.plugins.nowinandroid.android.library) - alias(libs.plugins.nowinandroid.android.library.jacoco) - alias(libs.plugins.nowinandroid.android.hilt) -} - -android { - namespace = "com.google.samples.apps.nowinandroid.core.common" + alias(libs.plugins.nowinandroid.jvm.library) + alias(libs.plugins.nowinandroid.hilt) } dependencies { + implementation(libs.kotlinx.coroutines.core) testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.turbine) } \ No newline at end of file diff --git a/core/common/src/main/AndroidManifest.xml b/core/common/src/main/AndroidManifest.xml deleted file mode 100644 index 51d0cfc2e..000000000 --- a/core/common/src/main/AndroidManifest.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - \ No newline at end of file diff --git a/core/data-test/build.gradle.kts b/core/data-test/build.gradle.kts index b166df288..420c34a57 100644 --- a/core/data-test/build.gradle.kts +++ b/core/data-test/build.gradle.kts @@ -15,7 +15,7 @@ */ plugins { alias(libs.plugins.nowinandroid.android.library) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) } android { diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index 142637ff9..83c268aab 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -16,7 +16,7 @@ plugins { alias(libs.plugins.nowinandroid.android.library) alias(libs.plugins.nowinandroid.android.library.jacoco) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) id("kotlinx-serialization") } diff --git a/core/database/build.gradle.kts b/core/database/build.gradle.kts index 4a6bcb66a..8bab355b4 100644 --- a/core/database/build.gradle.kts +++ b/core/database/build.gradle.kts @@ -17,15 +17,11 @@ plugins { alias(libs.plugins.nowinandroid.android.library) alias(libs.plugins.nowinandroid.android.library.jacoco) - alias(libs.plugins.nowinandroid.android.hilt) alias(libs.plugins.nowinandroid.android.room) + alias(libs.plugins.nowinandroid.hilt) } android { - defaultConfig { - testInstrumentationRunner = - "com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner" - } namespace = "com.google.samples.apps.nowinandroid.core.database" } @@ -34,5 +30,7 @@ dependencies { implementation(libs.kotlinx.datetime) - androidTestImplementation(projects.core.testing) + androidTestImplementation(libs.androidx.test.core) + androidTestImplementation(libs.androidx.test.runner) + androidTestImplementation(libs.kotlinx.coroutines.test) } diff --git a/core/datastore-test/build.gradle.kts b/core/datastore-test/build.gradle.kts index 53e5e2c0c..375b1d3d8 100644 --- a/core/datastore-test/build.gradle.kts +++ b/core/datastore-test/build.gradle.kts @@ -15,7 +15,7 @@ */ plugins { alias(libs.plugins.nowinandroid.android.library) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) } android { diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index 34ea5ee78..b17bf6abd 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -17,7 +17,7 @@ plugins { alias(libs.plugins.nowinandroid.android.library) alias(libs.plugins.nowinandroid.android.library.jacoco) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) } android { @@ -33,7 +33,7 @@ android { } dependencies { - api(libs.androidx.dataStore.core) + api(libs.androidx.dataStore) api(projects.core.datastoreProto) api(projects.core.model) diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index bbb4ab97b..31635865c 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -46,10 +46,7 @@ dependencies { testImplementation(libs.hilt.android.testing) testImplementation(libs.robolectric) - testImplementation(libs.roborazzi) testImplementation(projects.core.screenshotTesting) - testImplementation(projects.core.testing) - androidTestImplementation(libs.androidx.compose.ui.test) - androidTestImplementation(projects.core.testing) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) } diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 689a99e73..d12482a56 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -17,7 +17,7 @@ plugins { alias(libs.plugins.nowinandroid.android.library) alias(libs.plugins.nowinandroid.android.library.jacoco) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) id("kotlinx-serialization") id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") } diff --git a/core/notifications/build.gradle.kts b/core/notifications/build.gradle.kts index 92871b72b..34393049b 100644 --- a/core/notifications/build.gradle.kts +++ b/core/notifications/build.gradle.kts @@ -15,7 +15,7 @@ */ plugins { alias(libs.plugins.nowinandroid.android.library) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) } android { @@ -28,5 +28,4 @@ dependencies { implementation(projects.core.common) compileOnly(platform(libs.androidx.compose.bom)) - compileOnly(libs.androidx.compose.runtime) } diff --git a/core/notifications/src/main/kotlin/com/google/samples/apps/nowinandroid/core/notifications/SystemTrayNotifier.kt b/core/notifications/src/main/kotlin/com/google/samples/apps/nowinandroid/core/notifications/SystemTrayNotifier.kt index 694f7a206..731ac7657 100644 --- a/core/notifications/src/main/kotlin/com/google/samples/apps/nowinandroid/core/notifications/SystemTrayNotifier.kt +++ b/core/notifications/src/main/kotlin/com/google/samples/apps/nowinandroid/core/notifications/SystemTrayNotifier.kt @@ -65,9 +65,7 @@ internal class SystemTrayNotifier @Inject constructor( val newsNotifications = truncatedNewsResources.map { newsResource -> createNewsNotification { - setSmallIcon( - com.google.samples.apps.nowinandroid.core.common.R.drawable.core_common_ic_nia_notification, - ) + setSmallIcon(R.drawable.core_notifications_ic_nia_notification) .setContentTitle(newsResource.title) .setContentText(newsResource.content) .setContentIntent(newsPendingIntent(newsResource)) @@ -82,9 +80,7 @@ internal class SystemTrayNotifier @Inject constructor( ) setContentTitle(title) .setContentText(title) - .setSmallIcon( - com.google.samples.apps.nowinandroid.core.common.R.drawable.core_common_ic_nia_notification, - ) + .setSmallIcon(R.drawable.core_notifications_ic_nia_notification) // Build summary info into InboxStyle template. .setStyle(newsNotificationStyle(truncatedNewsResources, title)) .setGroup(NEWS_NOTIFICATION_GROUP) diff --git a/core/common/src/main/res/drawable-anydpi-v24/core_common_ic_nia_notification.xml b/core/notifications/src/main/res/drawable-anydpi-v24/core_notifications_ic_nia_notification.xml similarity index 100% rename from core/common/src/main/res/drawable-anydpi-v24/core_common_ic_nia_notification.xml rename to core/notifications/src/main/res/drawable-anydpi-v24/core_notifications_ic_nia_notification.xml diff --git a/core/common/src/main/res/drawable-hdpi/core_common_ic_nia_notification.png b/core/notifications/src/main/res/drawable-hdpi/core_notifications_ic_nia_notification.png similarity index 100% rename from core/common/src/main/res/drawable-hdpi/core_common_ic_nia_notification.png rename to core/notifications/src/main/res/drawable-hdpi/core_notifications_ic_nia_notification.png diff --git a/core/common/src/main/res/drawable-mdpi/core_common_ic_nia_notification.png b/core/notifications/src/main/res/drawable-mdpi/core_notifications_ic_nia_notification.png similarity index 100% rename from core/common/src/main/res/drawable-mdpi/core_common_ic_nia_notification.png rename to core/notifications/src/main/res/drawable-mdpi/core_notifications_ic_nia_notification.png diff --git a/core/common/src/main/res/drawable-xhdpi/core_common_ic_nia_notification.png b/core/notifications/src/main/res/drawable-xhdpi/core_notifications_ic_nia_notification.png similarity index 100% rename from core/common/src/main/res/drawable-xhdpi/core_common_ic_nia_notification.png rename to core/notifications/src/main/res/drawable-xhdpi/core_notifications_ic_nia_notification.png diff --git a/core/common/src/main/res/drawable-xxhdpi/core_common_ic_nia_notification.png b/core/notifications/src/main/res/drawable-xxhdpi/core_notifications_ic_nia_notification.png similarity index 100% rename from core/common/src/main/res/drawable-xxhdpi/core_common_ic_nia_notification.png rename to core/notifications/src/main/res/drawable-xxhdpi/core_notifications_ic_nia_notification.png diff --git a/core/screenshot-testing/build.gradle.kts b/core/screenshot-testing/build.gradle.kts index fb23cf057..794416ba9 100644 --- a/core/screenshot-testing/build.gradle.kts +++ b/core/screenshot-testing/build.gradle.kts @@ -16,7 +16,7 @@ plugins { alias(libs.plugins.nowinandroid.android.library) alias(libs.plugins.nowinandroid.android.library.compose) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) } android { @@ -24,11 +24,10 @@ android { } dependencies { + api(libs.bundles.androidx.compose.ui.test) api(libs.roborazzi) implementation(libs.androidx.compose.ui.test) implementation(libs.androidx.activity.compose) - implementation(libs.androidx.compose.ui.test) implementation(libs.robolectric) - implementation(projects.core.common) implementation(projects.core.designsystem) } diff --git a/core/testing/build.gradle.kts b/core/testing/build.gradle.kts index 02729ceff..01696d5e8 100644 --- a/core/testing/build.gradle.kts +++ b/core/testing/build.gradle.kts @@ -15,8 +15,7 @@ */ plugins { alias(libs.plugins.nowinandroid.android.library) - alias(libs.plugins.nowinandroid.android.library.compose) - alias(libs.plugins.nowinandroid.android.hilt) + alias(libs.plugins.nowinandroid.hilt) } android { @@ -24,19 +23,15 @@ android { } dependencies { - api(kotlin("test")) - api(libs.androidx.compose.ui.test) + api(libs.kotlinx.coroutines.test) api(projects.core.analytics) + api(projects.core.common) api(projects.core.data) api(projects.core.model) api(projects.core.notifications) - debugApi(libs.androidx.compose.ui.testManifest) implementation(libs.androidx.test.rules) implementation(libs.hilt.android.testing) - implementation(libs.kotlinx.coroutines.test) implementation(libs.kotlinx.datetime) - implementation(projects.core.common) - implementation(projects.core.designsystem) } diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 5d8a65d44..5606cb5d1 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -20,9 +20,6 @@ plugins { } android { - defaultConfig { - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } namespace = "com.google.samples.apps.nowinandroid.core.ui" } @@ -36,5 +33,6 @@ dependencies { implementation(libs.coil.kt) implementation(libs.coil.kt.compose) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(projects.core.testing) } diff --git a/docs/images/graphs/dep_graph_app.svg b/docs/images/graphs/dep_graph_app.svg index 8a94310b2..8e5d9d429 100644 --- a/docs/images/graphs/dep_graph_app.svg +++ b/docs/images/graphs/dep_graph_app.svg @@ -1,383 +1,305 @@ - - - - - G - - - :app - - :app + + + + + + :app + + + + :feature:interests + + + + + + + + :feature:foryou + + + + + + + + :feature:bookmarks + + + + + + + + :feature:topic + + + + + + + + :feature:search + + + + + + + + :feature:settings + + + + + + + + :core:common + + + + + + + + :core:ui + + + + + + + + :core:designsystem + + + + + + + + :core:data + + + + + + + + :core:model + + + + + + + + :core:analytics + + + + + + + + :sync:work + + + + + + + + + + + + + + + + + + + + :core:domain + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :feature:interests - - :feature:interests - - - :app->:feature:interests - - - - - :feature:foryou - - :feature:foryou - - - :app->:feature:foryou - - - - - :feature:bookmarks - - :feature:bookmarks - - - :app->:feature:bookmarks - - - - - :feature:topic - - :feature:topic - - - :app->:feature:topic - - - - - :feature:search - - :feature:search - - - :app->:feature:search - - - - - :feature:settings - - :feature:settings - - - :app->:feature:settings - - - - - :core:common - - :core:common - - - :app->:core:common - - - - - :core:ui - - :core:ui - - - :app->:core:ui - - - - - :core:designsystem - - :core:designsystem - - - :app->:core:designsystem - - - - - :core:data - - :core:data - - - :app->:core:data - - - - - :core:model - - :core:model - - - :app->:core:model - - - - - :core:analytics - - :core:analytics - - - :app->:core:analytics - - - - - :sync:work - - :sync:work - - - :app->:sync:work - - - - - :feature:interests->:core:ui - - - - - :feature:interests->:core:designsystem - - - - - :feature:interests->:core:data - - - - - :core:domain - - :core:domain - - - :feature:interests->:core:domain - - - - - :feature:foryou->:core:ui - - - - - :feature:foryou->:core:designsystem - - - - - :feature:foryou->:core:data - - - - - :feature:foryou->:core:domain - - - - - :feature:bookmarks->:core:ui - - - - - :feature:bookmarks->:core:designsystem - - - - - :feature:bookmarks->:core:data - - - - - :feature:topic->:core:ui - - - - - :feature:topic->:core:designsystem - - - - - :feature:topic->:core:data - - - - - :feature:search->:core:ui - - - - - :feature:search->:core:designsystem - - - - - :feature:search->:core:data - - - - - :feature:search->:core:domain - - - - - :feature:settings->:core:ui - - - - - :feature:settings->:core:designsystem - - - - - :feature:settings->:core:data - - - - - :core:ui->:core:designsystem - - - - - :core:ui->:core:model - - - - - :core:ui->:core:analytics - - - - - :core:data->:core:common - - - - - :core:data->:core:analytics - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :sync:work->:core:data - - - - - :sync:work->:core:analytics - - - - - :core:domain->:core:data - - - - - :core:domain->:core:model - - - - - :core:database->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore->:core:model - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:common - - - - - :core:network->:core:model - - - - - :core:notifications->:core:common - - - - - :core:notifications->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_app_nia_catalog.svg b/docs/images/graphs/dep_graph_app_nia_catalog.svg index fa7cfca5a..151ee63ad 100644 --- a/docs/images/graphs/dep_graph_app_nia_catalog.svg +++ b/docs/images/graphs/dep_graph_app_nia_catalog.svg @@ -1,58 +1,45 @@ - - - - - G - - - :app-nia-catalog - - :app-nia-catalog + + + + + + :app-nia-catalog + + + + :core:designsystem + + + + + + + + :core:ui + + + + + + + + + + + + :core:analytics + + + + + + + + :core:model + + + + + - - :core:designsystem - - :core:designsystem - - - :app-nia-catalog->:core:designsystem - - - - - :core:ui - - :core:ui - - - :app-nia-catalog->:core:ui - - - - - :core:ui->:core:designsystem - - - - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_core_analytics.svg b/docs/images/graphs/dep_graph_core_analytics.svg index 9cb11e4eb..45f1c1eb0 100644 --- a/docs/images/graphs/dep_graph_core_analytics.svg +++ b/docs/images/graphs/dep_graph_core_analytics.svg @@ -1,13 +1,9 @@ - - - - - G - - - :core:analytics - - :core:analytics + + + + + + :core:analytics + - diff --git a/docs/images/graphs/dep_graph_core_common.svg b/docs/images/graphs/dep_graph_core_common.svg index a1cdcb610..91033eaa0 100644 --- a/docs/images/graphs/dep_graph_core_common.svg +++ b/docs/images/graphs/dep_graph_core_common.svg @@ -1,13 +1,9 @@ - - - - - G - - - :core:common - - :core:common + + + + + + :core:common + - diff --git a/docs/images/graphs/dep_graph_core_data.svg b/docs/images/graphs/dep_graph_core_data.svg index 8637b06ee..ab91bafb2 100644 --- a/docs/images/graphs/dep_graph_core_data.svg +++ b/docs/images/graphs/dep_graph_core_data.svg @@ -1,123 +1,97 @@ - - - - - G - - - :core:data - - :core:data + + + + + + :core:data + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:analytics + + + + + + + + :core:notifications + + + + + + + + :core:model + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:analytics - - :core:analytics - - - :core:data->:core:analytics - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:model - - :core:model - - - :core:database->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore->:core:model - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:common - - - - - :core:network->:core:model - - - - - :core:notifications->:core:common - - - - - :core:notifications->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_core_data_test.svg b/docs/images/graphs/dep_graph_core_data_test.svg index 798696c11..b9736c859 100644 --- a/docs/images/graphs/dep_graph_core_data_test.svg +++ b/docs/images/graphs/dep_graph_core_data_test.svg @@ -1,133 +1,105 @@ - - - - - G - - - :core:data-test - - :core:data-test + + + + + + :core:data-test + + + + :core:data + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:analytics + + + + + + + + :core:notifications + + + + + + + + :core:model + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:data - - :core:data - - - :core:data-test->:core:data - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:analytics - - :core:analytics - - - :core:data->:core:analytics - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:model - - :core:model - - - :core:database->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore->:core:model - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:common - - - - - :core:network->:core:model - - - - - :core:notifications->:core:common - - - - - :core:notifications->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_core_database.svg b/docs/images/graphs/dep_graph_core_database.svg index dd3aef7ee..e82d46436 100644 --- a/docs/images/graphs/dep_graph_core_database.svg +++ b/docs/images/graphs/dep_graph_core_database.svg @@ -1,23 +1,17 @@ - - - - - G - - - :core:database - - :core:database + + + + + + :core:database + + + + :core:model + + + + + - - :core:model - - :core:model - - - :core:database->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_core_datastore.svg b/docs/images/graphs/dep_graph_core_datastore.svg index 3bf13d087..f7502e55b 100644 --- a/docs/images/graphs/dep_graph_core_datastore.svg +++ b/docs/images/graphs/dep_graph_core_datastore.svg @@ -1,43 +1,33 @@ - - - - - G - - - :core:datastore - - :core:datastore + + + + + + :core:datastore + + + + :core:datastore-proto + + + + + + + + :core:model + + + + + + + + :core:common + + + + + - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:model - - :core:model - - - :core:datastore->:core:model - - - - - :core:common - - :core:common - - - :core:datastore->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_core_datastore_proto.svg b/docs/images/graphs/dep_graph_core_datastore_proto.svg index fd3bba9b6..7fcfb8358 100644 --- a/docs/images/graphs/dep_graph_core_datastore_proto.svg +++ b/docs/images/graphs/dep_graph_core_datastore_proto.svg @@ -1,13 +1,9 @@ - - - - - G - - - :core:datastore-proto - - :core:datastore-proto + + + + + + :core:datastore-proto + - diff --git a/docs/images/graphs/dep_graph_core_datastore_test.svg b/docs/images/graphs/dep_graph_core_datastore_test.svg index e42e5e795..37521a05f 100644 --- a/docs/images/graphs/dep_graph_core_datastore_test.svg +++ b/docs/images/graphs/dep_graph_core_datastore_test.svg @@ -1,58 +1,45 @@ - - - - - G - - - :core:datastore-test - - :core:datastore-test + + + + + + :core:datastore-test + + + + :core:common + + + + + + + + :core:datastore + + + + + + + + + + + + :core:datastore-proto + + + + + + + + :core:model + + + + + - - :core:common - - :core:common - - - :core:datastore-test->:core:common - - - - - :core:datastore - - :core:datastore - - - :core:datastore-test->:core:datastore - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:model - - :core:model - - - :core:datastore->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_core_designsystem.svg b/docs/images/graphs/dep_graph_core_designsystem.svg index f33d70705..737140876 100644 --- a/docs/images/graphs/dep_graph_core_designsystem.svg +++ b/docs/images/graphs/dep_graph_core_designsystem.svg @@ -1,13 +1,9 @@ - - - - - G - - - :core:designsystem - - :core:designsystem + + + + + + :core:designsystem + - diff --git a/docs/images/graphs/dep_graph_core_domain.svg b/docs/images/graphs/dep_graph_core_domain.svg index 68543466c..fe3740d2f 100644 --- a/docs/images/graphs/dep_graph_core_domain.svg +++ b/docs/images/graphs/dep_graph_core_domain.svg @@ -1,138 +1,109 @@ - - - - - G - - - :core:domain - - :core:domain + + + + + + :core:domain + + + + :core:data + + + + + + + + :core:model + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:analytics + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:data - - :core:data - - - :core:domain->:core:data - - - - - :core:model - - :core:model - - - :core:domain->:core:model - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:analytics - - :core:analytics - - - :core:data->:core:analytics - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_core_model.svg b/docs/images/graphs/dep_graph_core_model.svg index 66959f2f1..125684a08 100644 --- a/docs/images/graphs/dep_graph_core_model.svg +++ b/docs/images/graphs/dep_graph_core_model.svg @@ -1,13 +1,9 @@ - - - - - G - - - :core:model - - :core:model + + + + + + :core:model + - diff --git a/docs/images/graphs/dep_graph_core_network.svg b/docs/images/graphs/dep_graph_core_network.svg index 9902ee8e3..3022a86ee 100644 --- a/docs/images/graphs/dep_graph_core_network.svg +++ b/docs/images/graphs/dep_graph_core_network.svg @@ -1,33 +1,25 @@ - - - - - G - - - :core:network - - :core:network + + + + + + :core:network + + + + :core:common + + + + + + + + :core:model + + + + + - - :core:common - - :core:common - - - :core:network->:core:common - - - - - :core:model - - :core:model - - - :core:network->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_core_notifications.svg b/docs/images/graphs/dep_graph_core_notifications.svg index 3a1126ca8..d96d28769 100644 --- a/docs/images/graphs/dep_graph_core_notifications.svg +++ b/docs/images/graphs/dep_graph_core_notifications.svg @@ -1,33 +1,25 @@ - - - - - G - - - :core:notifications - - :core:notifications + + + + + + :core:notifications + + + + :core:model + + + + + + + + :core:common + + + + + - - :core:model - - :core:model - - - :core:notifications->:core:model - - - - - :core:common - - :core:common - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_core_screenshot_testing.svg b/docs/images/graphs/dep_graph_core_screenshot_testing.svg index 8021dcda6..a7d58b0ea 100644 --- a/docs/images/graphs/dep_graph_core_screenshot_testing.svg +++ b/docs/images/graphs/dep_graph_core_screenshot_testing.svg @@ -1,33 +1,17 @@ - - - - - G - - - :core:screenshot-testing - - :core:screenshot-testing + + + + + + :core:screenshot-testing + + + + :core:designsystem + + + + + - - :core:common - - :core:common - - - :core:screenshot-testing->:core:common - - - - - :core:designsystem - - :core:designsystem - - - :core:screenshot-testing->:core:designsystem - - - - diff --git a/docs/images/graphs/dep_graph_core_testing.svg b/docs/images/graphs/dep_graph_core_testing.svg index ac1b301aa..d441858e5 100644 --- a/docs/images/graphs/dep_graph_core_testing.svg +++ b/docs/images/graphs/dep_graph_core_testing.svg @@ -1,163 +1,121 @@ - - - - - G - - - :core:testing - - :core:testing + + + + + + :core:testing + + + + :core:analytics + + + + + + + + :core:common + + + + + + + + :core:data + + + + + + + + :core:model + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + - - :core:analytics - - :core:analytics - - - :core:testing->:core:analytics - - - - - :core:data - - :core:data - - - :core:testing->:core:data - - - - - :core:model - - :core:model - - - :core:testing->:core:model - - - - - :core:notifications - - :core:notifications - - - :core:testing->:core:notifications - - - - - :core:common - - :core:common - - - :core:testing->:core:common - - - - - :core:designsystem - - :core:designsystem - - - :core:testing->:core:designsystem - - - - - :core:data->:core:analytics - - - - - :core:data->:core:notifications - - - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_core_ui.svg b/docs/images/graphs/dep_graph_core_ui.svg index a36dd7031..2cd972357 100644 --- a/docs/images/graphs/dep_graph_core_ui.svg +++ b/docs/images/graphs/dep_graph_core_ui.svg @@ -1,43 +1,33 @@ - - - - - G - - - :core:ui - - :core:ui + + + + + + :core:ui + + + + :core:analytics + + + + + + + + :core:designsystem + + + + + + + + :core:model + + + + + - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:designsystem - - :core:designsystem - - - :core:ui->:core:designsystem - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_feature_bookmarks.svg b/docs/images/graphs/dep_graph_feature_bookmarks.svg index 8fbe423c2..0391eb39c 100644 --- a/docs/images/graphs/dep_graph_feature_bookmarks.svg +++ b/docs/images/graphs/dep_graph_feature_bookmarks.svg @@ -1,168 +1,133 @@ - - - - - G - - - :feature:bookmarks - - :feature:bookmarks + + + + + + :feature:bookmarks + + + + :core:ui + + + + + + + + :core:designsystem + + + + + + + + :core:data + + + + + + + + + + + + :core:analytics + + + + + + + + :core:model + + + + + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:ui - - :core:ui - - - :feature:bookmarks->:core:ui - - - - - :core:designsystem - - :core:designsystem - - - :feature:bookmarks->:core:designsystem - - - - - :core:data - - :core:data - - - :feature:bookmarks->:core:data - - - - - :core:ui->:core:designsystem - - - - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - - :core:data->:core:analytics - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_feature_foryou.svg b/docs/images/graphs/dep_graph_feature_foryou.svg index 6b8af3764..63a154a87 100644 --- a/docs/images/graphs/dep_graph_feature_foryou.svg +++ b/docs/images/graphs/dep_graph_feature_foryou.svg @@ -1,188 +1,149 @@ - - - - - G - - - :feature:foryou - - :feature:foryou + + + + + + :feature:foryou + + + + :core:ui + + + + + + + + :core:designsystem + + + + + + + + :core:data + + + + + + + + :core:domain + + + + + + + + + + + + :core:analytics + + + + + + + + :core:model + + + + + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:ui - - :core:ui - - - :feature:foryou->:core:ui - - - - - :core:designsystem - - :core:designsystem - - - :feature:foryou->:core:designsystem - - - - - :core:data - - :core:data - - - :feature:foryou->:core:data - - - - - :core:domain - - :core:domain - - - :feature:foryou->:core:domain - - - - - :core:ui->:core:designsystem - - - - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - - :core:data->:core:analytics - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:domain->:core:data - - - - - :core:domain->:core:model - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_feature_interests.svg b/docs/images/graphs/dep_graph_feature_interests.svg index b13783a27..2de1fc61f 100644 --- a/docs/images/graphs/dep_graph_feature_interests.svg +++ b/docs/images/graphs/dep_graph_feature_interests.svg @@ -1,188 +1,149 @@ - - - - - G - - - :feature:interests - - :feature:interests + + + + + + :feature:interests + + + + :core:ui + + + + + + + + :core:designsystem + + + + + + + + :core:data + + + + + + + + :core:domain + + + + + + + + + + + + :core:analytics + + + + + + + + :core:model + + + + + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:ui - - :core:ui - - - :feature:interests->:core:ui - - - - - :core:designsystem - - :core:designsystem - - - :feature:interests->:core:designsystem - - - - - :core:data - - :core:data - - - :feature:interests->:core:data - - - - - :core:domain - - :core:domain - - - :feature:interests->:core:domain - - - - - :core:ui->:core:designsystem - - - - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - - :core:data->:core:analytics - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:domain->:core:data - - - - - :core:domain->:core:model - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_feature_search.svg b/docs/images/graphs/dep_graph_feature_search.svg index ff299f33f..7f8f29777 100644 --- a/docs/images/graphs/dep_graph_feature_search.svg +++ b/docs/images/graphs/dep_graph_feature_search.svg @@ -1,188 +1,149 @@ - - - - - G - - - :feature:search - - :feature:search + + + + + + :feature:search + + + + :core:ui + + + + + + + + :core:designsystem + + + + + + + + :core:data + + + + + + + + :core:domain + + + + + + + + + + + + :core:analytics + + + + + + + + :core:model + + + + + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:ui - - :core:ui - - - :feature:search->:core:ui - - - - - :core:designsystem - - :core:designsystem - - - :feature:search->:core:designsystem - - - - - :core:data - - :core:data - - - :feature:search->:core:data - - - - - :core:domain - - :core:domain - - - :feature:search->:core:domain - - - - - :core:ui->:core:designsystem - - - - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - - :core:data->:core:analytics - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:domain->:core:data - - - - - :core:domain->:core:model - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_feature_settings.svg b/docs/images/graphs/dep_graph_feature_settings.svg index 1b9648d8b..3f0d35df2 100644 --- a/docs/images/graphs/dep_graph_feature_settings.svg +++ b/docs/images/graphs/dep_graph_feature_settings.svg @@ -1,168 +1,133 @@ - - - - - G - - - :feature:settings - - :feature:settings + + + + + + :feature:settings + + + + :core:ui + + + + + + + + :core:designsystem + + + + + + + + :core:data + + + + + + + + + + + + :core:analytics + + + + + + + + :core:model + + + + + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:ui - - :core:ui - - - :feature:settings->:core:ui - - - - - :core:designsystem - - :core:designsystem - - - :feature:settings->:core:designsystem - - - - - :core:data - - :core:data - - - :feature:settings->:core:data - - - - - :core:ui->:core:designsystem - - - - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - - :core:data->:core:analytics - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_feature_topic.svg b/docs/images/graphs/dep_graph_feature_topic.svg index 49fe361a8..b7c7dd26c 100644 --- a/docs/images/graphs/dep_graph_feature_topic.svg +++ b/docs/images/graphs/dep_graph_feature_topic.svg @@ -1,168 +1,133 @@ - - - - - G - - - :feature:topic - - :feature:topic + + + + + + :feature:topic + + + + :core:ui + + + + + + + + :core:designsystem + + + + + + + + :core:data + + + + + + + + + + + + :core:analytics + + + + + + + + :core:model + + + + + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:ui - - :core:ui - - - :feature:topic->:core:ui - - - - - :core:designsystem - - :core:designsystem - - - :feature:topic->:core:designsystem - - - - - :core:data - - :core:data - - - :feature:topic->:core:data - - - - - :core:ui->:core:designsystem - - - - - :core:analytics - - :core:analytics - - - :core:ui->:core:analytics - - - - - :core:model - - :core:model - - - :core:ui->:core:model - - - - - :core:data->:core:analytics - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:database->:core:model - - - - - :core:datastore->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:model - - - - - :core:network->:core:common - - - - - :core:notifications->:core:model - - - - - :core:notifications->:core:common - - - - diff --git a/docs/images/graphs/dep_graph_sync_sync_test.svg b/docs/images/graphs/dep_graph_sync_sync_test.svg index 58a31af19..7a083ba54 100644 --- a/docs/images/graphs/dep_graph_sync_sync_test.svg +++ b/docs/images/graphs/dep_graph_sync_sync_test.svg @@ -1,153 +1,121 @@ - - - - - G - - - :sync:sync-test - - :sync:sync-test + + + + + + :sync:sync-test + + + + :core:data + + + + + + + + :sync:work + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:analytics + + + + + + + + :core:notifications + + + + + + + + + + + + + + + + :core:model + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:data - - :core:data - - - :sync:sync-test->:core:data - - - - - :sync:work - - :sync:work - - - :sync:sync-test->:sync:work - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:analytics - - :core:analytics - - - :core:data->:core:analytics - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :sync:work->:core:data - - - - - :sync:work->:core:analytics - - - - - :core:model - - :core:model - - - :core:database->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore->:core:model - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:common - - - - - :core:network->:core:model - - - - - :core:notifications->:core:common - - - - - :core:notifications->:core:model - - - - diff --git a/docs/images/graphs/dep_graph_sync_work.svg b/docs/images/graphs/dep_graph_sync_work.svg index 2581a10ae..c649f2397 100644 --- a/docs/images/graphs/dep_graph_sync_work.svg +++ b/docs/images/graphs/dep_graph_sync_work.svg @@ -1,138 +1,109 @@ - - - - - G - - - :sync:work - - :sync:work + + + + + + :sync:work + + + + :core:analytics + + + + + + + + :core:data + + + + + + + + + + + + :core:common + + + + + + + + :core:database + + + + + + + + :core:datastore + + + + + + + + :core:network + + + + + + + + :core:notifications + + + + + + + + :core:model + + + + + + + + + + + + + + + + :core:datastore-proto + + + + + + + + + + + + + + + + + + + + + - - :core:analytics - - :core:analytics - - - :sync:work->:core:analytics - - - - - :core:data - - :core:data - - - :sync:work->:core:data - - - - - :core:data->:core:analytics - - - - - :core:common - - :core:common - - - :core:data->:core:common - - - - - :core:database - - :core:database - - - :core:data->:core:database - - - - - :core:datastore - - :core:datastore - - - :core:data->:core:datastore - - - - - :core:network - - :core:network - - - :core:data->:core:network - - - - - :core:notifications - - :core:notifications - - - :core:data->:core:notifications - - - - - :core:model - - :core:model - - - :core:database->:core:model - - - - - :core:datastore->:core:common - - - - - :core:datastore->:core:model - - - - - :core:datastore-proto - - :core:datastore-proto - - - :core:datastore->:core:datastore-proto - - - - - :core:network->:core:common - - - - - :core:network->:core:model - - - - - :core:notifications->:core:common - - - - - :core:notifications->:core:model - - - - diff --git a/feature/bookmarks/build.gradle.kts b/feature/bookmarks/build.gradle.kts index 4e97176a2..51a15ce7a 100644 --- a/feature/bookmarks/build.gradle.kts +++ b/feature/bookmarks/build.gradle.kts @@ -29,5 +29,6 @@ dependencies { testImplementation(projects.core.testing) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(projects.core.testing) } diff --git a/feature/foryou/build.gradle.kts b/feature/foryou/build.gradle.kts index f37bf4bb1..41d5b16a2 100644 --- a/feature/foryou/build.gradle.kts +++ b/feature/foryou/build.gradle.kts @@ -34,8 +34,8 @@ dependencies { testImplementation(libs.hilt.android.testing) testImplementation(libs.robolectric) testImplementation(projects.core.testing) - testImplementation(projects.core.screenshotTesting) - testDemoImplementation(libs.roborazzi) + testDemoImplementation(projects.core.screenshotTesting) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(projects.core.testing) } diff --git a/feature/interests/build.gradle.kts b/feature/interests/build.gradle.kts index 3cb4346c7..2b84b135f 100644 --- a/feature/interests/build.gradle.kts +++ b/feature/interests/build.gradle.kts @@ -30,5 +30,6 @@ dependencies { testImplementation(projects.core.testing) testImplementation(libs.robolectric) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(projects.core.testing) } diff --git a/feature/search/build.gradle.kts b/feature/search/build.gradle.kts index 98052e9ab..c5f1f6ad0 100644 --- a/feature/search/build.gradle.kts +++ b/feature/search/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { testImplementation(projects.core.testing) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(projects.core.testing) } diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts index 4b9a72bdd..15d65204d 100644 --- a/feature/settings/build.gradle.kts +++ b/feature/settings/build.gradle.kts @@ -31,5 +31,5 @@ dependencies { testImplementation(projects.core.testing) - androidTestImplementation(projects.core.testing) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) } diff --git a/feature/topic/build.gradle.kts b/feature/topic/build.gradle.kts index 0b554c936..bd8b59ec8 100644 --- a/feature/topic/build.gradle.kts +++ b/feature/topic/build.gradle.kts @@ -30,5 +30,6 @@ dependencies { testImplementation(projects.core.testing) testImplementation(libs.robolectric) + androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(projects.core.testing) } \ No newline at end of file diff --git a/generateModuleGraphs.sh b/generateModuleGraphs.sh index eacf19eed..3c3583e67 100755 --- a/generateModuleGraphs.sh +++ b/generateModuleGraphs.sh @@ -31,6 +31,14 @@ then 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. @@ -113,12 +121,10 @@ echo "$module_paths" | while read -r module_path; do -Pmodules.graph.output.gv="/tmp/${file_name}.gv" \ -Pmodules.graph.of.module="${module_path}" /-->\x0/g' | grep -zv '^