From 471713e50a88c0910418625cf15b2446a56ee000 Mon Sep 17 00:00:00 2001 From: lihenggui Date: Wed, 26 Jun 2024 14:32:31 -0700 Subject: [PATCH 1/9] Migrate for you to the multiplatform module --- feature/foryou/build.gradle.kts | 45 ++++--- .../feature/foryou/ForYouScreenTest.kt | 0 .../foryou/ForYouScreenScreenshotTests.kt | 0 .../feature/foryou/ForYouViewModelTest.kt | 0 .../ForYouScreenLoading_foldable.png | Bin .../screenshots/ForYouScreenLoading_phone.png | Bin .../ForYouScreenLoading_tablet.png | Bin ...rYouScreenPopulatedAndLoading_foldable.png | Bin .../ForYouScreenPopulatedAndLoading_phone.png | Bin ...ouScreenPopulatedAndLoading_phone_dark.png | Bin ...ForYouScreenPopulatedAndLoading_tablet.png | Bin .../ForYouScreenPopulatedFeed_foldable.png | Bin .../ForYouScreenPopulatedFeed_phone.png | Bin .../ForYouScreenPopulatedFeed_tablet.png | Bin .../ForYouScreenTopicSelection_foldable.png | Bin .../ForYouScreenTopicSelection_phone.png | Bin .../ForYouScreenTopicSelection_phone_dark.png | Bin .../ForYouScreenTopicSelection_tablet.png | Bin .../feature_foryou_ic_icon_placeholder.xml | 0 .../composeResources}/values/strings.xml | 0 .../feature/foryou/ForYouScreen.kt | 114 +++++++++--------- .../feature/foryou/ForYouViewModel.kt | 4 +- .../feature/foryou/OnboardingUiState.kt | 0 .../foryou/navigation/ForYouNavigation.kt | 5 +- feature/foryou/src/main/AndroidManifest.xml | 17 --- 25 files changed, 90 insertions(+), 95 deletions(-) rename feature/foryou/src/{androidTest => androidInstrumentedTest}/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt (100%) rename feature/foryou/src/{test => androidUnitTest}/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenScreenshotTests.kt (100%) rename feature/foryou/src/{test => androidUnitTest}/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenLoading_foldable.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenLoading_phone.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenLoading_tablet.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenPopulatedAndLoading_foldable.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenPopulatedAndLoading_phone.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenPopulatedAndLoading_phone_dark.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenPopulatedAndLoading_tablet.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenPopulatedFeed_foldable.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenPopulatedFeed_phone.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenPopulatedFeed_tablet.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenTopicSelection_foldable.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenTopicSelection_phone.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenTopicSelection_phone_dark.png (100%) rename feature/foryou/src/{test => androidUnitTest}/screenshots/ForYouScreenTopicSelection_tablet.png (100%) rename feature/foryou/src/{main/res => commonMain/composeResources}/drawable/feature_foryou_ic_icon_placeholder.xml (100%) rename feature/foryou/src/{main/res => commonMain/composeResources}/values/strings.xml (100%) rename feature/foryou/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt (87%) rename feature/foryou/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt (98%) rename feature/foryou/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/OnboardingUiState.kt (100%) rename feature/foryou/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt (92%) delete mode 100644 feature/foryou/src/main/AndroidManifest.xml diff --git a/feature/foryou/build.gradle.kts b/feature/foryou/build.gradle.kts index fd41d9a13..1ac58a500 100644 --- a/feature/foryou/build.gradle.kts +++ b/feature/foryou/build.gradle.kts @@ -15,8 +15,9 @@ */ plugins { - alias(libs.plugins.nowinandroid.android.feature) - alias(libs.plugins.nowinandroid.android.library.compose) + alias(libs.plugins.nowinandroid.cmp.feature) + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose) alias(libs.plugins.nowinandroid.android.library.jacoco) alias(libs.plugins.roborazzi) } @@ -25,16 +26,32 @@ android { namespace = "com.google.samples.apps.nowinandroid.feature.foryou" } -dependencies { - implementation(libs.accompanist.permissions) - implementation(projects.core.data) - implementation(projects.core.domain) - - testImplementation(libs.hilt.android.testing) - testImplementation(libs.robolectric) - testImplementation(projects.core.testing) - testImplementation(projects.core.screenshotTesting) - testDemoImplementation(libs.roborazzi) - - androidTestImplementation(projects.core.testing) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.core.data) + implementation(projects.core.domain) + implementation(compose.material3) + implementation(compose.foundation) + implementation(compose.ui) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + implementation(libs.coil) + implementation(libs.coil.compose) + } + androidMain.dependencies { + implementation(libs.accompanist.permissions) + } + commonMain.dependencies { + implementation(projects.core.testing) + } + androidUnitTest.dependencies { + implementation(libs.robolectric) + implementation(libs.roborazzi) + implementation(projects.core.screenshotTesting) + } + androidInstrumentedTest.dependencies { + implementation(projects.core.testing) + } + } } diff --git a/feature/foryou/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt b/feature/foryou/src/androidInstrumentedTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt similarity index 100% rename from feature/foryou/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt rename to feature/foryou/src/androidInstrumentedTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt diff --git a/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenScreenshotTests.kt b/feature/foryou/src/androidUnitTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenScreenshotTests.kt similarity index 100% rename from feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenScreenshotTests.kt rename to feature/foryou/src/androidUnitTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenScreenshotTests.kt diff --git a/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt b/feature/foryou/src/androidUnitTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt similarity index 100% rename from feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt rename to feature/foryou/src/androidUnitTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt diff --git a/feature/foryou/src/test/screenshots/ForYouScreenLoading_foldable.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenLoading_foldable.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenLoading_foldable.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenLoading_foldable.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenLoading_phone.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenLoading_phone.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenLoading_phone.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenLoading_phone.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenLoading_tablet.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenLoading_tablet.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenLoading_tablet.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenLoading_tablet.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_foldable.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_foldable.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_foldable.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_foldable.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_phone.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_phone.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_phone.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_phone.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_phone_dark.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_phone_dark.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_phone_dark.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_phone_dark.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_tablet.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_tablet.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenPopulatedAndLoading_tablet.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedAndLoading_tablet.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_foldable.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedFeed_foldable.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_foldable.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedFeed_foldable.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_phone.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedFeed_phone.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_phone.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedFeed_phone.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_tablet.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedFeed_tablet.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenPopulatedFeed_tablet.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenPopulatedFeed_tablet.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_foldable.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_foldable.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_foldable.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_foldable.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_phone.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_phone.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone_dark.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_phone_dark.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_phone_dark.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_phone_dark.png diff --git a/feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_tablet.png b/feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_tablet.png similarity index 100% rename from feature/foryou/src/test/screenshots/ForYouScreenTopicSelection_tablet.png rename to feature/foryou/src/androidUnitTest/screenshots/ForYouScreenTopicSelection_tablet.png diff --git a/feature/foryou/src/main/res/drawable/feature_foryou_ic_icon_placeholder.xml b/feature/foryou/src/commonMain/composeResources/drawable/feature_foryou_ic_icon_placeholder.xml similarity index 100% rename from feature/foryou/src/main/res/drawable/feature_foryou_ic_icon_placeholder.xml rename to feature/foryou/src/commonMain/composeResources/drawable/feature_foryou_ic_icon_placeholder.xml diff --git a/feature/foryou/src/main/res/values/strings.xml b/feature/foryou/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from feature/foryou/src/main/res/values/strings.xml rename to feature/foryou/src/commonMain/composeResources/values/strings.xml diff --git a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt similarity index 87% rename from feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt rename to feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 885020636..0b867dc20 100644 --- a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -16,10 +16,6 @@ package com.google.samples.apps.nowinandroid.feature.foryou -import android.net.Uri -import android.os.Build.VERSION -import android.os.Build.VERSION_CODES -import androidx.activity.compose.ReportDrawnWhen import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -63,29 +59,22 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalContext import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier 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 import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.max import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.tracing.trace -import com.google.accompanist.permissions.ExperimentalPermissionsApi -import com.google.accompanist.permissions.PermissionStatus.Denied -import com.google.accompanist.permissions.rememberPermissionState +import coil3.ImageLoader +import coil3.compose.LocalPlatformContext import com.google.samples.apps.nowinandroid.core.designsystem.component.DynamicAsyncImage import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton @@ -100,16 +89,24 @@ import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource import com.google.samples.apps.nowinandroid.core.ui.DevicePreviews import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent -import com.google.samples.apps.nowinandroid.core.ui.TrackScrollJank import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider +import com.google.samples.apps.nowinandroid.core.ui.collectAsStateWithLifecycle import com.google.samples.apps.nowinandroid.core.ui.launchCustomChromeTab import com.google.samples.apps.nowinandroid.core.ui.newsFeed +import nowinandroid.feature.foryou.generated.resources.Res +import nowinandroid.feature.foryou.generated.resources.feature_foryou_done +import nowinandroid.feature.foryou.generated.resources.feature_foryou_loading +import nowinandroid.feature.foryou.generated.resources.feature_foryou_onboarding_guidance_subtitle +import nowinandroid.feature.foryou.generated.resources.feature_foryou_onboarding_guidance_title +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.PreviewParameter @Composable internal fun ForYouRoute( onTopicClick: (String) -> Unit, modifier: Modifier = Modifier, - viewModel: ForYouViewModel = hiltViewModel(), + viewModel: ForYouViewModel, ) { val onboardingUiState by viewModel.onboardingUiState.collectAsStateWithLifecycle() val feedState by viewModel.feedState.collectAsStateWithLifecycle() @@ -148,8 +145,8 @@ internal fun ForYouScreen( val isOnboardingLoading = onboardingUiState is OnboardingUiState.Loading val isFeedLoading = feedState is NewsFeedUiState.Loading - // This code should be called when the UI is ready for use and relates to Time To Full Display. - ReportDrawnWhen { !isSyncing && !isOnboardingLoading && !isFeedLoading } +// // This code should be called when the UI is ready for use and relates to Time To Full Display. +// ReportDrawnWhen { !isSyncing && !isOnboardingLoading && !isFeedLoading } val itemsAvailable = feedItemsSize(feedState, onboardingUiState) @@ -157,7 +154,7 @@ internal fun ForYouScreen( val scrollbarState = state.scrollbarState( itemsAvailable = itemsAvailable, ) - TrackScrollJank(scrollableState = state, stateName = "forYou:feed") +// TrackScrollJank(scrollableState = state, stateName = "forYou:feed") Box( modifier = modifier @@ -216,7 +213,7 @@ internal fun ForYouScreen( targetOffsetY = { fullHeight -> -fullHeight }, ) + fadeOut(), ) { - val loadingContentDescription = stringResource(id = R.string.feature_foryou_loading) + val loadingContentDescription = stringResource(Res.string.feature_foryou_loading) Box( modifier = Modifier .fillMaxWidth() @@ -243,7 +240,7 @@ internal fun ForYouScreen( ) } TrackScreenViewEvent(screenName = "ForYou") - NotificationPermissionEffect() +// NotificationPermissionEffect() DeepLinkEffect( deepLinkedUserNewsResource, onDeepLinkOpened, @@ -271,7 +268,7 @@ private fun LazyStaggeredGridScope.onboarding( item(span = StaggeredGridItemSpan.FullLine, contentType = "onboarding") { Column(modifier = interestsItemModifier) { Text( - text = stringResource(R.string.feature_foryou_onboarding_guidance_title), + text = stringResource(Res.string.feature_foryou_onboarding_guidance_title), textAlign = TextAlign.Center, modifier = Modifier .fillMaxWidth() @@ -279,7 +276,7 @@ private fun LazyStaggeredGridScope.onboarding( style = MaterialTheme.typography.titleMedium, ) Text( - text = stringResource(R.string.feature_foryou_onboarding_guidance_subtitle), + text = stringResource(Res.string.feature_foryou_onboarding_guidance_subtitle), modifier = Modifier .fillMaxWidth() .padding(top = 8.dp, start = 24.dp, end = 24.dp), @@ -305,7 +302,7 @@ private fun LazyStaggeredGridScope.onboarding( .fillMaxWidth(), ) { Text( - text = stringResource(R.string.feature_foryou_done), + text = stringResource(Res.string.feature_foryou_done), ) } } @@ -320,11 +317,11 @@ private fun TopicSelection( onboardingUiState: OnboardingUiState.Shown, onTopicCheckedChanged: (String, Boolean) -> Unit, modifier: Modifier = Modifier, -) = trace("TopicSelection") { +) { val lazyGridState = rememberLazyGridState() val topicSelectionTestTag = "forYou:topicSelection" - TrackScrollJank(scrollableState = lazyGridState, stateName = topicSelectionTestTag) +// TrackScrollJank(scrollableState = lazyGridState, stateName = topicSelectionTestTag) Box( modifier = modifier @@ -381,7 +378,7 @@ private fun SingleTopicButton( imageUrl: String, isSelected: Boolean, onClick: (String, Boolean) -> Unit, -) = trace("SingleTopicButton") { +) { Surface( modifier = Modifier .width(312.dp) @@ -434,52 +431,53 @@ fun TopicIcon( modifier: Modifier = Modifier, ) { DynamicAsyncImage( - placeholder = painterResource(R.drawable.feature_foryou_ic_icon_placeholder), +// placeholder = painterResource(R.drawable.feature_foryou_ic_icon_placeholder), imageUrl = imageUrl, // decorative contentDescription = null, modifier = modifier .padding(10.dp) .size(32.dp), + imageLoader = ImageLoader(LocalPlatformContext.current), ) } -@Composable -@OptIn(ExperimentalPermissionsApi::class) -private fun NotificationPermissionEffect() { - // 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 - val notificationsPermissionState = rememberPermissionState( - android.Manifest.permission.POST_NOTIFICATIONS, - ) - LaunchedEffect(notificationsPermissionState) { - val status = notificationsPermissionState.status - if (status is Denied && !status.shouldShowRationale) { - notificationsPermissionState.launchPermissionRequest() - } - } -} +//@Composable +//@OptIn(ExperimentalPermissionsApi::class) +//private fun NotificationPermissionEffect() { +// // 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 +// val notificationsPermissionState = rememberPermissionState( +// android.Manifest.permission.POST_NOTIFICATIONS, +// ) +// LaunchedEffect(notificationsPermissionState) { +// val status = notificationsPermissionState.status +// if (status is Denied && !status.shouldShowRationale) { +// notificationsPermissionState.launchPermissionRequest() +// } +// } +//} @Composable private fun DeepLinkEffect( userNewsResource: UserNewsResource?, onDeepLinkOpened: (String) -> Unit, ) { - val context = LocalContext.current - val backgroundColor = MaterialTheme.colorScheme.background.toArgb() - - LaunchedEffect(userNewsResource) { - if (userNewsResource == null) return@LaunchedEffect - if (!userNewsResource.hasBeenViewed) onDeepLinkOpened(userNewsResource.id) - - launchCustomChromeTab( - context = context, - uri = Uri.parse(userNewsResource.url), - toolbarColor = backgroundColor, - ) - } +// val context = LocalContext.current +// val backgroundColor = MaterialTheme.colorScheme.background.toArgb() +// +// LaunchedEffect(userNewsResource) { +// if (userNewsResource == null) return@LaunchedEffect +// if (!userNewsResource.hasBeenViewed) onDeepLinkOpened(userNewsResource.id) +// +// launchCustomChromeTab( +// context = context, +// uri = Uri.parse(userNewsResource.url), +// toolbarColor = backgroundColor, +// ) +// } } private fun feedItemsSize( diff --git a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt similarity index 98% rename from feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt rename to feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt index 85035a77a..281e4a4b8 100644 --- a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt +++ b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt @@ -29,7 +29,6 @@ import com.google.samples.apps.nowinandroid.core.data.util.SyncManager import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.feature.foryou.navigation.LINKED_NEWS_RESOURCE_ID -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -39,9 +38,8 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject -@HiltViewModel class ForYouViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, syncManager: SyncManager, diff --git a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/OnboardingUiState.kt b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/OnboardingUiState.kt similarity index 100% rename from feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/OnboardingUiState.kt rename to feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/OnboardingUiState.kt diff --git a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt similarity index 92% rename from feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt rename to feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt index 8e94a491a..b39b9d93f 100644 --- a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt +++ b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt @@ -22,7 +22,6 @@ import androidx.navigation.NavOptions import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument -import androidx.navigation.navDeepLink import com.google.samples.apps.nowinandroid.feature.foryou.ForYouRoute const val LINKED_NEWS_RESOURCE_ID = "linkedNewsResourceId" @@ -36,12 +35,12 @@ fun NavGraphBuilder.forYouScreen(onTopicClick: (String) -> Unit) { composable( route = FOR_YOU_ROUTE, deepLinks = listOf( - navDeepLink { uriPattern = DEEP_LINK_URI_PATTERN }, +// navDeepLink { uriPattern = DEEP_LINK_URI_PATTERN }, ), arguments = listOf( navArgument(LINKED_NEWS_RESOURCE_ID) { type = NavType.StringType }, ), ) { - ForYouRoute(onTopicClick) +// ForYouRoute(onTopicClick) } } diff --git a/feature/foryou/src/main/AndroidManifest.xml b/feature/foryou/src/main/AndroidManifest.xml deleted file mode 100644 index 51d0cfc2e..000000000 --- a/feature/foryou/src/main/AndroidManifest.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - \ No newline at end of file From 36c537466c09ea6816a953d2755e8c0e7922877f Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 11:05:03 -0700 Subject: [PATCH 2/9] Use correct implementation in providing multiplatform components --- ...roid.kt => AndroidPlatformDependentDataModule.kt} | 12 +++++++----- .../apps/nowinandroid/core/data/di/DataModule.kt | 2 +- .../core/data/di/PlatformDependentDataModule.kt | 11 ++++++++--- .../core/data/di/UserNewsResourceRepositoryModule.kt | 2 +- ...dule.jvm.kt => JvmPlatformDependentDataModule.kt} | 6 +++--- ...ative.kt => NativePlatformDependentDataModule.kt} | 6 +++--- 6 files changed, 23 insertions(+), 16 deletions(-) rename core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/{PlatformDependentDataModule.android.kt => AndroidPlatformDependentDataModule.kt} (67%) rename core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/{PlatformDependentDataModule.jvm.kt => JvmPlatformDependentDataModule.kt} (88%) rename core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/{PlatformDependentDataModule.native.kt => NativePlatformDependentDataModule.kt} (87%) diff --git a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.android.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt similarity index 67% rename from core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.android.kt rename to core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt index 87f01db64..f1f19d3c7 100644 --- a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.android.kt +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt @@ -16,20 +16,22 @@ package com.google.samples.apps.nowinandroid.core.data.di +import com.google.samples.apps.nowinandroid.core.data.util.ConnectivityManagerNetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor +import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneBroadcastMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -internal actual abstract class PlatformDependentDataModule { +abstract class AndroidPlatformDependentDataModule: PlatformDependentDataModule() { @Provides - internal actual fun bindsNetworkMonitor(): NetworkMonitor { - TODO() + override fun bindsNetworkMonitor(): NetworkMonitor { + return ConnectivityManagerNetworkMonitor() } @Provides - internal actual fun bindsTimeZoneMonitor(): TimeZoneMonitor { - TODO() + override fun bindsTimeZoneMonitor(): TimeZoneMonitor { + return TimeZoneBroadcastMonitor() } } diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt index bb29ee7a0..bad20ac1d 100644 --- a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt @@ -43,7 +43,7 @@ abstract class DataModule { ): NewsRepository = newsRepository @Provides - fun userDataRepository( + fun bindsUserDataRepository( userDataRepository: OfflineFirstUserDataRepository, ): UserDataRepository = userDataRepository diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt index d4c6409b7..9bdf3da6e 100644 --- a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt @@ -18,12 +18,17 @@ package com.google.samples.apps.nowinandroid.core.data.di 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.di.ApplicationScope import me.tatarka.inject.annotations.Provides -internal expect abstract class PlatformDependentDataModule { +@ApplicationScope +abstract class PlatformDependentDataModule { + + @ApplicationScope @Provides - internal fun bindsNetworkMonitor(): NetworkMonitor + abstract fun bindsNetworkMonitor(): NetworkMonitor + @ApplicationScope @Provides - internal fun bindsTimeZoneMonitor(): TimeZoneMonitor + abstract fun bindsTimeZoneMonitor(): TimeZoneMonitor } diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt index 59293fa9d..979fd60ec 100644 --- a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt @@ -22,7 +22,7 @@ import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -internal abstract class UserNewsResourceRepositoryModule { +abstract class UserNewsResourceRepositoryModule { @Provides fun bindsUserNewsResourceRepository( userDataRepository: CompositeUserNewsResourceRepository, diff --git a/core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.jvm.kt b/core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/JvmPlatformDependentDataModule.kt similarity index 88% rename from core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.jvm.kt rename to core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/JvmPlatformDependentDataModule.kt index df3acd1a3..e7bce4e73 100644 --- a/core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.jvm.kt +++ b/core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/JvmPlatformDependentDataModule.kt @@ -29,9 +29,9 @@ import me.tatarka.inject.annotations.Provides * Leave empty for now */ @Component -internal actual abstract class PlatformDependentDataModule { +abstract class JvmPlatformDependentDataModule : PlatformDependentDataModule() { @Provides - internal actual fun bindsNetworkMonitor(): NetworkMonitor { + override fun bindsNetworkMonitor(): NetworkMonitor { return object : NetworkMonitor { override val isOnline: Flow get() = flowOf(true) @@ -39,7 +39,7 @@ internal actual abstract class PlatformDependentDataModule { } @Provides - internal actual fun bindsTimeZoneMonitor(): TimeZoneMonitor { + override fun bindsTimeZoneMonitor(): TimeZoneMonitor { return object : TimeZoneMonitor { override val currentTimeZone: Flow get() = flowOf(TimeZone.UTC) diff --git a/core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.native.kt b/core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/NativePlatformDependentDataModule.kt similarity index 87% rename from core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.native.kt rename to core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/NativePlatformDependentDataModule.kt index 1600ad86b..95cc466b3 100644 --- a/core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.native.kt +++ b/core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/NativePlatformDependentDataModule.kt @@ -29,9 +29,9 @@ import me.tatarka.inject.annotations.Provides * Leave empty for now */ @Component -internal actual abstract class PlatformDependentDataModule { +abstract class NativePlatformDependentDataModule : PlatformDependentDataModule() { @Provides - internal actual fun bindsNetworkMonitor(): NetworkMonitor { + override fun bindsNetworkMonitor(): NetworkMonitor { return object : NetworkMonitor { override val isOnline: Flow get() = flowOf(true) @@ -39,7 +39,7 @@ internal actual abstract class PlatformDependentDataModule { } @Provides - internal actual fun bindsTimeZoneMonitor(): TimeZoneMonitor { + override fun bindsTimeZoneMonitor(): TimeZoneMonitor { return object : TimeZoneMonitor { override val currentTimeZone: Flow get() = flowOf(TimeZone.UTC) From 678e98ee3b66323b9580d536e6f1bb12a076800f Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 11:17:07 -0700 Subject: [PATCH 3/9] Use correct implementation for providing dispatchers --- ...nent.kt => AndroidDispatchersComponent.kt} | 8 ++-- .../core/di/DispatcherQualifier.kt | 46 +++++++++++++++++++ .../core/di/DispatchersComponent.kt | 9 ++-- .../core/di/JvmDispatchersComponent.kt} | 9 ++-- .../core/di/NativeDispatchersComponent.kt} | 9 ++-- .../di/AndroidPlatformDependentDataModule.kt | 7 ++- 6 files changed, 69 insertions(+), 19 deletions(-) rename core/common/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/di/{DispatchersComponent.kt => AndroidDispatchersComponent.kt} (72%) create mode 100644 core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt rename core/common/src/{nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt => jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt} (73%) rename core/common/src/{jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt => nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/NativeDispatchersComponent.kt} (70%) diff --git a/core/common/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt b/core/common/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/di/AndroidDispatchersComponent.kt similarity index 72% rename from core/common/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt rename to core/common/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/di/AndroidDispatchersComponent.kt index 6ae0c863d..0421b2b55 100644 --- a/core/common/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt +++ b/core/common/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/di/AndroidDispatchersComponent.kt @@ -16,15 +16,17 @@ package com.google.samples.apps.nowinandroid.core.di +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -actual abstract class DispatchersComponent { +abstract class AndroidDispatchersComponent : DispatchersComponent() { @Provides - actual fun providesIODispatcher(): IODispatcher = Dispatchers.IO + override fun providesIODispatcher(): @IoDispatcher CoroutineDispatcher = Dispatchers.IO @Provides - actual fun providesDefaultDispatcher(): DefaultDispatcher = Dispatchers.Default + override fun providesDefaultDispatcher(): @DefaultDispatcher CoroutineDispatcher = + Dispatchers.Default } diff --git a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt new file mode 100644 index 000000000..3193db2c9 --- /dev/null +++ b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt @@ -0,0 +1,46 @@ +/* + * 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.core.di + +import me.tatarka.inject.annotations.Qualifier + +@Qualifier +@Target( + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.FUNCTION, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.TYPE +) +annotation class IoDispatcher + +@Qualifier +@Target( + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.FUNCTION, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.TYPE +) +annotation class MainDispatcher + +@Qualifier +@Target( + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.FUNCTION, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.TYPE +) +annotation class DefaultDispatcher diff --git a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt index 3de817939..95cc4e8be 100644 --- a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt +++ b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt @@ -19,13 +19,10 @@ package com.google.samples.apps.nowinandroid.core.di import kotlinx.coroutines.CoroutineDispatcher import me.tatarka.inject.annotations.Provides -typealias DefaultDispatcher = CoroutineDispatcher -typealias IODispatcher = CoroutineDispatcher - -expect abstract class DispatchersComponent { +abstract class DispatchersComponent { @Provides - fun providesIODispatcher(): IODispatcher + abstract fun providesIODispatcher(): @IoDispatcher CoroutineDispatcher @Provides - fun providesDefaultDispatcher(): DefaultDispatcher + abstract fun providesDefaultDispatcher(): @DefaultDispatcher CoroutineDispatcher } diff --git a/core/common/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt b/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt similarity index 73% rename from core/common/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt rename to core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt index e4edc24a7..1afab8067 100644 --- a/core/common/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt +++ b/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt @@ -16,17 +16,16 @@ package com.google.samples.apps.nowinandroid.core.di +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -actual abstract class DispatchersComponent { - - // TODO Provides an actual IODispatcher +abstract class JvmDispatchersComponent: DispatchersComponent() { @Provides - actual fun providesIODispatcher(): IODispatcher = Dispatchers.Default + override fun providesIODispatcher(): @IoDispatcher CoroutineDispatcher = Dispatchers.IO @Provides - actual fun providesDefaultDispatcher(): DefaultDispatcher = Dispatchers.Default + override fun providesDefaultDispatcher(): @DefaultDispatcher CoroutineDispatcher = Dispatchers.Default } diff --git a/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt b/core/common/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/NativeDispatchersComponent.kt similarity index 70% rename from core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt rename to core/common/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/NativeDispatchersComponent.kt index 6ae0c863d..16cfd5a91 100644 --- a/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatchersComponent.kt +++ b/core/common/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/di/NativeDispatchersComponent.kt @@ -16,15 +16,18 @@ package com.google.samples.apps.nowinandroid.core.di +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -actual abstract class DispatchersComponent { +abstract class NativeDispatchersComponent : DispatchersComponent() { @Provides - actual fun providesIODispatcher(): IODispatcher = Dispatchers.IO + override fun providesIODispatcher(): @IoDispatcher CoroutineDispatcher = Dispatchers.IO @Provides - actual fun providesDefaultDispatcher(): DefaultDispatcher = Dispatchers.Default + override fun providesDefaultDispatcher(): @DefaultDispatcher CoroutineDispatcher = + Dispatchers.Default } diff --git a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt index f1f19d3c7..d0262c24f 100644 --- a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt @@ -20,14 +20,17 @@ import com.google.samples.apps.nowinandroid.core.data.util.ConnectivityManagerNe import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneBroadcastMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor +import com.google.samples.apps.nowinandroid.core.di.AndroidApplicationComponent import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -abstract class AndroidPlatformDependentDataModule: PlatformDependentDataModule() { +abstract class AndroidPlatformDependentDataModule( + @Component val applicationComponent: AndroidApplicationComponent, +): PlatformDependentDataModule() { @Provides override fun bindsNetworkMonitor(): NetworkMonitor { - return ConnectivityManagerNetworkMonitor() + return ConnectivityManagerNetworkMonitor(applicationComponent.application) } @Provides From 6982c57b93c2bd179dc966327c6a9d2552d7a9be Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 11:38:36 -0700 Subject: [PATCH 4/9] Provide CoroutineScope and Dispatchers in common --- .../nowinandroid/core/di/CoroutineScopeComponent.kt | 12 ++++++++---- .../apps/nowinandroid/core/di/DispatcherQualifier.kt | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt index abe513134..89b373db0 100644 --- a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt +++ b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.di +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import me.tatarka.inject.annotations.Component @@ -29,9 +30,12 @@ import me.tatarka.inject.annotations.Scope annotation class ApplicationScope @Component -abstract class CoroutineScopeComponent { +abstract class CoroutineScopeComponent( + @Component val dispatchersComponent: DispatchersComponent +) { + @DefaultDispatcher abstract val defaultDispatcher: CoroutineDispatcher + @Provides - fun providesCoroutineScope( - dispatcher: DefaultDispatcher, - ): CoroutineScope = CoroutineScope(SupervisorJob() + dispatcher) + fun providesCoroutineScope(): CoroutineScope = + CoroutineScope(SupervisorJob() + defaultDispatcher) } diff --git a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt index 3193db2c9..d51c0277a 100644 --- a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt +++ b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt @@ -23,7 +23,8 @@ import me.tatarka.inject.annotations.Qualifier AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, - AnnotationTarget.TYPE + AnnotationTarget.TYPE, + AnnotationTarget.PROPERTY ) annotation class IoDispatcher @@ -32,7 +33,8 @@ annotation class IoDispatcher AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, - AnnotationTarget.TYPE + AnnotationTarget.TYPE, + AnnotationTarget.PROPERTY ) annotation class MainDispatcher @@ -41,6 +43,7 @@ annotation class MainDispatcher AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, - AnnotationTarget.TYPE + AnnotationTarget.TYPE, + AnnotationTarget.PROPERTY ) annotation class DefaultDispatcher From eeb86ad23a58cfcb821265803cb536c741dd82bc Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 13:33:38 -0700 Subject: [PATCH 5/9] Use correct provider for CoroutineScope --- .../di/AndroidPlatformDependentDataModule.kt | 22 ++++++++++++++++--- .../data/util/TimeZoneBroadcastMonitor.kt | 4 ++-- .../data/di/PlatformDependentDataModule.kt | 5 +---- .../DefaultSearchContentsRepository.kt | 5 +++-- .../core/database/di/DatabaseModule.kt | 15 ++++++------- .../datastore/NiaPreferencesDataSource.kt | 6 ++--- .../network/demo/DemoNiaNetworkDataSource.kt | 5 +++-- 7 files changed, 38 insertions(+), 24 deletions(-) diff --git a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt index d0262c24f..c7830b28c 100644 --- a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt @@ -16,25 +16,41 @@ package com.google.samples.apps.nowinandroid.core.data.di +import android.app.Application import com.google.samples.apps.nowinandroid.core.data.util.ConnectivityManagerNetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneBroadcastMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.di.AndroidApplicationComponent +import com.google.samples.apps.nowinandroid.core.di.ApplicationScope +import com.google.samples.apps.nowinandroid.core.di.CoroutineScopeComponent +import com.google.samples.apps.nowinandroid.core.di.DispatchersComponent +import com.google.samples.apps.nowinandroid.core.di.IoDispatcher +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component abstract class AndroidPlatformDependentDataModule( @Component val applicationComponent: AndroidApplicationComponent, -): PlatformDependentDataModule() { + @Component val dispatchersComponent: DispatchersComponent, + @Component val coroutineScopeComponent: CoroutineScopeComponent, +) : PlatformDependentDataModule() { + abstract val application: Application + @IoDispatcher abstract val ioDispatcher: CoroutineDispatcher + abstract val coroutineScope: CoroutineScope + @Provides override fun bindsNetworkMonitor(): NetworkMonitor { - return ConnectivityManagerNetworkMonitor(applicationComponent.application) + return ConnectivityManagerNetworkMonitor( + application, + ioDispatcher, + ) } @Provides override fun bindsTimeZoneMonitor(): TimeZoneMonitor { - return TimeZoneBroadcastMonitor() + return TimeZoneBroadcastMonitor(application, coroutineScope, ioDispatcher) } } diff --git a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt index 27fb21eda..615e803cb 100644 --- a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt @@ -23,7 +23,7 @@ import android.content.IntentFilter import android.os.Build.VERSION import android.os.Build.VERSION_CODES import androidx.tracing.trace -import com.google.samples.apps.nowinandroid.core.di.IODispatcher +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharedFlow @@ -42,7 +42,7 @@ import java.time.ZoneId internal class TimeZoneBroadcastMonitor( private val context: Context, appScope: CoroutineScope, - private val ioDispatcher: IODispatcher, + private val ioDispatcher: CoroutineDispatcher, ) : TimeZoneMonitor { override val currentTimeZone: SharedFlow = diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt index 9bdf3da6e..3228f38eb 100644 --- a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt @@ -21,14 +21,11 @@ import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.di.ApplicationScope import me.tatarka.inject.annotations.Provides -@ApplicationScope -abstract class PlatformDependentDataModule { - @ApplicationScope +abstract class PlatformDependentDataModule { @Provides abstract fun bindsNetworkMonitor(): NetworkMonitor - @ApplicationScope @Provides abstract fun bindsTimeZoneMonitor(): TimeZoneMonitor } diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt index cfa582586..921b63dba 100644 --- a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt @@ -23,8 +23,9 @@ import com.google.samples.apps.nowinandroid.core.database.dao.TopicFtsDao import com.google.samples.apps.nowinandroid.core.database.model.PopulatedNewsResource import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel import com.google.samples.apps.nowinandroid.core.database.model.asFtsEntity -import com.google.samples.apps.nowinandroid.core.di.IODispatcher +import com.google.samples.apps.nowinandroid.core.di.IoDispatcher import com.google.samples.apps.nowinandroid.core.model.data.SearchResult +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -42,7 +43,7 @@ class DefaultSearchContentsRepository( private val newsResourceFtsDao: NewsResourceFtsDao, private val topicDao: TopicDao, private val topicFtsDao: TopicFtsDao, - private val ioDispatcher: IODispatcher, + @IoDispatcher private val ioDispatcher: CoroutineDispatcher, ) : SearchContentsRepository { override suspend fun populateFtsData() { diff --git a/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt b/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt index 10845d248..ba733a146 100644 --- a/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt +++ b/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt @@ -23,42 +23,41 @@ import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceFtsDao import com.google.samples.apps.nowinandroid.core.database.dao.RecentSearchQueryDao import com.google.samples.apps.nowinandroid.core.database.dao.TopicDao import com.google.samples.apps.nowinandroid.core.database.dao.TopicFtsDao -import com.google.samples.apps.nowinandroid.core.di.IODispatcher +import com.google.samples.apps.nowinandroid.core.di.DispatchersComponent +import com.google.samples.apps.nowinandroid.core.di.IoDispatcher +import kotlinx.coroutines.CoroutineDispatcher import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -internal abstract class DatabaseModule { +abstract class DatabaseModule(@Component val dispatchersComponent: DispatchersComponent) { + @IoDispatcher abstract val dispatcher: CoroutineDispatcher + @Provides fun providesNiaDatabase(driver: SqlDriver): NiaDatabase = NiaDatabase(driver) @Provides fun providesTopicsDao( - database: NiaDatabase, - dispatcher: IODispatcher, + database: NiaDatabase ): TopicDao = TopicDao(database, dispatcher) @Provides fun providesNewsResourceDao( database: NiaDatabase, - dispatcher: IODispatcher, ): NewsResourceDao = NewsResourceDao(database, dispatcher) @Provides fun providesTopicFtsDao( database: NiaDatabase, - dispatcher: IODispatcher, ): TopicFtsDao = TopicFtsDao(database, dispatcher) @Provides fun providesNewsResourceFtsDao( database: NiaDatabase, - dispatcher: IODispatcher, ): NewsResourceFtsDao = NewsResourceFtsDao(database, dispatcher) @Provides fun providesRecentSearchQueryDao( database: NiaDatabase, - dispatcher: IODispatcher, ): RecentSearchQueryDao = RecentSearchQueryDao(database, dispatcher) } diff --git a/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt index 9cc91745a..d7248081c 100644 --- a/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt @@ -15,8 +15,7 @@ */ package com.google.samples.apps.nowinandroid.core.datastore - -import com.google.samples.apps.nowinandroid.core.di.IODispatcher +import com.google.samples.apps.nowinandroid.core.di.IoDispatcher import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand import com.google.samples.apps.nowinandroid.core.model.data.UserData @@ -25,6 +24,7 @@ import com.russhwolf.settings.Settings import com.russhwolf.settings.serialization.decodeValue import com.russhwolf.settings.serialization.decodeValueOrNull import com.russhwolf.settings.serialization.encodeValue +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map @@ -38,7 +38,7 @@ private const val USER_DATA_KEY = "userData" @Inject class NiaPreferencesDataSource( private val settings: Settings, - private val dispatcher: IODispatcher, + @IoDispatcher private val dispatcher: CoroutineDispatcher, ) { // FlowSettings did not support JS, use a workaround instead // https://github.com/russhwolf/multiplatform-settings/issues/139 diff --git a/core/network/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt b/core/network/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt index 78a71a68a..379ebaf16 100644 --- a/core/network/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt +++ b/core/network/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/network/demo/DemoNiaNetworkDataSource.kt @@ -16,13 +16,14 @@ package com.google.samples.apps.nowinandroid.core.network.demo -import com.google.samples.apps.nowinandroid.core.di.IODispatcher +import com.google.samples.apps.nowinandroid.core.di.IoDispatcher import com.google.samples.apps.nowinandroid.core.network.NiaNetworkDataSource import com.google.samples.apps.nowinandroid.core.network.assets.NEWS_DATA import com.google.samples.apps.nowinandroid.core.network.assets.TOPICS_DATA import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import me.tatarka.inject.annotations.Inject @@ -31,7 +32,7 @@ import me.tatarka.inject.annotations.Inject * [NiaNetworkDataSource] implementation that provides static news resources to aid development */ class DemoNiaNetworkDataSource @Inject constructor( - private val ioDispatcher: IODispatcher, + @IoDispatcher private val ioDispatcher: CoroutineDispatcher, private val networkJson: Json, ) : NiaNetworkDataSource { From 288ec388d720ba61d46b368a9418d0db1c89f9ca Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 13:34:45 -0700 Subject: [PATCH 6/9] Spotless --- .../core/di/CoroutineScopeComponent.kt | 2 +- .../nowinandroid/core/di/DispatcherQualifier.kt | 6 +++--- .../core/di/JvmDispatchersComponent.kt | 2 +- .../data/di/AndroidPlatformDependentDataModule.kt | 2 +- .../core/data/di/PlatformDependentDataModule.kt | 2 -- .../core/database/di/DatabaseModule.kt | 2 +- .../nowinandroid/feature/foryou/ForYouScreen.kt | 14 ++++---------- .../feature/foryou/navigation/ForYouNavigation.kt | 1 - 8 files changed, 11 insertions(+), 20 deletions(-) diff --git a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt index 89b373db0..a10a19c69 100644 --- a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt +++ b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/CoroutineScopeComponent.kt @@ -31,7 +31,7 @@ annotation class ApplicationScope @Component abstract class CoroutineScopeComponent( - @Component val dispatchersComponent: DispatchersComponent + @Component val dispatchersComponent: DispatchersComponent, ) { @DefaultDispatcher abstract val defaultDispatcher: CoroutineDispatcher diff --git a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt index d51c0277a..23cb66353 100644 --- a/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt +++ b/core/common/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/di/DispatcherQualifier.kt @@ -24,7 +24,7 @@ import me.tatarka.inject.annotations.Qualifier AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE, - AnnotationTarget.PROPERTY + AnnotationTarget.PROPERTY, ) annotation class IoDispatcher @@ -34,7 +34,7 @@ annotation class IoDispatcher AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE, - AnnotationTarget.PROPERTY + AnnotationTarget.PROPERTY, ) annotation class MainDispatcher @@ -44,6 +44,6 @@ annotation class MainDispatcher AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE, - AnnotationTarget.PROPERTY + AnnotationTarget.PROPERTY, ) annotation class DefaultDispatcher diff --git a/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt b/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt index 1afab8067..c6df8a244 100644 --- a/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt +++ b/core/common/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/di/JvmDispatchersComponent.kt @@ -22,7 +22,7 @@ import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @Component -abstract class JvmDispatchersComponent: DispatchersComponent() { +abstract class JvmDispatchersComponent : DispatchersComponent() { @Provides override fun providesIODispatcher(): @IoDispatcher CoroutineDispatcher = Dispatchers.IO diff --git a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt index c7830b28c..b42830ae0 100644 --- a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/AndroidPlatformDependentDataModule.kt @@ -22,7 +22,6 @@ import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneBroadcastMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.di.AndroidApplicationComponent -import com.google.samples.apps.nowinandroid.core.di.ApplicationScope import com.google.samples.apps.nowinandroid.core.di.CoroutineScopeComponent import com.google.samples.apps.nowinandroid.core.di.DispatchersComponent import com.google.samples.apps.nowinandroid.core.di.IoDispatcher @@ -38,6 +37,7 @@ abstract class AndroidPlatformDependentDataModule( @Component val coroutineScopeComponent: CoroutineScopeComponent, ) : PlatformDependentDataModule() { abstract val application: Application + @IoDispatcher abstract val ioDispatcher: CoroutineDispatcher abstract val coroutineScope: CoroutineScope diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt index 3228f38eb..3ffa58ecb 100644 --- a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt @@ -18,10 +18,8 @@ package com.google.samples.apps.nowinandroid.core.data.di 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.di.ApplicationScope import me.tatarka.inject.annotations.Provides - abstract class PlatformDependentDataModule { @Provides abstract fun bindsNetworkMonitor(): NetworkMonitor diff --git a/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt b/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt index ba733a146..d202e5229 100644 --- a/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt +++ b/core/database/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/database/di/DatabaseModule.kt @@ -38,7 +38,7 @@ abstract class DatabaseModule(@Component val dispatchersComponent: DispatchersCo @Provides fun providesTopicsDao( - database: NiaDatabase + database: NiaDatabase, ): TopicDao = TopicDao(database, dispatcher) @Provides diff --git a/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 0b867dc20..c43351862 100644 --- a/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -59,15 +59,11 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalContext -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -91,14 +87,12 @@ import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider import com.google.samples.apps.nowinandroid.core.ui.collectAsStateWithLifecycle -import com.google.samples.apps.nowinandroid.core.ui.launchCustomChromeTab import com.google.samples.apps.nowinandroid.core.ui.newsFeed import nowinandroid.feature.foryou.generated.resources.Res import nowinandroid.feature.foryou.generated.resources.feature_foryou_done import nowinandroid.feature.foryou.generated.resources.feature_foryou_loading import nowinandroid.feature.foryou.generated.resources.feature_foryou_onboarding_guidance_subtitle import nowinandroid.feature.foryou.generated.resources.feature_foryou_onboarding_guidance_title -import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.ui.tooling.preview.PreviewParameter @@ -442,9 +436,9 @@ fun TopicIcon( ) } -//@Composable -//@OptIn(ExperimentalPermissionsApi::class) -//private fun NotificationPermissionEffect() { +// @Composable +// @OptIn(ExperimentalPermissionsApi::class) +// private fun NotificationPermissionEffect() { // // Permission requests should only be made from an Activity Context, which is not present // // in previews // if (LocalInspectionMode.current) return @@ -458,7 +452,7 @@ fun TopicIcon( // notificationsPermissionState.launchPermissionRequest() // } // } -//} +// } @Composable private fun DeepLinkEffect( diff --git a/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt index b39b9d93f..5f77351f8 100644 --- a/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt +++ b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt @@ -22,7 +22,6 @@ import androidx.navigation.NavOptions import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument -import com.google.samples.apps.nowinandroid.feature.foryou.ForYouRoute const val LINKED_NEWS_RESOURCE_ID = "linkedNewsResourceId" const val FOR_YOU_ROUTE = "for_you_route/{$LINKED_NEWS_RESOURCE_ID}" From 5ba50fc3250b0baf368fe51a43dec4a130b6748e Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 14:28:33 -0700 Subject: [PATCH 7/9] Temp remove implementations for viewmodels --- .../feature/bookmarks/di/BookmarkComponent.kt | 25 ------------------- .../navigation/BookmarksNavigation.kt | 8 +++--- .../bookmarks/BookmarksViewModelTest.kt | 13 ++++------ 3 files changed, 8 insertions(+), 38 deletions(-) delete mode 100644 feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/di/BookmarkComponent.kt diff --git a/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/di/BookmarkComponent.kt b/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/di/BookmarkComponent.kt deleted file mode 100644 index 68853dc22..000000000 --- a/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/di/BookmarkComponent.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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.feature.bookmarks.di - -import com.google.samples.apps.nowinandroid.feature.bookmarks.BookmarksViewModel -import me.tatarka.inject.annotations.Component - -@Component -abstract class BookmarkComponent { - abstract val viewModel: BookmarksViewModel -} diff --git a/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt b/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt index 64cf40df7..76abd0019 100644 --- a/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt +++ b/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt @@ -21,7 +21,6 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.google.samples.apps.nowinandroid.feature.bookmarks.BookmarksRoute -import com.google.samples.apps.nowinandroid.feature.bookmarks.di.BookmarkComponent const val BOOKMARKS_ROUTE = "bookmarks_route" @@ -31,8 +30,7 @@ fun NavGraphBuilder.bookmarksScreen( onTopicClick: (String) -> Unit, onShowSnackbar: suspend (String, String?) -> Boolean, ) { - val viewModel = BookmarkComponent::class.create().viewModel - composable(route = BOOKMARKS_ROUTE) { - BookmarksRoute(onTopicClick, onShowSnackbar, viewModel) - } +// composable(route = BOOKMARKS_ROUTE) { +// BookmarksRoute(onTopicClick, onShowSnackbar, viewModel) +// } } diff --git a/feature/bookmarks/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt b/feature/bookmarks/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt index 037e9db64..9b8010625 100644 --- a/feature/bookmarks/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt +++ b/feature/bookmarks/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt @@ -20,16 +20,15 @@ import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNe import com.google.samples.apps.nowinandroid.core.testing.data.newsResourcesTestData 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.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test +import kotlin.test.BeforeTest +import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs @@ -38,9 +37,6 @@ import kotlin.test.assertIs * https://developer.android.com/kotlin/flow/test#statein */ class BookmarksViewModelTest { - @get:Rule - val dispatcherRule = MainDispatcherRule() - private val userDataRepository = TestUserDataRepository() private val newsRepository = TestNewsRepository() private val userNewsResourceRepository = CompositeUserNewsResourceRepository( @@ -49,7 +45,7 @@ class BookmarksViewModelTest { ) private lateinit var viewModel: BookmarksViewModel - @Before + @BeforeTest fun setup() { viewModel = BookmarksViewModel( userDataRepository = userDataRepository, @@ -75,6 +71,7 @@ class BookmarksViewModelTest { collectJob.cancel() } + @OptIn(ExperimentalCoroutinesApi::class) @Test fun oneBookmark_whenRemoving_removesFromFeed() = runTest { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.feedUiState.collect() } From 6ca1ec2f68eb7e443b26b6ecd0e09d44ae9a95d4 Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 14:30:35 -0700 Subject: [PATCH 8/9] Opt in ExperimentalCoroutinesApi in ForYouViewModel --- .../samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt index 281e4a4b8..d668b2509 100644 --- a/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt +++ b/feature/foryou/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt @@ -29,6 +29,7 @@ import com.google.samples.apps.nowinandroid.core.data.util.SyncManager import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.feature.foryou.navigation.LINKED_NEWS_RESOURCE_ID +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -52,6 +53,7 @@ class ForYouViewModel @Inject constructor( private val shouldShowOnboarding: Flow = userDataRepository.userData.map { !it.shouldHideOnboarding } + @OptIn(ExperimentalCoroutinesApi::class) val deepLinkedNewsResource = savedStateHandle.getStateFlow( key = LINKED_NEWS_RESOURCE_ID, null, From 75bed25ebd1d69087231fcd79838a593dcac8ba5 Mon Sep 17 00:00:00 2001 From: lihenggui Date: Fri, 28 Jun 2024 14:32:55 -0700 Subject: [PATCH 9/9] Spotless --- .../feature/bookmarks/navigation/BookmarksNavigation.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt b/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt index 76abd0019..faed38e90 100644 --- a/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt +++ b/feature/bookmarks/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt @@ -19,8 +19,6 @@ package com.google.samples.apps.nowinandroid.feature.bookmarks.navigation import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions -import androidx.navigation.compose.composable -import com.google.samples.apps.nowinandroid.feature.bookmarks.BookmarksRoute const val BOOKMARKS_ROUTE = "bookmarks_route"