Merge branch 'main' into dt/nav-safe-args

dt/nav-safe-args-android-dependency
Don Turner 11 months ago committed by GitHub
commit 2d45b84031
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -128,6 +128,13 @@ jobs:
name: local-test-results
path: '**/build/test-results/test*UnitTest/**.xml'
- name: Upload screenshot results (PNG)
if: always()
uses: actions/upload-artifact@v4
with:
name: screenshot-test-results
path: '**/build/outputs/roborazzi/*_compare.png'
- name: Check lint
run: ./gradlew :app:lintProdRelease :app-nia-catalog:lintRelease :lint:lint

@ -118,6 +118,7 @@ dependencies {
testImplementation(projects.core.dataTest)
testImplementation(projects.core.testing)
testImplementation(projects.sync.syncTest)
testImplementation(libs.androidx.compose.ui.test)
testImplementation(libs.hilt.android.testing)
testImplementation(libs.work.testing)

@ -103,11 +103,11 @@ androidx.lifecycle:lifecycle-viewmodel:2.8.0-alpha04
androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-alpha04
androidx.navigation:navigation-common-ktx:2.7.4
androidx.navigation:navigation-common:2.7.4
androidx.navigation:navigation-compose:2.7.4
androidx.navigation:navigation-runtime-ktx:2.7.4
androidx.navigation:navigation-runtime:2.7.4
androidx.navigation:navigation-common-ktx:2.7.7
androidx.navigation:navigation-common:2.7.7
androidx.navigation:navigation-compose:2.7.7
androidx.navigation:navigation-runtime-ktx:2.7.7
androidx.navigation:navigation-runtime:2.7.7
androidx.print:print:1.0.0
androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05
androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05

@ -16,6 +16,7 @@
package com.google.samples.apps.nowinandroid.ui
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
@ -200,15 +201,7 @@ internal fun NiaApp(
)
}
NiaNavHost(
appState = appState,
onShowSnackbar = { message, action ->
snackbarHostState.showSnackbar(
message = message,
actionLabel = action,
duration = Short,
) == ActionPerformed
},
Box(
modifier = if (shouldShowTopAppBar) {
Modifier.consumeWindowInsets(
WindowInsets.safeDrawing.only(WindowInsetsSides.Top),
@ -216,7 +209,18 @@ internal fun NiaApp(
} else {
Modifier
},
)
) {
NiaNavHost(
appState = appState,
onShowSnackbar = { message, action ->
snackbarHostState.showSnackbar(
message = message,
actionLabel = action,
duration = Short,
) == ActionPerformed
},
)
}
}
// TODO: We may want to add padding or spacer when the snackbar is shown so that

@ -16,7 +16,6 @@
package com.google.samples.apps.nowinandroid.ui
import android.util.Log
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.CompositionLocalProvider
@ -28,10 +27,6 @@ import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.test.platform.app.InstrumentationRegistry
import androidx.work.Configuration
import androidx.work.testing.SynchronousExecutor
import androidx.work.testing.WorkManagerTestInitHelper
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.UserDataRepository
@ -109,17 +104,6 @@ class NiaAppScreenSizesScreenshotTests {
@Before
fun setup() {
val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setExecutor(SynchronousExecutor())
.build()
// Initialize WorkManager for instrumentation tests.
WorkManagerTestInitHelper.initializeTestWorkManager(
InstrumentationRegistry.getInstrumentation().context,
config,
)
hiltRule.inject()
// Configure user data

@ -16,13 +16,14 @@
package com.google.samples.apps.nowinandroid.ui
import android.util.Log
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.material3.SnackbarDuration.Indefinite
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.test.DeviceConfigurationOverride
import androidx.compose.ui.test.ForcedSize
import androidx.compose.ui.test.junit4.createAndroidComposeRule
@ -30,10 +31,6 @@ import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.test.platform.app.InstrumentationRegistry
import androidx.work.Configuration
import androidx.work.testing.SynchronousExecutor
import androidx.work.testing.WorkManagerTestInitHelper
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
@ -60,6 +57,7 @@ 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
/**
@ -112,17 +110,6 @@ class SnackbarScreenshotTests {
@Before
fun setup() {
val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setExecutor(SynchronousExecutor())
.build()
// Initialize WorkManager for instrumentation tests.
WorkManagerTestInitHelper.initializeTestWorkManager(
InstrumentationRegistry.getInstrumentation().context,
config,
)
hiltRule.inject()
// Configure user data
@ -135,6 +122,12 @@ class SnackbarScreenshotTests {
}
}
@Before
fun setTimeZone() {
// Make time zone deterministic in tests
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
}
@Test
fun phone_noSnackbar() {
val snackbarHostState = SnackbarHostState()
@ -207,22 +200,27 @@ class SnackbarScreenshotTests {
) {
lateinit var scope: CoroutineScope
composeTestRule.setContent {
scope = rememberCoroutineScope()
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(width, height)),
CompositionLocalProvider(
// Replaces images with placeholders
LocalInspectionMode provides true,
) {
BoxWithConstraints {
val appState = rememberNiaAppState(
windowSizeClass = WindowSizeClass.calculateFromSize(
DpSize(maxWidth, maxHeight),
),
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
NiaTheme {
NiaApp(appState, snackbarHostState, false, {}, {})
scope = rememberCoroutineScope()
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(width, height)),
) {
BoxWithConstraints {
val appState = rememberNiaAppState(
windowSizeClass = WindowSizeClass.calculateFromSize(
DpSize(maxWidth, maxHeight),
),
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
)
NiaTheme {
NiaApp(appState, snackbarHostState, false, {}, {})
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 96 KiB

@ -57,6 +57,7 @@ internal fun Project.configureAndroidCompose(
kotlinOptions {
freeCompilerArgs += buildComposeMetricsParameters()
freeCompilerArgs += stabilityConfiguration()
freeCompilerArgs += strongSkippingConfiguration()
}
}
}
@ -84,6 +85,7 @@ private fun Project.buildComposeMetricsParameters(): List<String> {
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + reportsFolder.absolutePath
)
}
return metricParameters.toList()
}
@ -91,3 +93,8 @@ private fun Project.stabilityConfiguration() = listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=${project.rootDir.absolutePath}/compose_compiler_config.conf",
)
private fun Project.strongSkippingConfiguration() = listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:experimentalStrongSkipping=true",
)

@ -2,5 +2,10 @@
// It allows us to define classes that our not part of our codebase without wrapping them in a stable class.
// For more information, check https://developer.android.com/jetpack/compose/performance/stability/fix#configuration-file
// We always use immutable classes for our data model, to avoid running the Compose compiler
// in the module we declare it to be stable here.
com.google.samples.apps.nowinandroid.core.model.data.*
// Java standard library classes
java.time.ZoneId
java.time.ZoneOffset

@ -20,7 +20,6 @@ androidxHiltNavigationCompose = "1.2.0"
androidxLifecycle = "2.7.0"
androidxMacroBenchmark = "1.2.2"
androidxMetrics = "1.0.0-alpha04"
#androidxNavigation = "2.8.0-SNAPSHOT"
androidxNavigation = "2.8.0-alpha08"
androidxProfileinstaller = "1.3.1"
androidxTestCore = "1.5.0"

@ -18,6 +18,8 @@ package com.google.samples.apps.nowinandroid.core.sync.test
import com.google.samples.apps.nowinandroid.core.data.util.SyncManager
import com.google.samples.apps.nowinandroid.sync.di.SyncModule
import com.google.samples.apps.nowinandroid.sync.status.StubSyncSubscriber
import com.google.samples.apps.nowinandroid.sync.status.SyncSubscriber
import dagger.Binds
import dagger.Module
import dagger.hilt.components.SingletonComponent
@ -33,4 +35,9 @@ internal interface TestSyncModule {
fun bindsSyncStatusMonitor(
syncStatusMonitor: NeverSyncingSyncManager,
): SyncManager
@Binds
fun bindsSyncSubscriber(
syncSubscriber: StubSyncSubscriber,
): SyncSubscriber
}

@ -24,7 +24,7 @@ private const val TAG = "StubSyncSubscriber"
/**
* Stub implementation of [SyncSubscriber]
*/
internal class StubSyncSubscriber @Inject constructor() : SyncSubscriber {
class StubSyncSubscriber @Inject constructor() : SyncSubscriber {
override suspend fun subscribe() {
Log.d(TAG, "Subscribing to sync")
}

Loading…
Cancel
Save