From 456630d4dc7d484b4ee17498bd6cfcb9a9c41e2f Mon Sep 17 00:00:00 2001 From: Maximillian Leonov <91663102+MaximillianLeonov@users.noreply.github.com> Date: Tue, 25 Apr 2023 09:31:57 +0400 Subject: [PATCH 01/33] Replace `if` condition with AnimatedVisibility component --- .../feature/settings/SettingsDialog.kt | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt b/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt index 847493a83..504fee4fe 100644 --- a/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt +++ b/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt @@ -18,8 +18,10 @@ package com.google.samples.apps.nowinandroid.feature.settings import android.content.Intent import android.net.Uri +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -149,7 +151,7 @@ fun SettingsDialog( } @Composable -private fun SettingsPanel( +private fun ColumnScope.SettingsPanel( settings: UserEditableSettings, supportDynamicColor: Boolean, onChangeThemeBrand: (themeBrand: ThemeBrand) -> Unit, @@ -169,19 +171,21 @@ private fun SettingsPanel( onClick = { onChangeThemeBrand(ANDROID) }, ) } - if (settings.brand == DEFAULT && supportDynamicColor) { - SettingsDialogSectionTitle(text = stringResource(R.string.dynamic_color_preference)) - Column(Modifier.selectableGroup()) { - SettingsDialogThemeChooserRow( - text = stringResource(string.dynamic_color_yes), - selected = settings.useDynamicColor, - onClick = { onChangeDynamicColorPreference(true) }, - ) - SettingsDialogThemeChooserRow( - text = stringResource(string.dynamic_color_no), - selected = !settings.useDynamicColor, - onClick = { onChangeDynamicColorPreference(false) }, - ) + AnimatedVisibility(visible = settings.brand == DEFAULT && supportDynamicColor) { + Column { + SettingsDialogSectionTitle(text = stringResource(R.string.dynamic_color_preference)) + Column(Modifier.selectableGroup()) { + SettingsDialogThemeChooserRow( + text = stringResource(string.dynamic_color_yes), + selected = settings.useDynamicColor, + onClick = { onChangeDynamicColorPreference(true) }, + ) + SettingsDialogThemeChooserRow( + text = stringResource(string.dynamic_color_no), + selected = !settings.useDynamicColor, + onClick = { onChangeDynamicColorPreference(false) }, + ) + } } } SettingsDialogSectionTitle(text = stringResource(R.string.dark_mode_preference)) From 22304d7fce0dd5919163609caa287ea2cc4ba233 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sun, 21 May 2023 11:31:37 +0100 Subject: [PATCH 02/33] Manually accept Android licenses instead of relying on third party action --- .github/workflows/AndroidCIWithGmd.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/AndroidCIWithGmd.yaml b/.github/workflows/AndroidCIWithGmd.yaml index e10c49f9e..f504540b7 100644 --- a/.github/workflows/AndroidCIWithGmd.yaml +++ b/.github/workflows/AndroidCIWithGmd.yaml @@ -30,8 +30,8 @@ jobs: - name: Setup Gradle uses: gradle/gradle-build-action@v2 - - name: Setup Android SDK - uses: android-actions/setup-android@v2 + - name: Accept Android licenses + run: yes | "$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager --licenses || true - name: Build AndroidTest apps run: ./gradlew packageDemoDebug packageDemoDebugAndroidTest From 100cd471619db0d02c7e6f44cd7b339754e3c189 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Wed, 24 May 2023 20:11:36 +0200 Subject: [PATCH 03/33] Grant `POST_NOTIFICATIONS` permission in more instrumented tests Continues the work initiated in #738. Extract the SDK version check inside a `GrantPostNotificationPermissionRule` class that delegates to a regular `GrantPermissionRule`. --- .../apps/nowinandroid/ui/NavigationTest.kt | 9 +++++- .../apps/nowinandroid/ui/NavigationUiTest.kt | 9 +++++- .../GrantPostNotificationsPermissionRule.kt | 29 +++++++++++++++++++ .../feature/foryou/ForYouScreenTest.kt | 17 +++-------- 4 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/rules/GrantPostNotificationsPermissionRule.kt diff --git a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt index 5aa3ab02e..036a2955c 100644 --- a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt +++ b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt @@ -33,6 +33,7 @@ import androidx.test.espresso.Espresso import androidx.test.espresso.NoActivityResumedException import com.google.samples.apps.nowinandroid.MainActivity import com.google.samples.apps.nowinandroid.R +import com.google.samples.apps.nowinandroid.core.rules.GrantPostNotificationsPermissionRule import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest @@ -66,9 +67,15 @@ class NavigationTest { val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() /** - * Use the primary activity to initialize the app normally. + * Grant [android.Manifest.permission.POST_NOTIFICATIONS] permission. */ @get:Rule(order = 2) + val postNotificationsPermission = GrantPostNotificationsPermissionRule() + + /** + * Use the primary activity to initialize the app normally. + */ + @get:Rule(order = 3) val composeTestRule = createAndroidComposeRule() private fun AndroidComposeTestRule<*, *>.stringResource(@StringRes resId: Int) = diff --git a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt index cd4b40a50..d92390918 100644 --- a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt +++ b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.unit.dp import com.google.accompanist.testharness.TestHarness import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor +import com.google.samples.apps.nowinandroid.core.rules.GrantPostNotificationsPermissionRule import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity @@ -61,9 +62,15 @@ class NavigationUiTest { val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() /** - * Use a test activity to set the content on. + * Grant [android.Manifest.permission.POST_NOTIFICATIONS] permission. */ @get:Rule(order = 2) + val postNotificationsPermission = GrantPostNotificationsPermissionRule() + + /** + * Use a test activity to set the content on. + */ + @get:Rule(order = 3) val composeTestRule = createAndroidComposeRule() val userNewsResourceRepository = CompositeUserNewsResourceRepository( diff --git a/core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/rules/GrantPostNotificationsPermissionRule.kt b/core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/rules/GrantPostNotificationsPermissionRule.kt new file mode 100644 index 000000000..512399d85 --- /dev/null +++ b/core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/rules/GrantPostNotificationsPermissionRule.kt @@ -0,0 +1,29 @@ +/* + * 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.core.rules + +import android.Manifest.permission.POST_NOTIFICATIONS +import android.os.Build.VERSION.SDK_INT +import android.os.Build.VERSION_CODES.TIRAMISU +import androidx.test.rule.GrantPermissionRule.grant +import org.junit.rules.TestRule + +/** + * [TestRule] granting [POST_NOTIFICATIONS] permission if running on [SDK_INT] greater than [TIRAMISU]. + */ +class GrantPostNotificationsPermissionRule : + TestRule by if (SDK_INT >= TIRAMISU) grant(POST_NOTIFICATIONS) else grant() diff --git a/feature/foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt b/feature/foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt index b138cba06..8dcdef6be 100644 --- a/feature/foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt +++ b/feature/foryou/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt @@ -16,9 +16,6 @@ package com.google.samples.apps.nowinandroid.feature.foryou -import android.Manifest -import android.os.Build.VERSION.SDK_INT -import android.os.Build.VERSION_CODES.TIRAMISU import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.ui.test.assertHasClickAction @@ -31,8 +28,7 @@ import androidx.compose.ui.test.onFirst import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performScrollToNode -import androidx.test.rule.GrantPermissionRule -import androidx.test.rule.GrantPermissionRule.grant +import com.google.samples.apps.nowinandroid.core.rules.GrantPostNotificationsPermissionRule import com.google.samples.apps.nowinandroid.core.testing.data.followableTopicTestData import com.google.samples.apps.nowinandroid.core.testing.data.userNewsResourcesTestData import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState @@ -41,15 +37,10 @@ import org.junit.Test class ForYouScreenTest { - @get:Rule - val permissionTestRule: GrantPermissionRule = - if (SDK_INT >= TIRAMISU) { - grant(Manifest.permission.POST_NOTIFICATIONS) - } else { - grant() - } + @get:Rule(order = 0) + val postNotificationsPermission = GrantPostNotificationsPermissionRule() - @get:Rule + @get:Rule(order = 1) val composeTestRule = createAndroidComposeRule() private val doneButtonMatcher by lazy { From c4689e2690218efa1f1102db0497e022d83dc19e Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 27 May 2023 10:40:43 +0100 Subject: [PATCH 04/33] Mention core-designsystem module in the modularization journey docs Closes #189 --- docs/ModularizationLearningJourney.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 81e35c436..f2f9b06bd 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -107,7 +107,7 @@ The Now in Android app contains the following types of modules: * `core:` modules - common library modules containing auxiliary code and specific dependencies that need to be shared between other modules in the app. These modules can depend on other core - modules, but they shouldn’t depend on feature nor app modules. + modules, but they shouldn't depend on feature nor app modules. * Miscellaneous modules - such as `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog` - a catalog app for displaying our design system quickly. @@ -159,13 +159,21 @@ Using the above modularization strategy, the Now in Android app has the followin TopicsRepository
+ + core:designsystem + + Design system, tokens and icons. + + NiaTheme
+ NiaIcons + + core:ui - UI components, composables and resources, such as icons, used by different features. + UI components, composables and resources, used by different features. - NiaIcons
- NewsResourceCardExpanded + NewsResourceCardExpanded From b0ad7a1d12e50d08dba57e2f6e19953e935eccca Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 27 May 2023 10:41:54 +0100 Subject: [PATCH 05/33] fixup --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index f2f9b06bd..8409fbf4a 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -107,7 +107,7 @@ The Now in Android app contains the following types of modules: * `core:` modules - common library modules containing auxiliary code and specific dependencies that need to be shared between other modules in the app. These modules can depend on other core - modules, but they shouldn't depend on feature nor app modules. + modules, but they shouldn’t depend on feature nor app modules. * Miscellaneous modules - such as `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog` - a catalog app for displaying our design system quickly. From 1a5a91f87103d2f66de6794c47103ec1dc3f9e23 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 27 May 2023 12:03:44 +0200 Subject: [PATCH 06/33] Cleanup proguard configuration - Remove custom KotlinX Serialization config as it's already provided, see https://github.com/Kotlin/kotlinx.serialization#android. - Delete empty config files. --- app-nia-catalog/proguard-rules.pro | 21 --------------------- app/proguard-rules.pro | 27 --------------------------- feature/settings/proguard-rules.pro | 21 --------------------- 3 files changed, 69 deletions(-) delete mode 100644 app-nia-catalog/proguard-rules.pro delete mode 100644 feature/settings/proguard-rules.pro diff --git a/app-nia-catalog/proguard-rules.pro b/app-nia-catalog/proguard-rules.pro deleted file mode 100644 index ff59496d8..000000000 --- a/app-nia-catalog/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle.kts. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 41012b47a..dcaf39ce7 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,30 +1,3 @@ -# Keep `Companion` object fields of serializable classes. -# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. --if @kotlinx.serialization.Serializable class ** --keepclassmembers class <1> { - static <1>$Companion Companion; -} - -# Keep `serializer()` on companion objects (both default and named) of serializable classes. --if @kotlinx.serialization.Serializable class ** { - static **$* *; -} --keepclassmembers class <2>$<3> { - kotlinx.serialization.KSerializer serializer(...); -} - -# Keep `INSTANCE.serializer()` of serializable objects. --if @kotlinx.serialization.Serializable class ** { - public static ** INSTANCE; -} --keepclassmembers class <1> { - public static <1> INSTANCE; - kotlinx.serialization.KSerializer serializer(...); -} - -# @Serializable and @Polymorphic are used at runtime for polymorphic serialization. --keepattributes RuntimeVisibleAnnotations,AnnotationDefault - -dontwarn org.bouncycastle.jsse.BCSSLParameters -dontwarn org.bouncycastle.jsse.BCSSLSocket -dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider diff --git a/feature/settings/proguard-rules.pro b/feature/settings/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/feature/settings/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file From 6dea47cee5f45b98748d43ca8fd89db272a3b17d Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 27 May 2023 12:07:36 +0200 Subject: [PATCH 07/33] Update KotlinX Serialization to version 1.5.1 https://github.com/Kotlin/kotlinx.serialization/releases/tag/v1.5.1 > ### Bugfixes > - KeyValueSerializer: Fix missing call to endStructure() (#2272) > - ObjectSerializer: Respect sequential decoding (#2273) > - Fix value class encoding in various corner cases (#2242) > - Fix incorrect json decoding iterator's .hasNext() behavior on array-wrapped inputs (#2268) > - Fix memory leak caused by invalid KTypeWrapper's equals method (#2274) > - Fixed NoSuchMethodError when parsing a JSON stream on Java 8 (#2219) > - Fix MissingFieldException duplication (#2213) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0be000440..f2d071b56 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,7 @@ junit4 = "4.13.2" kotlin = "1.8.20" kotlinxCoroutines = "1.6.4" kotlinxDatetime = "0.4.0" -kotlinxSerializationJson = "1.5.0" +kotlinxSerializationJson = "1.5.1" ksp = "1.8.20-1.0.11" lint = "30.3.1" okhttp = "4.10.0" From 48b8883cea9308997970053abdba5e7480f8c110 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 27 May 2023 20:51:41 +0200 Subject: [PATCH 08/33] Merge `AndroidCIWithGmd.yaml` into `Build.yaml` Add dependency on the `build` job, and add the same timeout of 55 minutes. Closes #761 --- .github/workflows/AndroidCIWithGmd.yaml | 49 ------------------------- .github/workflows/Build.yaml | 40 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 49 deletions(-) delete mode 100644 .github/workflows/AndroidCIWithGmd.yaml diff --git a/.github/workflows/AndroidCIWithGmd.yaml b/.github/workflows/AndroidCIWithGmd.yaml deleted file mode 100644 index e10c49f9e..000000000 --- a/.github/workflows/AndroidCIWithGmd.yaml +++ /dev/null @@ -1,49 +0,0 @@ -name: Android CI with GMD - -on: - push: - branches: - - main - pull_request: - -jobs: - - android-ci: - runs-on: macos-12 - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 - - - name: Copy CI gradle.properties - run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: 17 - - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 - - - name: Setup Android SDK - uses: android-actions/setup-android@v2 - - - name: Build AndroidTest apps - run: ./gradlew packageDemoDebug packageDemoDebugAndroidTest - - - name: Run instrumented tests with GMD - run: ./gradlew cleanManagedDevices --unused-only && - ./gradlew ciDemoDebugAndroidTest -Dorg.gradle.workers.max=1 - -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true - - - name: Upload test reports - if: success() || failure() - uses: actions/upload-artifact@v3 - with: - name: test-reports - path: '**/build/reports/androidTests' diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index a3b328dcb..f28a9a89c 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -5,6 +5,7 @@ on: branches: - main pull_request: + concurrency: group: build-${{ github.ref }} cancel-in-progress: true @@ -108,3 +109,42 @@ jobs: with: name: test-reports-${{ matrix.api-level }} path: '**/build/reports/androidTests' + + androidTest-GMD: + needs: build + runs-on: macOS-latest # enables hardware acceleration in the virtual machine + timeout-minutes: 55 + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Copy CI gradle.properties + run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 17 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Setup Android SDK + uses: android-actions/setup-android@v2 + + - name: Build AndroidTest apps + run: ./gradlew packageDemoDebug packageDemoDebugAndroidTest + + - name: Run instrumented tests with GMD + run: ./gradlew cleanManagedDevices --unused-only && + ./gradlew ciDemoDebugAndroidTest -Dorg.gradle.workers.max=1 + -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true + + - name: Upload test reports + if: success() || failure() + uses: actions/upload-artifact@v3 + with: + name: test-reports + path: '**/build/reports/androidTests' From 769e5dd458eff252dad9321c1fce9f6c4d01f654 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Tue, 30 May 2023 23:06:40 +0200 Subject: [PATCH 09/33] Keep track of matching `Network`s inside `NetworkCallback` This will ensure the connectivity state remains synchronized with the `ConnectivityManager`. Fixes #714 --- .../util/ConnectivityManagerNetworkMonitor.kt | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt b/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt index b0bf9d820..d55520646 100644 --- a/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt +++ b/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt @@ -20,7 +20,8 @@ import android.content.Context import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback import android.net.Network -import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkRequest import android.net.NetworkRequest.Builder import android.os.Build.VERSION import android.os.Build.VERSION_CODES @@ -44,36 +45,31 @@ class ConnectivityManagerNetworkMonitor @Inject constructor( } /** - * Sends the latest connectivity status to the underlying channel. - */ - fun update() { - channel.trySend(connectivityManager.isCurrentlyConnected()) - } - - /** - * The callback's methods are invoked on changes to *any* network, not just the active - * network. So to check for network connectivity, one must query the active network of the - * ConnectivityManager. + * The callback's methods are invoked on changes to *any* network matching the [NetworkRequest], + * not just the active network. So we can simply track the presence (or absence) of such [Network]. */ val callback = object : NetworkCallback() { - override fun onAvailable(network: Network) = update() - override fun onLost(network: Network) = update() + private val networks = mutableSetOf() - override fun onCapabilitiesChanged( - network: Network, - networkCapabilities: NetworkCapabilities, - ) = update() + override fun onAvailable(network: Network) { + networks += network + channel.trySend(true) + } + + override fun onLost(network: Network) { + networks -= network + channel.trySend(networks.isNotEmpty()) + } } - connectivityManager.registerNetworkCallback( - Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(), - callback, - ) + val request = Builder().addCapability(NET_CAPABILITY_INTERNET).build() + connectivityManager.registerNetworkCallback(request, callback) - update() + /** + * Sends the latest connectivity status to the underlying channel. + */ + channel.trySend(connectivityManager.isCurrentlyConnected()) awaitClose { connectivityManager.unregisterNetworkCallback(callback) @@ -86,7 +82,8 @@ class ConnectivityManagerNetworkMonitor @Inject constructor( VERSION.SDK_INT >= VERSION_CODES.M -> activeNetwork ?.let(::getNetworkCapabilities) - ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + ?.hasCapability(NET_CAPABILITY_INTERNET) + else -> activeNetworkInfo?.isConnected } ?: false } From d19c4efb2cc32effad9f681ea2056a57e03fbb6a Mon Sep 17 00:00:00 2001 From: Maximillian Leonov Date: Thu, 1 Jun 2023 11:14:04 +0400 Subject: [PATCH 10/33] Add comment for ColumnScope usage --- .../samples/apps/nowinandroid/feature/settings/SettingsDialog.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt b/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt index 504fee4fe..959d17797 100644 --- a/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt +++ b/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt @@ -150,6 +150,7 @@ fun SettingsDialog( ) } +// [ColumnScope] is used for using the [ColumnScope.AnimatedVisibility] extension overload composable. @Composable private fun ColumnScope.SettingsPanel( settings: UserEditableSettings, From e50d4870a9af3ff3a161020a455cd1e4fc82204c Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Fri, 2 Jun 2023 22:29:28 +0200 Subject: [PATCH 11/33] Add IntelliJ IDEA icons --- .idea/icon.png | Bin 0 -> 9710 bytes .idea/icon_dark.png | Bin 0 -> 10926 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 .idea/icon.png create mode 100644 .idea/icon_dark.png diff --git a/.idea/icon.png b/.idea/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c91b32cd910818b03875c28181e1a79c51ffc9de GIT binary patch literal 9710 zcmY*_00KlJ$a?;vf zCP&#AY1-4@2Jl#6ff~-SQ67IW(K)TL*~kTr2;KVM2o+)%?4py)#=wN=ICsgL%pZ-& zNtp5&FezC$oRKUORNeU4KJjtFaHO4>Fy$r$Z*Cm2s|`}W?5)(Ja~or&AviOP;bb^AhmOAI>9$M68!p(r{AE0sH>F7|DSPigF;fn z9qQ^vreB+cGYEsr1d|lKa5Hk)3UwJ9%+ow<_5-SnS^*=}$5>ukGxSSxObV~S1`F)6 z3B+q?0I!GFfHl@?bU^f%Fzt^NF(ivr0gTQvYz-`{`gpg73=y3>ohNbB8eav^6-hKNwX5TFGv5kX?#?XUz!Tbq#FSLLHV# zXU$~48$K!SK|v#M?RF=2=ELJ@?l&ukqDCeu4$bIuEg7g6m#HzZ5`8F)NuGAEzL<_o z#U!G+H-;uqn{%6P6wT5Kl!rKCAG1Q$ZXA=pz18yA?MNg(=Rn8l{6#{NtdW-qco?f&-233q1ni(G{Mcmy8Ql z{lZw5WEUp#6RE9aRfq3FXM-jD!khkk>GxKglT>J*Q=YIa4l{d#daaNz)t zPoJ|TcFXtiTvnCo>Bgnby=DUxOo~5yT*;HhIFC9cxc*nee|IzEIa8o4q0(zLFCBJt z^^04dVgB9eHh84B%5@<~K;w*AgQ7212tTz`)`be1DOwd?_TH`3atC*5Fe{a?j|Tj{ z`>Mc_eevdg=*uFhN&yYqd$>vD25#XF)uZu`Z%4jQo6@Ozr=s>(Cy6AEge0#G%vCz# z6YPKwCX#nfi@RMwQA95wt9nC0qd*$l{BTUQ-kAdDQe%cyZI%9+((edslp}`uVr+@_ zba3VDZ2^Ad4y<-dmeNV!alzEuop%JG~m3RBZH}B2ycW5#|zvl*o8XFDKyB4 zPh!|BFI)@NZS)pF*rjIEaxG6oH+9oMTT+Y30^9l&A&oT#z~4E!xmh;7U(~g~#$Rf4 zHrU%7P%81S@0aFRFM3nv-;D+Y)0- zmSRWQA5r}uDA%^WVg*jZ(0n73bz=6r0JGEdxt=?nY}za7ma`UVI>i>kvNr=0A(f~_ zW-G@x*4V=Y9xrvTXn_jZS}G+Zt>LpttA*;Uddv!(shUhiol;@%Px3?0J-R^oPAx8t z`kW*#hE|MnWPUI|9H)Hmyflt{D{^6d_)VL?Xzm#@Oc@}7DXd7@iITX$bD&-&I)+GgMvkm zh<&^C-FAO72wjZwTI_+GC*;Xc&}iJ$f0w9c>QlZBcZv9E(WVge4S>>pxz39H*2wwn znZ{#|A&uWw_cT7>k?D57qJ|Q7e{~QHR8B#r5%q{E)?yWyw@fmdD${^2{Is>$+v)W^ z=^&$a>PDz@V*?BW!8y?@fMj%yKRe-x%QO1U8o9^IZ37Ck+Pnv~`{ezN_(}l1VK`Xu zK#^^LB=0q9w^9uICs|347Jg#&W@a3(L4$+2x*p$NAF*iw@~C~^A0EpH&9RlJ>s&qO z@t_Eub|YDwBvZj7>3Mq7^&$@cpC%yHf(hnQ+s7oc@Ze}wD`#iLHgm1#g`$9+Y^zVZ zkJYftDnbTTQBJCuJx;|P&Yg+NK?Z|Zbu8t7sawan5 zG4+9jMwcA29rdI?Ez}itPrTNPCy5;=albovF&4V)xhkF}=xD-0r&9?S?knx1h3R_m zD*TLM!ew81oVTkV3zEeX=OdT!^Ku#jrXn+e;;^0fic?W%O?>Tf^|NM@jZKRo6;+Lx zV3EC|HFz?N5B=IoH8n{!<%Yl_@&aC-p)-b#G|GiRYZ=lYMcy>&S7C%k9M`g5t0WXp z=5)uq6NSM#6}o*sv+(R>xb~Y2?0I+5Vcr|I21TR87Mug+*5Eh$wHt8gjg$aHvbaYC zj1NIOiyL&nP*R`Rd>wdfmbb-Pa%Zf~OvZRe#V`C_K=iG;e3vLSW^@C}si9%5vWgFgRJl zBev|4W>NRPs}Z)EY|wodGV(j?TThqJIM)tBjG>e4R5aw%0&Fp}B=){9bnK+K-220F?H4NDGK7F*H*J4DiEe`Gs}Q>Q z!rAJ!M;JrF%iMS)P=(3;VL15{y`Ig@w*g(; zYv($jtNpbvXtd}a%kH!Klw&AX!Ok;!mHGrDc&-Q&eiwdxv6!JQMAbPADQ&<9ggJ0V zH!x9E=zik6^k-gZnzHAzyIwSG-gznv78Di~$|Cdc> zlW*1v2vRjB9siauM|ibk!8p4V`W9>Hfb)>a5M~}Oj8jt{*Gbk|1>w;@P_ElOE)>{6fdjGn6WaeKE4NC0$sg-|32 zQN<@TaySZ3az&OAdU$jW*6-q?%F;BT0FNXh{CBM6ifEWaLdb~x5z!1uo*|_eQ%j`o zn}7Jj(;rY5l|9}yn@J#&5^U7(nORU!SSlR1gvh!gBmOqkt@IDbmj@SqF6#Ecp5>UQVrKRW$U6-4<{ zqKftB^Z5`(E@*?>JNrmklCVrQ!L!I&WGg_ zR4g*inBqlzu<%y0zK9O`78?ubMUEp?S{k!^!A1|^`#xn+ShqvvAF$|~+dsL_#G|>A zUDEhUnU z8>;z#A6VAb>vPt3Rn@VXtiiPvrtGt0t3 zlley33@N=%6kswwqDsu}NT)^e$JGDvb0B()+lW&MVNP<$L@6%iPq1^vvp#YBlvIlk zeErw|Bm_r?fdWuPJhqWMlvRfJ;jGT0rAQ$pR*@(>2c3`flMA7B?g2U$MN2@kCqpT)=sgRz{ko$ff5$I#eu2rhO8jZ zBrQb1@%n=%^Z|iZQGRepz<$B(g^oF;9w;BEJw?zT29aOpM15f&9}p8GMAiwMha3e6 zVR=S-1nNu?Sdqp$5qhHR`T-QO>AHm<2IvC(yv%e4;%F=aYCH~Gc5>E-TpkYV)eapo z!bjx&bef0J0sqIgKddM7xf4o&N*DR0{{0;SZfxsjqH>Snj3nIPbo6PLcN!a9=YKu_ zvA1yU<#9){Y0zHqL&)_r^?Gj>iBX@Y&O_HL6sajZGYLTKcmA~3*M;Sn;SL>FGwWM~ z$HEyPy3cNhEuWCHd*SpiT}v?4)ZhEC1(|8H;Pn9H!qv0RD6}59_`bb1h z3SWRUN5GTI`LQ80VJgqG%U`$?P}r^Jf1Whw`YpoaXaVJB+0zt^b~?)YtLP15NrzqB2Q|N_wJfkbE?0aTOW|#%MtEuo~ZCspON* zVM_?pW|j?C+;K>>6QM)On|mS>Pfcu4;fz_HB@0Yb5EGyDX>s*g7ldrLX8LkJYi`Yb zZ&z&AcGQS~)#gX= zqY>_&>_`7x9?7<-Eyi)j_sm`UM1=0y<{ptpR!(0mc~e?7%yzOpadY5R9W}7|ZaXv6 z4pZ8N^cxPv+gIfLpR~!H8J2wDp+eIt1>>;fa<|+H*gECF7tY$*03F`g+ikY$_VeLW zns-G+YGORt?*(*t8t1Jt*J=WuY>kC^g8SoWsC+rsf3M`OzR$uy(*Vrg*^{D38GTG6 zDG;KyrnluDRNsGxz~=HhPg=NR$keuIKjDG=m=TFCh@1%JhArhjvAY;$MX@@*1@)K zc^xmgW513QjqiVRj5}(>hn^RZ7(b-)NUI)D7`vyJf4Dx9g|xtYFDF0;S14&3{UOlw z$K?}$vXwtriiMl@;5_n?R4%*|j!t+6^xleZYkg)S3-FwMIDM`)?}hvVQZqEEP~3T! z>mT#np^#;c-Ni;;D2t#<&TQvaG?o%4(ziN>4cO>pMlU#G4V9BS;KeD`G zwKmDgRT$`Fl(Z@(vbe&pKm@x_g#=vN(wd~#$O{i#1d9*7;zH>E8#NAbw2{E0=a~`v z$}w@HKG+F75KosYn}~u%ip>YaW1tf$G48&5U3Jo+0Lmzwdq=P4Gv5iv2+8M7WZH2=65Oxffu07>J2(joqM5Tq@ z^AJ4NVn8H+Xhc39wGg)(ISX~b;_^umoz7B@ciKWLoJb0kYa7EWWaj}1|X^b_6) zGwAvGA@VFyS`kHGOmcslDG!_^p$njAJNHv48sf&y6SGL59TbtL=xIi0rdaWhYDr{)4Drn!sFHBPM~rM%8D@b3H$!Uc-_DF4tJ%!@elG z!OzR^gPek^`BA4-5h9Hc*`JB@15FanG>|xTbKi^%nE~>4b})h=rg5tqhMu+V`KGSx z7XVbA%y=p>UlaI(w!IVI=Yoa{1qyv5hZ{=s8f!(^e+sGQ4%P3f1KUX(!syI!#LYXc zdwqy;-ysT2Gz1csEqARrZKXm~>6!}-X{Ij~L;f1(Zt{kvHAp4-rUfn2Cm;%vrR^F0 zuvDy+7FR-2F3r@yNPe7qYRXvkRX7IM$Yn}sIIA+mVopcBQCACIjeg@+|K{7A|HDx* z8l7KlK`LJZUmCD$EeH$ZZj2ft7Wjy|B#8i8Qz9FB_nFY~UQWJHrd1_q2+K~Gnb*lK zhuHA;2PkZg*k$BR6O8hA;a+#V$a)A7#C-*MO4WnnoQv2OOT(?FLWi`CU&lx*LJ@2H zQ_Te$T+o_beDnj`0h6a+TS?Ynl6JJG8)5v5a`%*&1byS*!L->_SEDnG`@3>apZJpif1N0eo33IRbNcoiH`t z=(Tm}==r257d!_#*E20X8EZ!|%R`BJ->zevK6 zvi8IN95^_u6fc|RHa`c_)|oIh{uWn7$#U?o#xI3Lp>!m~-!^cdb33J2VP#tAPI5=ja^YfFB>bUn{(yn7$XJ6RHfWcEE=JVbaBIN$;#rB>NH9Uupu6m+ z>&mxB0_s0DYra+fIp}}TT79T!2G@ZTHOyp;zat|p%!!)(EWnJyb>@r2^K7Km*D>t= zjMz||NLLT?^>UDq9nnfLa(kHy*|wM)|`HcUbIPr!JVaNWDt zB(T;KI6FKIONNVsXdS*cxcxB{MC~^#zI7k}07Sw*jHICKv{+M<$6DQ=+&7mZVU#XZWsjea>m!cbPkg!Ltj7D)2J5gRT zxy-ip@qeHsI*6E~#7!$AvY{bNU&_m5U-|wfjkrS*_qiMt-m5Gp7jd(0ICJ6lI$g{9 zOOzD%PvQ|HVl}`;5f@k=-SsUFO1~MLFaC5Mh*F}8mt^;=X0!BYU26KPX=uEJ zz8|7i`XOtZDI*CcdY3#`n=R%{wK0|3{?zMtgk+D|L`(%I%p_Szn0EzRPG2-ZtL!9h z@5VbuIPYG*+9{w%MO;$JWDp0Ef98A9NLEImf0;E6c#5S^>;iHq@%?I; zM-P8&_)uj@W1{8{nqpBO(3dUZhs=f^eq?izw2-9@f79~v{BXcuN`=!IEAZ}hH`M+x zMZrNga)s%u{TSuCg=ZV04w z{!XFXpR$f;>0;6V{vLW;(tnd2b79GL6^MX@`uM9S6syaU&7kgcF5#+Jom>^b(w!zs(fGH$>%P_X>n3fue>-B z)&R6OAju!s?9)Na=CLv!LW|cbvVKoGL?9#|?w;=x z7SgwZq6Ncyt_{R#MUdF!wwCNwVf2GYmK;_a#EHGDE@rRp^|mAyHUH^`A@2qp`>8q$ z&_a|z;gPj$_WISPqa1u&Il_-F5JGy}9#;<6Umom!PV1)0Jy4ZitvUbgUv4vl2Duv% zLp9NTimZc4kdBef5_iL>9MC!2PkYuDY-@06y*Crog$sU_pcqB+nfHXO>2=-fcu5O^ zq*5j?4t7B_R3RhuR=;vOo*Ne(9y)BIR~j(v>*3t8{(BNPi~T$J)Q=Zv)t=wMbP#os ze{kqB$^At2weNbm&Nr2c=l$1JfV0idIXSz9@e&33!&ao;`cnQXG=snF?p%L~lZnA4 zZLYM0GsK0!Ms5kh>&~3Dyad{XIDyMeE=_HWC3FH@;zmnr!t|Vy@HkXdv}M1Gu_pND z;0nBPov`?u#_ujy=24cdX8cw}vx(PgRNouU9%K34{cHam5N&8Dg$oo^Eh)sa1VqXd zYkb)!tJT(3E#O4;Z7YPrNpHa9?b+X#oAT0}`;Az^6?D}M6(k>dR{XCk49|kM7)!6Y z;q@ICTz-kOf!BA3lD0K!%YRVQ8`a^sn!c+bpJ959u0Zo|`ftto8L@rWsL~kH-kJ05 z@>>pmbv@~Nd2WGso1de619+p>Kq0934A1W(;PPknD?d=lwymjQ06U)Z)t51Hx3?C4xkqiw%qgex zuz5#7PJ$~(z^s~aIrVsVG0S_9iIGh>T)`XvU6G=|D$d!d3s^LS{I}ivVuosiYY_iM zir=$LYd=L~e2U-w`1)P~HZPOt$k%;r$;3YqPFZKA;mJtEXHr7oo9%ntBJ2OKxC#~= zKhGdD_2V%@tXlsQ!{}#N9+g-0GTeW9K%6^Baq(JB>ouX$tK zdPzmSJzBPwp^*Q!=sm;v*A=&Gs^00E+jk|0RCNBg>$3wf6t13K{!idI{D7C3>|b`A z?uyx(O_b}AVS?g!hSEzD^q)xUpaxID>ICHdIM!?G1To^ibAt&?0sQc^7>KDftHQf> zWR5W)djLnvY%=&YYa>kleQAFmHJ@99^Q zOYaOq3bX8S8kPDU(EXnGCxnXslAv+fWAS&L)(4@D2&Q{@ljB}8_UWOB4JnSdi4DRm z&3GhVh&e&2L~!R}jF-#s`Syill|B(^k1pWxj0ArCoh0cQyH7jfN<5YD zJG^z5GuHU1dh2tYGfg;!=B3E_Ad_0_MihH> zE8Kg!bhws76;1l)KC$B`$Nl|gl3EWxpEt2gLLs?^Tx1sBgeP_F%Iin4L=Ue^oj3s~ zU?>r23eJ^y!WriNG*woin*Lm#?fyx2Lu*@QK5`#_M2~9q=&ibhwbA_BY>=gI|o*#eO3BUT(gOhZN$5H;gkfFM^ z7_+DGQRX$Z{804nMFyC8jQcY&{*S*fUZr&yr%|)h5xiTl!rk$BNafIMeh6=!h0jb) zQI~J2PktOOv%+0h*$-^Z1D8>$Jz^%@6C;SGH1j85GdoR*VS-R15Tv=WvWEC|B9KHq zkNsfXUyy#4=)oJ8hfhiHq>yyqpPJnnO|Q3tUl=){XVSx7w=AHp(5t~EK^{mF?@QCV zdx!LlQ>XFj(0!C_l&g{Q?RlPEj7-0?v7qPi5`WlX&4vBBl*zcrK_zr^Z1apBDCS*? zoeY%qDG***)Up}|)2Ne8VYvT|G&LvGL3U5!_uG%dgf-a$3$am`r&OYDvE7-FLl&I} zXdWN}@B-fQ_8Yuz9#a)uzLfNYvqieySUR8G{Nnx?pY#>)?a}lTa(VB7m3D7-G7kOP zg*08(F-m{I!eJ%Z!<&y|8CT=*?e{*6!Y1Xc`b^Pk*?T7&FQJ5I?OVckfVixgjqy_%sx0w@{wLPd>kCzYeDn zwjgSmc_`7(y1h<7|yuC-ci+(tXw=6OPd^F{4wwq|wj>EVVBaGU+|*HNsu zzCFoX@5qB}{pMD{dr;0Xt$aCEEOAyPXGruz9!GNI4~>4mjt;8nGgyt2hP)F9Wn)3( zLtZLOuA2u2uKrdj6T*bdoFuJwXlv$U`Yt4x9^OKAm}f7bm;d6a_}?{}D^WjQive4_ z6T+PK#E<7-ih`ojN(aZ2LJ=J{_(b$5(oUgrX6I<4?@59z#JPbH8Eyp1Vk+2KN`ne` z*gSPDdkOOl@@W$&ZKXzXFV!rszoObCFxy<^=Q(gEg&&k($#yF5{H z$P;fZ84)~B5T{!g-|OIu-qeaJgOs_j(pMrP?gT%?JXDvE0b5zxQsp9)d+w8&FoCWT jnjiwzS)xvr^Os3S*Sz_b2|D;aE`XvuSgu;eEa-m$3Ra&> literal 0 HcmV?d00001 diff --git a/.idea/icon_dark.png b/.idea/icon_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..cc8a9c1b015bec59cb4e4070ff648857844d67e1 GIT binary patch literal 10926 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 Date: Fri, 2 Jun 2023 21:51:42 +0100 Subject: [PATCH 12/33] Gradle configure cache property is no longer `unsafe` https://docs.gradle.org/current/userguide/upgrading_version_8.html#configuration_caching_options_renamed --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 10ff2e365..94e673a47 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,7 @@ org.gradle.configureondemand=false org.gradle.caching=true # Enable configuration caching between builds. -org.gradle.unsafe.configuration-cache=true +org.gradle.configuration-cache=true # AndroidX package structure to make it clearer which packages are bundled with the # Android operating system, and which are packaged with your app"s APK From 9f41929dc0aa983b6e724e5fecf984a8fb3ba8d2 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Fri, 2 Jun 2023 21:56:42 +0100 Subject: [PATCH 13/33] Update default build features value in `gradle.properties` --- gradle.properties | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 10ff2e365..bf98b4553 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,9 +35,6 @@ kotlin.code.style=official android.nonTransitiveRClass=true # Disable build features that are enabled by default, -# https://developer.android.com/studio/releases/gradle-plugin#buildFeatures -android.defaults.buildfeatures.buildconfig=false -android.defaults.buildfeatures.aidl=false -android.defaults.buildfeatures.renderscript=false +# https://developer.android.com/build/releases/gradle-plugin#default-changes android.defaults.buildfeatures.resvalues=false android.defaults.buildfeatures.shaders=false From a68b544da54459f71861f3f6a136bb4067be455e Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Fri, 2 Jun 2023 22:13:56 +0100 Subject: [PATCH 14/33] Revert "Remove `ExperimentalCoroutinesApi` and `FlowPreview` opt-in" --- .../com/google/samples/apps/nowinandroid/KotlinAndroid.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt index edffeeda7..976183aa4 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt @@ -88,6 +88,9 @@ private fun Project.configureKotlin() { allWarningsAsErrors = warningsAsErrors.toBoolean() freeCompilerArgs = freeCompilerArgs + listOf( "-opt-in=kotlin.RequiresOptIn", + // Enable experimental coroutines APIs, including Flow + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + "-opt-in=kotlinx.coroutines.FlowPreview", ) } } From 06d07dbca4b15a888065aa23679c15442fa8dcca Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 3 Jun 2023 14:09:55 +0200 Subject: [PATCH 15/33] Apply changes from review comments --- .../core/data/util/ConnectivityManagerNetworkMonitor.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt b/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt index d55520646..c88125be8 100644 --- a/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt +++ b/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt @@ -20,7 +20,7 @@ import android.content.Context import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback import android.net.Network -import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities import android.net.NetworkRequest import android.net.NetworkRequest.Builder import android.os.Build.VERSION @@ -63,7 +63,9 @@ class ConnectivityManagerNetworkMonitor @Inject constructor( } } - val request = Builder().addCapability(NET_CAPABILITY_INTERNET).build() + val request = Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build() connectivityManager.registerNetworkCallback(request, callback) /** @@ -82,7 +84,7 @@ class ConnectivityManagerNetworkMonitor @Inject constructor( VERSION.SDK_INT >= VERSION_CODES.M -> activeNetwork ?.let(::getNetworkCapabilities) - ?.hasCapability(NET_CAPABILITY_INTERNET) + ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) else -> activeNetworkInfo?.isConnected } ?: false From 41f3359168e4d91e48b6388b24cb628299628a0e Mon Sep 17 00:00:00 2001 From: Alejandra Stamato Date: Mon, 5 Jun 2023 13:52:44 +0100 Subject: [PATCH 16/33] Added scroll test for topic list --- .../interests/ScrollTopicListBenchmark.kt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt diff --git a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt new file mode 100644 index 000000000..b43d3a84b --- /dev/null +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/ScrollTopicListBenchmark.kt @@ -0,0 +1,62 @@ +/* + * 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.interests + +import androidx.benchmark.macro.CompilationMode +import androidx.benchmark.macro.FrameTimingMetric +import androidx.benchmark.macro.StartupMode +import androidx.benchmark.macro.junit4.MacrobenchmarkRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.uiautomator.By +import com.google.samples.apps.nowinandroid.PACKAGE_NAME +import com.google.samples.apps.nowinandroid.allowNotifications +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ScrollTopicListBenchmark { + @get:Rule + val benchmarkRule = MacrobenchmarkRule() + + @Test + fun benchmarkStateChangeCompilationBaselineProfile() = + benchmarkStateChange(CompilationMode.Partial()) + + private fun benchmarkStateChange(compilationMode: CompilationMode) = + benchmarkRule.measureRepeated( + packageName = PACKAGE_NAME, + metrics = listOf(FrameTimingMetric()), + compilationMode = compilationMode, + iterations = 10, + startupMode = StartupMode.WARM, + setupBlock = { + // Start the app + pressHome() + startActivityAndWait() + allowNotifications() + // Navigate to interests screen + device.findObject(By.text("Interests")).click() + device.waitForIdle() + }, + ) { + interestsWaitForTopics() + repeat(3) { + interestsScrollTopicsDownUp() + } + } +} From f71375f510328cfe5ac9a1117d2d5d0aa3507516 Mon Sep 17 00:00:00 2001 From: Amaury Medeiros Date: Wed, 7 Jun 2023 12:00:47 +0100 Subject: [PATCH 17/33] Fix ForYouScreen Compose Previews Permissions should only be called in an Activity context, which is a layoutlib limitation. We need to avoid launching the permission request when in LocalInspectionMode, otherwise we'll have render errors on the ForYouScreen previews. --- .../samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index ebc0a6fe9..012b98608 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -68,6 +68,7 @@ import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -406,6 +407,8 @@ fun TopicIcon( @Composable @OptIn(ExperimentalPermissionsApi::class) private fun NotificationPermissionEffect() { + // Permissions should be called from in an Activity Context, which is not present in previews + if (LocalInspectionMode.current) return if (VERSION.SDK_INT < VERSION_CODES.TIRAMISU) return val notificationsPermissionState = rememberPermissionState( android.Manifest.permission.POST_NOTIFICATIONS, From 66f6205ec554579452797fe44aa7de321ead9a7f Mon Sep 17 00:00:00 2001 From: Amaury Medeiros Date: Wed, 7 Jun 2023 14:33:15 +0100 Subject: [PATCH 18/33] Apply suggested changes to inline comment --- .../samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 012b98608..f71be33e9 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -407,7 +407,8 @@ fun TopicIcon( @Composable @OptIn(ExperimentalPermissionsApi::class) private fun NotificationPermissionEffect() { - // Permissions should be called from in an Activity Context, which is not present in previews + // Permissions should be called from in an Activity Context, which is not present + // in previews if (LocalInspectionMode.current) return if (VERSION.SDK_INT < VERSION_CODES.TIRAMISU) return val notificationsPermissionState = rememberPermissionState( From 7dead405105f42b82fdefddc2dce5a94fe15a126 Mon Sep 17 00:00:00 2001 From: Amaury Medeiros Date: Wed, 7 Jun 2023 14:37:05 +0100 Subject: [PATCH 19/33] Fix inline comment as suggested in PR --- .../samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index f71be33e9..70cc7e541 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -407,7 +407,7 @@ fun TopicIcon( @Composable @OptIn(ExperimentalPermissionsApi::class) private fun NotificationPermissionEffect() { - // Permissions should be called from in an Activity Context, which is not present + // Permission requests should only be made from an Activity Context, which is not present // in previews if (LocalInspectionMode.current) return if (VERSION.SDK_INT < VERSION_CODES.TIRAMISU) return From f5a5811506b3c667fc3055d07fa69ba313f3cfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Mlynari=C4=8D?= Date: Wed, 14 Jun 2023 10:23:22 +0200 Subject: [PATCH 20/33] Add contentType to news feed Before ScrollForYouFeedBenchmark_scrollFeedCompilationFull frameDurationCpuMs P50 4.9, P90 6.9, P95 7.6, P99 9.5 frameOverrunMs P50 -10.3, P90 -6.8, P95 -2.8, P99 -2.1 Traces: Iteration 0 1 2 3 4 5 6 7 8 9 After ScrollForYouFeedBenchmark_scrollFeedCompilationFull frameDurationCpuMs P50 4.6, P90 6.3, P95 7.2, P99 9.2 frameOverrunMs P50 -10.6, P90 -8.7, P95 -7.8, P99 -4.7 Traces: Iteration 0 1 2 3 4 5 6 7 8 9 Change-Id: I5589776f9627c27154873529c9ca9dd055a8a8ef --- .../google/samples/apps/nowinandroid/core/ui/NewsFeed.kt | 6 +++++- .../apps/nowinandroid/feature/foryou/ForYouScreen.kt | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt index 58ec216fd..22783abc1 100644 --- a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt +++ b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt @@ -57,7 +57,11 @@ fun LazyGridScope.newsFeed( when (feedState) { NewsFeedUiState.Loading -> Unit is NewsFeedUiState.Success -> { - items(feedState.feed, key = { it.id }) { userNewsResource -> + items( + feedState.feed, + key = { it.id }, + contentType = { "newsFeedItem" }, + ) { userNewsResource -> val resourceUrl by remember { mutableStateOf(Uri.parse(userNewsResource.url)) } diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 70cc7e541..0c6aa40e1 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -182,7 +182,7 @@ internal fun ForYouScreen( onTopicClick = onTopicClick, ) - item(span = { GridItemSpan(maxLineSpan) }) { + item(span = { GridItemSpan(maxLineSpan) }, contentType = { "bottomSpacing" }) { Column { Spacer(modifier = Modifier.height(8.dp)) // Add space for the content to clear the "offline" snackbar. @@ -240,7 +240,7 @@ private fun LazyGridScope.onboarding( -> Unit is OnboardingUiState.Shown -> { - item(span = { GridItemSpan(maxLineSpan) }) { + item(span = { GridItemSpan(maxLineSpan) }, contentType = "onboarding") { Column(modifier = interestsItemModifier) { Text( text = stringResource(R.string.onboarding_guidance_title), From 5637f3ece573662b8d7aab895826e81918182b0b Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 14 Jun 2023 22:41:33 +0100 Subject: [PATCH 21/33] Update docs/ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 8409fbf4a..46487d669 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -173,7 +173,7 @@ Using the above modularization strategy, the Now in Android app has the followin UI components, composables and resources, used by different features. - NewsResourceCardExpanded + NewsFeed NewsResourceCardExpanded From ed6bc1b37c6dc87c2609db5ce2a39e760b207788 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 14 Jun 2023 22:41:42 +0100 Subject: [PATCH 22/33] Update docs/ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 46487d669..716b8c404 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -171,7 +171,7 @@ Using the above modularization strategy, the Now in Android app has the followin core:ui - UI components, composables and resources, used by different features. + Composite UI components and resources used by feature modules, such as the news feed. Unlike the `designsystem` module, it is dependent on the data layer since it renders models, like news resources. NewsFeed NewsResourceCardExpanded From 20d5442046a98572dbd238668e6067571009e60f Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 14 Jun 2023 22:41:51 +0100 Subject: [PATCH 23/33] Update docs/ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 716b8c404..94a3e90a7 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -165,7 +165,7 @@ Using the above modularization strategy, the Now in Android app has the followin Design system, tokens and icons. NiaTheme
- NiaIcons + NiaIcons NiaButton NiaTheme From 2d9b83dd033d5f6b392a43c0bcea229b29fd587f Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 14 Jun 2023 22:41:56 +0100 Subject: [PATCH 24/33] Update docs/ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 94a3e90a7..c272818ae 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -162,7 +162,7 @@ Using the above modularization strategy, the Now in Android app has the followin core:designsystem - Design system, tokens and icons. + Design system which includes Core UI components (many of which are customized Material 3 components), app theme and icons. The design system can be viewed by running the `app-nia-catalog` run configuration`. NiaTheme
NiaIcons NiaButton NiaTheme From dc0339036888b165b0cbfc77c859cde2c93a6325 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 14 Jun 2023 22:42:29 +0100 Subject: [PATCH 25/33] Update docs/ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index c272818ae..966ef4615 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -162,7 +162,7 @@ Using the above modularization strategy, the Now in Android app has the followin core:designsystem - Design system which includes Core UI components (many of which are customized Material 3 components), app theme and icons. The design system can be viewed by running the `app-nia-catalog` run configuration`. + Design system which includes Core UI components (many of which are customized Material 3 components), app theme and icons. The design system can be viewed by running the `app-nia-catalog` run configuration. NiaTheme
NiaIcons NiaButton NiaTheme From 8b526065f09e475460f2cb69b8ca7eeebe97764b Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 14 Jun 2023 22:42:55 +0100 Subject: [PATCH 26/33] Update docs/ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 966ef4615..da916912c 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -164,7 +164,7 @@ Using the above modularization strategy, the Now in Android app has the followin Design system which includes Core UI components (many of which are customized Material 3 components), app theme and icons. The design system can be viewed by running the `app-nia-catalog` run configuration. - NiaTheme
+ NiaIcons NiaButton NiaTheme From 7f45283dfe903dc6677280fd7ee63bb19038f198 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 14 Jun 2023 22:44:41 +0100 Subject: [PATCH 27/33] Update ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index da916912c..3762cf04c 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -162,7 +162,7 @@ Using the above modularization strategy, the Now in Android app has the followin core:designsystem - Design system which includes Core UI components (many of which are customized Material 3 components), app theme and icons. The design system can be viewed by running the `app-nia-catalog` run configuration. + Design system which includes Core UI components (many of which are customized Material 3 components), app theme and icons. The design system can be viewed by running the app-nia-catalog run configuration. NiaIcons NiaButton NiaTheme From 3cadf84adba370379f917557e47bb2f10bc9578d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Mlynari=C4=8D?= Date: Thu, 15 Jun 2023 09:59:19 +0200 Subject: [PATCH 28/33] Don't use lambda contentType for a single item Change-Id: I0588c031428d523707463c5f0f0b6c586ea5e2c3 --- .../samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 0c6aa40e1..eaa0c58fa 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -182,7 +182,7 @@ internal fun ForYouScreen( onTopicClick = onTopicClick, ) - item(span = { GridItemSpan(maxLineSpan) }, contentType = { "bottomSpacing" }) { + item(span = { GridItemSpan(maxLineSpan) }, contentType = "bottomSpacing") { Column { Spacer(modifier = Modifier.height(8.dp)) // Add space for the content to clear the "offline" snackbar. From 43c087d7aa87fb48127720bf8fd874325583ad09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Mlynari=C4=8D?= Date: Thu, 15 Jun 2023 09:59:25 +0200 Subject: [PATCH 29/33] Add named arguments Change-Id: Ic91ae4fc04bf8eb92c3e5845c7e984475526ec91 --- .../com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt index 22783abc1..16cd3edf7 100644 --- a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt +++ b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt @@ -58,7 +58,7 @@ fun LazyGridScope.newsFeed( NewsFeedUiState.Loading -> Unit is NewsFeedUiState.Success -> { items( - feedState.feed, + items = feedState.feed, key = { it.id }, contentType = { "newsFeedItem" }, ) { userNewsResource -> From e1c01b257b8c35dfef8bdbcbe85ab5764436c67b Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Thu, 15 Jun 2023 18:25:06 +0100 Subject: [PATCH 30/33] Fix HTML/Markdown typo in `ModularizationLearningJourney.md` --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 3762cf04c..8cee53672 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -171,7 +171,7 @@ Using the above modularization strategy, the Now in Android app has the followin core:ui - Composite UI components and resources used by feature modules, such as the news feed. Unlike the `designsystem` module, it is dependent on the data layer since it renders models, like news resources. + Composite UI components and resources used by feature modules, such as the news feed. Unlike the designsystem module, it is dependent on the data layer since it renders models, like news resources. NewsFeed NewsResourceCardExpanded From a6f25688121a932d348c70ebc344b9dc99887d7b Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Thu, 15 Jun 2023 20:48:09 +0200 Subject: [PATCH 31/33] Extract `Project.libs` extension for `build-logic` plugins --- ...roidApplicationFirebaseConventionPlugin.kt | 4 +-- .../kotlin/AndroidFeatureConventionPlugin.kt | 6 +---- .../kotlin/AndroidHiltConventionPlugin.kt | 4 +-- .../kotlin/AndroidLibraryConventionPlugin.kt | 4 +-- .../kotlin/AndroidRoomConventionPlugin.kt | 4 +-- .../apps/nowinandroid/AndroidCompose.kt | 4 --- .../samples/apps/nowinandroid/Jacoco.kt | 4 --- .../apps/nowinandroid/KotlinAndroid.kt | 4 --- .../apps/nowinandroid/ProjectExtensions.kt | 25 +++++++++++++++++++ 9 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/ProjectExtensions.kt diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationFirebaseConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationFirebaseConventionPlugin.kt index 7b3a0059f..422592b8a 100644 --- a/build-logic/convention/src/main/kotlin/AndroidApplicationFirebaseConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationFirebaseConventionPlugin.kt @@ -16,12 +16,11 @@ import com.android.build.api.dsl.ApplicationExtension import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension +import com.google.samples.apps.nowinandroid.libs import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.getByType class AndroidApplicationFirebaseConventionPlugin : Plugin { override fun apply(target: Project) { @@ -32,7 +31,6 @@ class AndroidApplicationFirebaseConventionPlugin : Plugin { apply("com.google.firebase.crashlytics") } - val libs = extensions.getByType().named("libs") dependencies { val bom = libs.findLibrary("firebase-bom").get() add("implementation", platform(bom)) diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt index 1b567ae2d..cc42d60fd 100644 --- a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt @@ -14,15 +14,13 @@ * limitations under the License. */ -import com.android.build.api.dsl.ApplicationExtension import com.android.build.gradle.LibraryExtension import com.google.samples.apps.nowinandroid.configureGradleManagedDevices +import com.google.samples.apps.nowinandroid.libs import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.kotlin class AndroidFeatureConventionPlugin : Plugin { @@ -40,8 +38,6 @@ class AndroidFeatureConventionPlugin : Plugin { configureGradleManagedDevices(this) } - val libs = extensions.getByType().named("libs") - dependencies { add("implementation", project(":core:model")) add("implementation", project(":core:ui")) diff --git a/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt index 29cb748c2..b98673619 100644 --- a/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt @@ -14,11 +14,10 @@ * limitations under the License. */ +import com.google.samples.apps.nowinandroid.libs import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.getByType class AndroidHiltConventionPlugin : Plugin { override fun apply(target: Project) { @@ -30,7 +29,6 @@ class AndroidHiltConventionPlugin : Plugin { apply("org.jetbrains.kotlin.kapt") } - val libs = extensions.getByType().named("libs") dependencies { "implementation"(libs.findLibrary("hilt.android").get()) "kapt"(libs.findLibrary("hilt.compiler").get()) diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt index 275a26620..287b09cf5 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -21,12 +21,11 @@ import com.google.samples.apps.nowinandroid.configureGradleManagedDevices import com.google.samples.apps.nowinandroid.configureKotlinAndroid import com.google.samples.apps.nowinandroid.configurePrintApksTask import com.google.samples.apps.nowinandroid.disableUnnecessaryAndroidTests +import com.google.samples.apps.nowinandroid.libs import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.kotlin class AndroidLibraryConventionPlugin : Plugin { @@ -47,7 +46,6 @@ class AndroidLibraryConventionPlugin : Plugin { configurePrintApksTask(this) disableUnnecessaryAndroidTests(target) } - val libs = extensions.getByType().named("libs") configurations.configureEach { resolutionStrategy { force(libs.findLibrary("junit4").get()) diff --git a/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt index 778798b96..b67fb1b26 100644 --- a/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt @@ -15,15 +15,14 @@ */ import com.google.devtools.ksp.gradle.KspExtension +import com.google.samples.apps.nowinandroid.libs import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.getByType import org.gradle.process.CommandLineArgumentProvider import java.io.File @@ -40,7 +39,6 @@ class AndroidRoomConventionPlugin : Plugin { arg(RoomSchemaArgProvider(File(projectDir, "schemas"))) } - val libs = extensions.getByType().named("libs") dependencies { add("implementation", libs.findLibrary("room.runtime").get()) add("implementation", libs.findLibrary("room.ktx").get()) diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt index 5997f7d4e..9950352b1 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/AndroidCompose.kt @@ -18,9 +18,7 @@ package com.google.samples.apps.nowinandroid import com.android.build.api.dsl.CommonExtension import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.io.File @@ -31,8 +29,6 @@ import java.io.File internal fun Project.configureAndroidCompose( commonExtension: CommonExtension<*, *, *, *>, ) { - val libs = extensions.getByType().named("libs") - commonExtension.apply { buildFeatures { compose = true 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 d801d7b69..70eef1a2d 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 @@ -18,10 +18,8 @@ package com.google.samples.apps.nowinandroid import com.android.build.api.variant.AndroidComponentsExtension import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.tasks.testing.Test import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.withType import org.gradle.testing.jacoco.plugins.JacocoPluginExtension @@ -44,8 +42,6 @@ private fun String.capitalize() = replaceFirstChar { internal fun Project.configureJacoco( androidComponentsExtension: AndroidComponentsExtension<*, *, *>, ) { - val libs = extensions.getByType().named("libs") - configure { toolVersion = libs.findVersion("jacoco").get().toString() } diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt index 976183aa4..5cdf2f593 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/KotlinAndroid.kt @@ -19,11 +19,9 @@ package com.google.samples.apps.nowinandroid import com.android.build.api.dsl.CommonExtension import org.gradle.api.JavaVersion import org.gradle.api.Project -import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.plugins.JavaPluginExtension import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.tasks.KotlinCompile @@ -52,8 +50,6 @@ internal fun Project.configureKotlinAndroid( configureKotlin() - val libs = extensions.getByType().named("libs") - dependencies { add("coreLibraryDesugaring", libs.findLibrary("android.desugarJdkLibs").get()) } diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/ProjectExtensions.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/ProjectExtensions.kt new file mode 100644 index 000000000..e45d7f2e1 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/ProjectExtensions.kt @@ -0,0 +1,25 @@ +/* + * 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 + +import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalog +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByType + +val Project.libs + get(): VersionCatalog = extensions.getByType().named("libs") From 5bd3b4394ca1edebad6df064bc2f75499bf31dca Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sat, 17 Jun 2023 16:55:12 +0700 Subject: [PATCH 32/33] remove M1 Mac Rosetta caution in README.md --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 9aca22cbd..1b1fb795e 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,6 @@ understanding of which libraries and tools are being used, the reasoning behind UI, testing, architecture and more, and how all of these different pieces of the project fit together to create a complete app. -NOTE: Building the app using an M1 Mac will require the use of -[Rosetta](https://support.apple.com/en-gb/HT211861). See -[the following bug](https://github.com/protocolbuffers/protobuf/issues/9397#issuecomment-1086138036) -for more details. - # Architecture The **Now in Android** app follows the From 3c9ff51454e6135668d190f3595e4fdccb9e3e35 Mon Sep 17 00:00:00 2001 From: tsumuchan Date: Tue, 20 Jun 2023 07:01:58 +0900 Subject: [PATCH 33/33] fix: close tag --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 8cee53672..a9766c68d 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -171,7 +171,7 @@ Using the above modularization strategy, the Now in Android app has the followin core:ui - Composite UI components and resources used by feature modules, such as the news feed. Unlike the designsystem module, it is dependent on the data layer since it renders models, like news resources. + Composite UI components and resources used by feature modules, such as the news feed. Unlike the designsystem module, it is dependent on the data layer since it renders models, like news resources. NewsFeed NewsResourceCardExpanded