diff --git a/README.md b/README.md index 66c51b237..eea2627f2 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ As Firebase Analytics does not yet support Kotlin Multiplatform, the implementat | :feature:foryou | In progress | ✔️ | ✔️ | ✔️ | ❌ | | :feature:interests | In progress | ✔️ | ✔️ | ✔️ | ❌ | | :feature:search | In progress | ✔️ | ✔️ | ✔️ | ❌ | -| :feature:settings | Not started | ❌ | ❌ | ❌ | ❌ | +| :feature:settings | Not started | ✔️ | ✔️ | ✔️ | ❌ | | :feature:topic | Not started | ❌ | ❌ | ❌ | ❌ | | lint | Not started | ❌ | ❌ | ❌ | ❌ | | :sync:sync-test | Not started | ❌ | ❌ | ❌ | ❌ | diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts index 15d65204d..6c01874b8 100644 --- a/feature/settings/build.gradle.kts +++ b/feature/settings/build.gradle.kts @@ -15,8 +15,7 @@ */ plugins { - alias(libs.plugins.nowinandroid.android.feature) - alias(libs.plugins.nowinandroid.android.library.compose) + alias(libs.plugins.nowinandroid.cmp.feature) alias(libs.plugins.nowinandroid.android.library.jacoco) } @@ -24,12 +23,32 @@ android { namespace = "com.google.samples.apps.nowinandroid.feature.settings" } -dependencies { - implementation(libs.androidx.appcompat) - implementation(libs.google.oss.licenses) - implementation(projects.core.data) - - testImplementation(projects.core.testing) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.core.data) + implementation(projects.core.ui) + implementation(compose.material3) + implementation(compose.foundation) + implementation(compose.ui) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + } + commonMain.dependencies { + implementation(projects.core.testing) + } + androidUnitTest.dependencies { + implementation(libs.robolectric) + implementation(libs.roborazzi) + implementation(projects.core.screenshotTesting) + } + androidInstrumentedTest.dependencies { + implementation(projects.core.testing) + implementation(libs.bundles.androidx.compose.ui.test) + } + } +} - androidTestImplementation(libs.bundles.androidx.compose.ui.test) +compose.resources { + publicResClass = true } diff --git a/feature/settings/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt b/feature/settings/src/androidInstrumentedTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt similarity index 57% rename from feature/settings/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt rename to feature/settings/src/androidInstrumentedTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt index 790b5964d..342aa6172 100644 --- a/feature/settings/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt +++ b/feature/settings/src/androidInstrumentedTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt @@ -25,6 +25,22 @@ import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.DEFAULT import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success +import kotlinx.coroutines.runBlocking +import nowinandroid.feature.settings.generated.resources.Res +import nowinandroid.feature.settings.generated.resources.feature_settings_brand_android +import nowinandroid.feature.settings.generated.resources.feature_settings_brand_default +import nowinandroid.feature.settings.generated.resources.feature_settings_brand_guidelines +import nowinandroid.feature.settings.generated.resources.feature_settings_dark_mode_config_dark +import nowinandroid.feature.settings.generated.resources.feature_settings_dark_mode_config_light +import nowinandroid.feature.settings.generated.resources.feature_settings_dark_mode_config_system_default +import nowinandroid.feature.settings.generated.resources.feature_settings_dynamic_color_no +import nowinandroid.feature.settings.generated.resources.feature_settings_dynamic_color_preference +import nowinandroid.feature.settings.generated.resources.feature_settings_dynamic_color_yes +import nowinandroid.feature.settings.generated.resources.feature_settings_feedback +import nowinandroid.feature.settings.generated.resources.feature_settings_licenses +import nowinandroid.feature.settings.generated.resources.feature_settings_loading +import nowinandroid.feature.settings.generated.resources.feature_settings_privacy_policy +import org.jetbrains.compose.resources.StringResource import org.junit.Rule import org.junit.Test @@ -33,7 +49,10 @@ class SettingsDialogTest { @get:Rule val composeTestRule = createAndroidComposeRule() - private fun getString(id: Int) = composeTestRule.activity.resources.getString(id) + private fun getString(id: StringResource) = runBlocking { + // TODO remove runBlocking + org.jetbrains.compose.resources.getString(id) + } @Test fun whenLoading_showsLoadingText() { @@ -48,7 +67,7 @@ class SettingsDialogTest { } composeTestRule - .onNodeWithText(getString(R.string.feature_settings_loading)) + .onNodeWithText(getString(Res.string.feature_settings_loading)) .assertExists() } @@ -71,17 +90,17 @@ class SettingsDialogTest { } // Check that all the possible settings are displayed. - composeTestRule.onNodeWithText(getString(R.string.feature_settings_brand_default)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_brand_android)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_brand_default)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_brand_android)).assertExists() composeTestRule.onNodeWithText( - getString(R.string.feature_settings_dark_mode_config_system_default), + getString(Res.string.feature_settings_dark_mode_config_system_default), ).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dark_mode_config_light)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dark_mode_config_dark)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dark_mode_config_light)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dark_mode_config_dark)).assertExists() // Check that the correct settings are selected. - composeTestRule.onNodeWithText(getString(R.string.feature_settings_brand_android)).assertIsSelected() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dark_mode_config_dark)).assertIsSelected() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_brand_android)).assertIsSelected() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dark_mode_config_dark)).assertIsSelected() } @Test @@ -103,12 +122,12 @@ class SettingsDialogTest { ) } - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_preference)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_yes)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_no)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_preference)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_yes)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_no)).assertExists() // Check that the correct default dynamic color setting is selected. - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_no)).assertIsSelected() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_no)).assertIsSelected() } @Test @@ -129,10 +148,10 @@ class SettingsDialogTest { ) } - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_preference)) + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_preference)) .assertDoesNotExist() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_yes)).assertDoesNotExist() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_no)).assertDoesNotExist() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_yes)).assertDoesNotExist() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_no)).assertDoesNotExist() } @Test @@ -153,10 +172,10 @@ class SettingsDialogTest { ) } - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_preference)) + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_preference)) .assertDoesNotExist() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_yes)).assertDoesNotExist() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_dynamic_color_no)).assertDoesNotExist() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_yes)).assertDoesNotExist() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_dynamic_color_no)).assertDoesNotExist() } @Test @@ -177,9 +196,9 @@ class SettingsDialogTest { ) } - composeTestRule.onNodeWithText(getString(R.string.feature_settings_privacy_policy)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_licenses)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_brand_guidelines)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feature_settings_feedback)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_privacy_policy)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_licenses)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_brand_guidelines)).assertExists() + composeTestRule.onNodeWithText(getString(Res.string.feature_settings_feedback)).assertExists() } } diff --git a/feature/settings/src/main/AndroidManifest.xml b/feature/settings/src/commonMain/AndroidManifest.xml similarity index 100% rename from feature/settings/src/main/AndroidManifest.xml rename to feature/settings/src/commonMain/AndroidManifest.xml diff --git a/feature/settings/src/main/res/values/strings.xml b/feature/settings/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from feature/settings/src/main/res/values/strings.xml rename to feature/settings/src/commonMain/composeResources/values/strings.xml diff --git a/feature/settings/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt b/feature/settings/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt similarity index 74% rename from feature/settings/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt rename to feature/settings/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt index db60a6447..e4eea7f99 100644 --- a/feature/settings/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt +++ b/feature/settings/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialog.kt @@ -18,7 +18,6 @@ package com.google.samples.apps.nowinandroid.feature.settings -import android.content.Intent import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -31,7 +30,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectableGroup @@ -45,17 +43,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource +import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.semantics.Role -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.google.android.gms.oss.licenses.OssLicensesMenuActivity import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTextButton import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.supportsDynamicTheming @@ -67,14 +59,34 @@ import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.DEFAULT import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent -import com.google.samples.apps.nowinandroid.feature.settings.R.string +import com.google.samples.apps.nowinandroid.core.ui.collectAsStateWithLifecycle import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success +import nowinandroid.feature.settings.generated.resources.Res +import nowinandroid.feature.settings.generated.resources.feature_settings_brand_android +import nowinandroid.feature.settings.generated.resources.feature_settings_brand_default +import nowinandroid.feature.settings.generated.resources.feature_settings_brand_guidelines +import nowinandroid.feature.settings.generated.resources.feature_settings_dark_mode_config_dark +import nowinandroid.feature.settings.generated.resources.feature_settings_dark_mode_config_light +import nowinandroid.feature.settings.generated.resources.feature_settings_dark_mode_config_system_default +import nowinandroid.feature.settings.generated.resources.feature_settings_dark_mode_preference +import nowinandroid.feature.settings.generated.resources.feature_settings_dismiss_dialog_button_text +import nowinandroid.feature.settings.generated.resources.feature_settings_dynamic_color_no +import nowinandroid.feature.settings.generated.resources.feature_settings_dynamic_color_preference +import nowinandroid.feature.settings.generated.resources.feature_settings_dynamic_color_yes +import nowinandroid.feature.settings.generated.resources.feature_settings_feedback +import nowinandroid.feature.settings.generated.resources.feature_settings_licenses +import nowinandroid.feature.settings.generated.resources.feature_settings_loading +import nowinandroid.feature.settings.generated.resources.feature_settings_privacy_policy +import nowinandroid.feature.settings.generated.resources.feature_settings_theme +import nowinandroid.feature.settings.generated.resources.feature_settings_title +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview @Composable fun SettingsDialog( onDismiss: () -> Unit, - viewModel: SettingsViewModel = hiltViewModel(), + viewModel: SettingsViewModel, ) { val settingsUiState by viewModel.settingsUiState.collectAsStateWithLifecycle() SettingsDialog( @@ -95,7 +107,7 @@ fun SettingsDialog( onChangeDynamicColorPreference: (useDynamicColor: Boolean) -> Unit, onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit, ) { - val configuration = LocalConfiguration.current + val configuration = LocalViewConfiguration.current /** * usePlatformDefaultWidth = false is use as a temporary fix to allow @@ -106,11 +118,10 @@ fun SettingsDialog( */ AlertDialog( properties = DialogProperties(usePlatformDefaultWidth = false), - modifier = Modifier.widthIn(max = configuration.screenWidthDp.dp - 80.dp), onDismissRequest = { onDismiss() }, title = { Text( - text = stringResource(string.feature_settings_title), + text = stringResource(Res.string.feature_settings_title), style = MaterialTheme.typography.titleLarge, ) }, @@ -120,7 +131,7 @@ fun SettingsDialog( when (settingsUiState) { Loading -> { Text( - text = stringResource(string.feature_settings_loading), + text = stringResource(Res.string.feature_settings_loading), modifier = Modifier.padding(vertical = 16.dp), ) } @@ -142,7 +153,7 @@ fun SettingsDialog( }, confirmButton = { Text( - text = stringResource(string.feature_settings_dismiss_dialog_button_text), + text = stringResource(Res.string.feature_settings_dismiss_dialog_button_text), style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary, modifier = Modifier @@ -162,50 +173,50 @@ private fun ColumnScope.SettingsPanel( onChangeDynamicColorPreference: (useDynamicColor: Boolean) -> Unit, onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit, ) { - SettingsDialogSectionTitle(text = stringResource(string.feature_settings_theme)) + SettingsDialogSectionTitle(text = stringResource(Res.string.feature_settings_theme)) Column(Modifier.selectableGroup()) { SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_brand_default), + text = stringResource(Res.string.feature_settings_brand_default), selected = settings.brand == DEFAULT, onClick = { onChangeThemeBrand(DEFAULT) }, ) SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_brand_android), + text = stringResource(Res.string.feature_settings_brand_android), selected = settings.brand == ANDROID, onClick = { onChangeThemeBrand(ANDROID) }, ) } AnimatedVisibility(visible = settings.brand == DEFAULT && supportDynamicColor) { Column { - SettingsDialogSectionTitle(text = stringResource(string.feature_settings_dynamic_color_preference)) + SettingsDialogSectionTitle(text = stringResource(Res.string.feature_settings_dynamic_color_preference)) Column(Modifier.selectableGroup()) { SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_dynamic_color_yes), + text = stringResource(Res.string.feature_settings_dynamic_color_yes), selected = settings.useDynamicColor, onClick = { onChangeDynamicColorPreference(true) }, ) SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_dynamic_color_no), + text = stringResource(Res.string.feature_settings_dynamic_color_no), selected = !settings.useDynamicColor, onClick = { onChangeDynamicColorPreference(false) }, ) } } } - SettingsDialogSectionTitle(text = stringResource(string.feature_settings_dark_mode_preference)) + SettingsDialogSectionTitle(text = stringResource(Res.string.feature_settings_dark_mode_preference)) Column(Modifier.selectableGroup()) { SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_dark_mode_config_system_default), + text = stringResource(Res.string.feature_settings_dark_mode_config_system_default), selected = settings.darkThemeConfig == FOLLOW_SYSTEM, onClick = { onChangeDarkThemeConfig(FOLLOW_SYSTEM) }, ) SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_dark_mode_config_light), + text = stringResource(Res.string.feature_settings_dark_mode_config_light), selected = settings.darkThemeConfig == LIGHT, onClick = { onChangeDarkThemeConfig(LIGHT) }, ) SettingsDialogThemeChooserRow( - text = stringResource(string.feature_settings_dark_mode_config_dark), + text = stringResource(Res.string.feature_settings_dark_mode_config_dark), selected = settings.darkThemeConfig == DARK, onClick = { onChangeDarkThemeConfig(DARK) }, ) @@ -261,25 +272,24 @@ private fun LinksPanel() { NiaTextButton( onClick = { uriHandler.openUri(PRIVACY_POLICY_URL) }, ) { - Text(text = stringResource(string.feature_settings_privacy_policy)) + Text(text = stringResource(Res.string.feature_settings_privacy_policy)) } - val context = LocalContext.current NiaTextButton( onClick = { - context.startActivity(Intent(context, OssLicensesMenuActivity::class.java)) + // Intentionally left blank }, ) { - Text(text = stringResource(string.feature_settings_licenses)) + Text(text = stringResource(Res.string.feature_settings_licenses)) } NiaTextButton( onClick = { uriHandler.openUri(BRAND_GUIDELINES_URL) }, ) { - Text(text = stringResource(string.feature_settings_brand_guidelines)) + Text(text = stringResource(Res.string.feature_settings_brand_guidelines)) } NiaTextButton( onClick = { uriHandler.openUri(FEEDBACK_URL) }, ) { - Text(text = stringResource(string.feature_settings_feedback)) + Text(text = stringResource(Res.string.feature_settings_feedback)) } } } @@ -319,5 +329,6 @@ private fun PreviewSettingsDialogLoading() { } private const val PRIVACY_POLICY_URL = "https://policies.google.com/privacy" -private const val BRAND_GUIDELINES_URL = "https://developer.android.com/distribute/marketing-tools/brand-guidelines" +private const val BRAND_GUIDELINES_URL = + "https://developer.android.com/distribute/marketing-tools/brand-guidelines" private const val FEEDBACK_URL = "https://goo.gle/nia-app-feedback" diff --git a/feature/settings/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt b/feature/settings/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt similarity index 95% rename from feature/settings/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt rename to feature/settings/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt index 123c84d1c..fc172233a 100644 --- a/feature/settings/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt +++ b/feature/settings/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt @@ -23,17 +23,14 @@ 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.feature.settings.SettingsUiState.Loading import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import javax.inject.Inject import kotlin.time.Duration.Companion.seconds -@HiltViewModel -class SettingsViewModel @Inject constructor( +class SettingsViewModel constructor( private val userDataRepository: UserDataRepository, ) : ViewModel() { val settingsUiState: StateFlow = diff --git a/feature/settings/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt b/feature/settings/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt similarity index 90% rename from feature/settings/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt rename to feature/settings/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt index 9062abee6..0de463042 100644 --- a/feature/settings/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt +++ b/feature/settings/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt @@ -19,28 +19,24 @@ package com.google.samples.apps.nowinandroid.feature.settings import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.DARK import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID 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.feature.settings.SettingsUiState.Loading import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.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 class SettingsViewModelTest { - @get:Rule - val mainDispatcherRule = MainDispatcherRule() - private val userDataRepository = TestUserDataRepository() private lateinit var viewModel: SettingsViewModel - @Before + @BeforeTest fun setup() { viewModel = SettingsViewModel(userDataRepository) } @@ -50,6 +46,7 @@ class SettingsViewModelTest { assertEquals(Loading, viewModel.settingsUiState.value) } + @OptIn(ExperimentalCoroutinesApi::class) @Test fun stateIsSuccessAfterUserDataLoaded() = runTest { val collectJob =