Refactor settings feature from api to impl

The `feature:settings:api` module has been renamed to `feature:settings:impl` to better reflect its role as an implementation module.

This change includes:
*   Updating module paths and namespaces.
*   Moving all related files, including source code, resources, and tests, to the new `impl` directory.
*   Updating dependencies and project configurations in Gradle scripts and README files to point to the new module path.
*   Renaming string resources to include the `_impl` suffix for clarity.
*   Updating the AndroidX Lifecycle dependency to version 2.10.0.
pull/2003/head
Don Turner 1 week ago
parent 5ea5a64786
commit 1ded3e3db5

@ -54,7 +54,7 @@ graph TB
end
subgraph :feature:settings
direction TB
:feature:settings:api[api]:::android-library
:feature:settings:impl[impl]:::android-library
end
subgraph :sync
direction TB
@ -78,7 +78,7 @@ graph TB
:app -.-> :feature:interests:impl
:app -.-> :feature:search:api
:app -.-> :feature:search:impl
:app -.-> :feature:settings:api
:app -.-> :feature:settings:impl
:app -.-> :feature:topic:api
:app -.-> :feature:topic:impl
:app -.-> :sync:work
@ -129,9 +129,9 @@ graph TB
:feature:search:impl -.-> :feature:interests:api
:feature:search:impl -.-> :feature:search:api
:feature:search:impl -.-> :feature:topic:api
:feature:settings:api -.-> :core:data
:feature:settings:api -.-> :core:designsystem
:feature:settings:api -.-> :core:ui
:feature:settings:impl -.-> :core:data
:feature:settings:impl -.-> :core:designsystem
:feature:settings:impl -.-> :core:ui
:feature:topic:api -.-> :core:designsystem
:feature:topic:api --> :core:navigation
:feature:topic:api -.-> :core:ui

@ -78,7 +78,7 @@ dependencies {
implementation(projects.feature.topic.impl)
implementation(projects.feature.search.api)
implementation(projects.feature.search.impl)
implementation(projects.feature.settings.api)
implementation(projects.feature.settings.impl)
implementation(projects.core.common)
implementation(projects.core.ui)

@ -53,7 +53,7 @@ import javax.inject.Inject
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.R as BookmarksR
import com.google.samples.apps.nowinandroid.feature.foryou.api.R as FeatureForyouR
import com.google.samples.apps.nowinandroid.feature.search.api.R as FeatureSearchR
import com.google.samples.apps.nowinandroid.feature.settings.api.R as SettingsR
import com.google.samples.apps.nowinandroid.feature.settings.impl.R as SettingsR
/**
* Tests all the navigation flows that are handled by the navigation library.

@ -81,10 +81,10 @@ import com.google.samples.apps.nowinandroid.feature.foryou.impl.navigation.forYo
import com.google.samples.apps.nowinandroid.feature.interests.impl.navigation.interestsEntry
import com.google.samples.apps.nowinandroid.feature.search.api.navigation.SearchNavKey
import com.google.samples.apps.nowinandroid.feature.search.impl.navigation.searchEntry
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsDialog
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsDialog
import com.google.samples.apps.nowinandroid.feature.topic.impl.navigation.topicEntry
import com.google.samples.apps.nowinandroid.navigation.TOP_LEVEL_NAV_ITEMS
import com.google.samples.apps.nowinandroid.feature.settings.api.R as settingsR
import com.google.samples.apps.nowinandroid.feature.settings.impl.R as settingsR
@Composable
fun NiaApp(
@ -230,11 +230,11 @@ internal fun NiaApp(
titleRes = destination.titleTextId,
navigationIcon = NiaIcons.Search,
navigationIconContentDescription = stringResource(
id = settingsR.string.feature_settings_top_app_bar_navigation_icon_description,
id = settingsR.string.feature_settings_impl_top_app_bar_navigation_icon_description,
),
actionIcon = NiaIcons.Settings,
actionIconContentDescription = stringResource(
id = settingsR.string.feature_settings_top_app_bar_action_icon_description,
id = settingsR.string.feature_settings_impl_top_app_bar_action_icon_description,
),
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,

@ -54,7 +54,7 @@ graph TB
end
subgraph :feature:settings
direction TB
:feature:settings:api[api]:::android-library
:feature:settings:impl[impl]:::android-library
end
subgraph :sync
direction TB
@ -78,7 +78,7 @@ graph TB
:app -.-> :feature:interests:impl
:app -.-> :feature:search:api
:app -.-> :feature:search:impl
:app -.-> :feature:settings:api
:app -.-> :feature:settings:impl
:app -.-> :feature:topic:api
:app -.-> :feature:topic:impl
:app -.-> :sync:work
@ -129,9 +129,9 @@ graph TB
:feature:search:impl -.-> :feature:interests:api
:feature:search:impl -.-> :feature:search:api
:feature:search:impl -.-> :feature:topic:api
:feature:settings:api -.-> :core:data
:feature:settings:api -.-> :core:designsystem
:feature:settings:api -.-> :core:ui
:feature:settings:impl -.-> :core:data
:feature:settings:impl -.-> :core:designsystem
:feature:settings:impl -.-> :core:ui
:feature:topic:api -.-> :core:designsystem
:feature:topic:api --> :core:navigation
:feature:topic:api -.-> :core:ui

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 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
http://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.
-->
<resources>
<string name="feature_settings_top_app_bar_action_icon_description">Settings</string>
<string name="feature_settings_top_app_bar_navigation_icon_description">Search</string>
<string name="feature_settings_title">Settings</string>
<string name="feature_settings_loading">Loading…</string>
<string name="feature_settings_privacy_policy">Privacy policy</string>
<string name="feature_settings_licenses">Licenses</string>
<string name="feature_settings_brand_guidelines">Brand Guidelines</string>
<string name="feature_settings_feedback">Feedback</string>
<string name="feature_settings_theme">Theme</string>
<string name="feature_settings_brand_default">Default</string>
<string name="feature_settings_brand_android">Android</string>
<string name="feature_settings_dark_mode_preference">Dark mode preference</string>
<string name="feature_settings_dark_mode_config_system_default">System default</string>
<string name="feature_settings_dark_mode_config_light">Light</string>
<string name="feature_settings_dark_mode_config_dark">Dark</string>
<string name="feature_settings_dynamic_color_preference">Use Dynamic Color</string>
<string name="feature_settings_dynamic_color_yes">Yes</string>
<string name="feature_settings_dynamic_color_no">No</string>
<string name="feature_settings_dismiss_dialog_button_text">OK</string>
</resources>

@ -27,7 +27,7 @@ graph TB
end
subgraph :feature:settings
direction TB
:feature:settings:api[api]:::android-library
:feature:settings:impl[impl]:::android-library
end
:core:data -.-> :core:analytics
@ -47,9 +47,9 @@ graph TB
:core:ui --> :core:analytics
:core:ui --> :core:designsystem
:core:ui --> :core:model
:feature:settings:api -.-> :core:data
:feature:settings:api -.-> :core:designsystem
:feature:settings:api -.-> :core:ui
:feature:settings:impl -.-> :core:data
:feature:settings:impl -.-> :core:designsystem
:feature:settings:impl -.-> :core:ui
classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;

@ -21,7 +21,7 @@ plugins {
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.settings.api"
namespace = "com.google.samples.apps.nowinandroid.feature.settings.impl"
}
dependencies {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.settings.api
package com.google.samples.apps.nowinandroid.feature.settings.impl
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.assertIsSelected
@ -23,8 +23,8 @@ import androidx.compose.ui.test.onNodeWithText
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.model.data.ThemeBrand.DEFAULT
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Success
import org.junit.Rule
import org.junit.Test

@ -1,5 +1,5 @@
/*
* Copyright 2022 The Android Open Source Project
* Copyright 2025 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.
@ -16,7 +16,7 @@
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.feature.settings.api
package com.google.samples.apps.nowinandroid.feature.settings.impl
import android.content.Intent
import androidx.compose.animation.AnimatedVisibility
@ -66,9 +66,9 @@ 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.api.R.string
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.impl.R.string
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Success
@Composable
fun SettingsDialog(
@ -109,7 +109,7 @@ fun SettingsDialog(
onDismissRequest = { onDismiss() },
title = {
Text(
text = stringResource(string.feature_settings_title),
text = stringResource(string.feature_settings_impl_title),
style = MaterialTheme.typography.titleLarge,
)
},
@ -119,7 +119,7 @@ fun SettingsDialog(
when (settingsUiState) {
Loading -> {
Text(
text = stringResource(string.feature_settings_loading),
text = stringResource(string.feature_settings_impl_loading),
modifier = Modifier.padding(vertical = 16.dp),
)
}
@ -145,7 +145,7 @@ fun SettingsDialog(
modifier = Modifier.padding(horizontal = 8.dp),
) {
Text(
text = stringResource(string.feature_settings_dismiss_dialog_button_text),
text = stringResource(string.feature_settings_impl_dismiss_dialog_button_text),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary,
)
@ -163,50 +163,50 @@ private fun ColumnScope.SettingsPanel(
onChangeDynamicColorPreference: (useDynamicColor: Boolean) -> Unit,
onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit,
) {
SettingsDialogSectionTitle(text = stringResource(string.feature_settings_theme))
SettingsDialogSectionTitle(text = stringResource(string.feature_settings_impl_theme))
Column(Modifier.selectableGroup()) {
SettingsDialogThemeChooserRow(
text = stringResource(string.feature_settings_brand_default),
text = stringResource(string.feature_settings_impl_brand_default),
selected = settings.brand == DEFAULT,
onClick = { onChangeThemeBrand(DEFAULT) },
)
SettingsDialogThemeChooserRow(
text = stringResource(string.feature_settings_brand_android),
text = stringResource(string.feature_settings_impl_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(string.feature_settings_impl_dynamic_color_preference))
Column(Modifier.selectableGroup()) {
SettingsDialogThemeChooserRow(
text = stringResource(string.feature_settings_dynamic_color_yes),
text = stringResource(string.feature_settings_impl_dynamic_color_yes),
selected = settings.useDynamicColor,
onClick = { onChangeDynamicColorPreference(true) },
)
SettingsDialogThemeChooserRow(
text = stringResource(string.feature_settings_dynamic_color_no),
text = stringResource(string.feature_settings_impl_dynamic_color_no),
selected = !settings.useDynamicColor,
onClick = { onChangeDynamicColorPreference(false) },
)
}
}
}
SettingsDialogSectionTitle(text = stringResource(string.feature_settings_dark_mode_preference))
SettingsDialogSectionTitle(text = stringResource(string.feature_settings_impl_dark_mode_preference))
Column(Modifier.selectableGroup()) {
SettingsDialogThemeChooserRow(
text = stringResource(string.feature_settings_dark_mode_config_system_default),
text = stringResource(string.feature_settings_impl_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(string.feature_settings_impl_dark_mode_config_light),
selected = settings.darkThemeConfig == LIGHT,
onClick = { onChangeDarkThemeConfig(LIGHT) },
)
SettingsDialogThemeChooserRow(
text = stringResource(string.feature_settings_dark_mode_config_dark),
text = stringResource(string.feature_settings_impl_dark_mode_config_dark),
selected = settings.darkThemeConfig == DARK,
onClick = { onChangeDarkThemeConfig(DARK) },
)
@ -262,7 +262,7 @@ private fun LinksPanel() {
NiaTextButton(
onClick = { uriHandler.openUri(PRIVACY_POLICY_URL) },
) {
Text(text = stringResource(string.feature_settings_privacy_policy))
Text(text = stringResource(string.feature_settings_impl_privacy_policy))
}
val context = LocalContext.current
NiaTextButton(
@ -270,17 +270,17 @@ private fun LinksPanel() {
context.startActivity(Intent(context, OssLicensesMenuActivity::class.java))
},
) {
Text(text = stringResource(string.feature_settings_licenses))
Text(text = stringResource(string.feature_settings_impl_licenses))
}
NiaTextButton(
onClick = { uriHandler.openUri(BRAND_GUIDELINES_URL) },
) {
Text(text = stringResource(string.feature_settings_brand_guidelines))
Text(text = stringResource(string.feature_settings_impl_brand_guidelines))
}
NiaTextButton(
onClick = { uriHandler.openUri(FEEDBACK_URL) },
) {
Text(text = stringResource(string.feature_settings_feedback))
Text(text = stringResource(string.feature_settings_impl_feedback))
}
}
}

@ -14,15 +14,15 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.settings.api
package com.google.samples.apps.nowinandroid.feature.settings.impl
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
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.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Success
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
import kotlinx.coroutines.flow.StateFlow

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 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
http://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.
-->
<resources>
<string name="feature_settings_impl_top_app_bar_action_icon_description">Settings</string>
<string name="feature_settings_impl_top_app_bar_navigation_icon_description">Search</string>
<string name="feature_settings_impl_title">Settings</string>
<string name="feature_settings_impl_loading">Loading…</string>
<string name="feature_settings_impl_privacy_policy">Privacy policy</string>
<string name="feature_settings_impl_licenses">Licenses</string>
<string name="feature_settings_impl_brand_guidelines">Brand Guidelines</string>
<string name="feature_settings_impl_feedback">Feedback</string>
<string name="feature_settings_impl_theme">Theme</string>
<string name="feature_settings_impl_brand_default">Default</string>
<string name="feature_settings_impl_brand_android">Android</string>
<string name="feature_settings_impl_dark_mode_preference">Dark mode preference</string>
<string name="feature_settings_impl_dark_mode_config_system_default">System default</string>
<string name="feature_settings_impl_dark_mode_config_light">Light</string>
<string name="feature_settings_impl_dark_mode_config_dark">Dark</string>
<string name="feature_settings_impl_dynamic_color_preference">Use Dynamic Color</string>
<string name="feature_settings_impl_dynamic_color_yes">Yes</string>
<string name="feature_settings_impl_dynamic_color_no">No</string>
<string name="feature_settings_impl_dismiss_dialog_button_text">OK</string>
</resources>

@ -14,14 +14,14 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.settings.api
package com.google.samples.apps.nowinandroid.feature.settings.impl
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.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.impl.SettingsUiState.Success
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher

@ -17,7 +17,7 @@ androidxCoreSplashscreen = "1.0.1"
androidxDataStore = "1.2.0"
androidxEspresso = "3.6.1"
androidxHiltLifecycleViewModelCompose = "1.3.0-alpha02"
androidxLifecycle = "2.8.7"
androidxLifecycle = "2.10.0"
androidxLintGradle = "1.0.0-alpha03"
androidxLifecycleViewModelNavigation3 = "2.10.0"
androidxMacroBenchmark = "1.4.1"

@ -76,7 +76,7 @@ include(":feature:topic:api")
include(":feature:topic:impl")
include(":feature:search:api")
include(":feature:search:impl")
include(":feature:settings:api")
include(":feature:settings:impl")
include(":lint")
include(":sync:work")
include(":sync:sync-test")

Loading…
Cancel
Save