Skip to content

Commit d94f8e9

Browse files
Refactor Settings Compose Setup
This PR refines the Settings screen setup using Jetpack Compose: * **Navigation Routing**: Updated navigation logic to use **Serialized Routes**, as recommended in the [official Compose navigation documentation](https://developer.android.com/develop/ui/compose/navigation). * **Screen Title Management**: Migrated screen title handling to a Compose-native approach instead of using `addOnDestinationChangedListener`. * **Toolbar Enhancements**: * Refined the toolbar layout and styling to improve alignment with Material theming. * Implemented proper ripple effects and consistent color usage. * Fixed back navigation behavior to align with Compose conventions. * **Theming Note**: The current Compose-based theme system does not yet fully replicate the color palette used in the legacy (pre-Compose) implementation, especially across different services. A `TODO` has been added in code, and a separate task will be created to address this comprehensively.
1 parent d81b571 commit d94f8e9

6 files changed

Lines changed: 65 additions & 40 deletions

File tree

app/src/main/java/org/schabi/newpipe/settings/SettingsScreen.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ import androidx.compose.runtime.Composable
66
import androidx.compose.ui.Modifier
77
import androidx.compose.ui.graphics.Color
88
import org.schabi.newpipe.R
9+
import org.schabi.newpipe.ui.SettingsRoutes
910
import org.schabi.newpipe.ui.TextPreference
1011

1112
@Composable
1213
fun SettingsScreen(
13-
onSelectSettingOption: (SettingsScreenKey) -> Unit,
14+
onSelectSettingOption: (settingsRoute: SettingsRoutes) -> Unit,
1415
modifier: Modifier = Modifier
1516
) {
1617
Column(modifier = modifier) {
1718
TextPreference(
1819
title = R.string.settings_category_debug_title,
19-
onClick = { onSelectSettingOption(SettingsScreenKey.DEBUG) }
20+
onClick = { onSelectSettingOption(SettingsRoutes.SettingsDebugRoute) }
2021
)
2122
HorizontalDivider(color = Color.Black)
2223
}

app/src/main/java/org/schabi/newpipe/settings/SettingsV2Activity.kt

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,19 @@ import androidx.compose.material3.Scaffold
1010
import androidx.compose.runtime.getValue
1111
import androidx.compose.runtime.mutableIntStateOf
1212
import androidx.compose.runtime.remember
13-
import androidx.compose.runtime.setValue
1413
import androidx.compose.ui.Modifier
1514
import androidx.compose.ui.res.stringResource
1615
import androidx.navigation.compose.NavHost
1716
import androidx.navigation.compose.composable
17+
import androidx.navigation.compose.currentBackStackEntryAsState
1818
import androidx.navigation.compose.rememberNavController
19-
import androidx.navigation.navArgument
2019
import dagger.hilt.android.AndroidEntryPoint
2120
import org.schabi.newpipe.R
2221
import org.schabi.newpipe.settings.viewmodel.SettingsViewModel
22+
import org.schabi.newpipe.ui.SettingsRoutes
2323
import org.schabi.newpipe.ui.Toolbar
2424
import org.schabi.newpipe.ui.theme.AppTheme
2525

26-
const val SCREEN_TITLE_KEY = "SCREEN_TITLE_KEY"
27-
2826
@AndroidEntryPoint
2927
class SettingsV2Activity : ComponentActivity() {
3028

@@ -35,37 +33,41 @@ class SettingsV2Activity : ComponentActivity() {
3533

3634
setContent {
3735
val navController = rememberNavController()
38-
var screenTitle by remember { mutableIntStateOf(SettingsScreenKey.ROOT.screenTitle) }
39-
navController.addOnDestinationChangedListener { _, _, arguments ->
40-
screenTitle =
41-
arguments?.getInt(SCREEN_TITLE_KEY) ?: SettingsScreenKey.ROOT.screenTitle
36+
val navBackStackEntry by navController.currentBackStackEntryAsState()
37+
@StringRes val screenTitleRes by remember(navBackStackEntry) {
38+
mutableIntStateOf(
39+
when (navBackStackEntry?.destination?.route) {
40+
SettingsRoutes.SettingsMainRoute::class.java.canonicalName -> SettingsRoutes.SettingsMainRoute.screenTitleRes
41+
SettingsRoutes.SettingsDebugRoute::class.java.canonicalName -> SettingsRoutes.SettingsDebugRoute.screenTitleRes
42+
else -> R.string.settings
43+
}
44+
)
4245
}
4346

4447
AppTheme {
4548
Scaffold(topBar = {
4649
Toolbar(
47-
title = stringResource(id = screenTitle),
50+
title = stringResource(screenTitleRes),
51+
onNavigateBack = {
52+
if (!navController.popBackStack()) {
53+
finish()
54+
}
55+
},
4856
hasSearch = true,
4957
onSearchQueryChange = null // TODO: Add suggestions logic
5058
)
5159
}) { padding ->
5260
NavHost(
5361
navController = navController,
54-
startDestination = SettingsScreenKey.ROOT.name,
62+
startDestination = SettingsRoutes.SettingsMainRoute,
5563
modifier = Modifier.padding(padding)
5664
) {
57-
composable(
58-
SettingsScreenKey.ROOT.name,
59-
listOf(createScreenTitleArg(SettingsScreenKey.ROOT.screenTitle))
60-
) {
61-
SettingsScreen(onSelectSettingOption = { screen ->
62-
navController.navigate(screen.name)
65+
composable<SettingsRoutes.SettingsMainRoute> {
66+
SettingsScreen(onSelectSettingOption = { route ->
67+
navController.navigate(route)
6368
})
6469
}
65-
composable(
66-
SettingsScreenKey.DEBUG.name,
67-
listOf(createScreenTitleArg(SettingsScreenKey.DEBUG.screenTitle))
68-
) {
70+
composable<SettingsRoutes.SettingsDebugRoute> {
6971
DebugScreen(settingsViewModel)
7072
}
7173
}
@@ -74,12 +76,3 @@ class SettingsV2Activity : ComponentActivity() {
7476
}
7577
}
7678
}
77-
78-
fun createScreenTitleArg(@StringRes screenTitle: Int) = navArgument(SCREEN_TITLE_KEY) {
79-
defaultValue = screenTitle
80-
}
81-
82-
enum class SettingsScreenKey(@StringRes val screenTitle: Int) {
83-
ROOT(R.string.settings),
84-
DEBUG(R.string.settings_category_debug_title)
85-
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.schabi.newpipe.ui
2+
3+
import androidx.annotation.StringRes
4+
import kotlinx.serialization.Serializable
5+
import org.schabi.newpipe.R
6+
7+
// Settings screens
8+
@Serializable
9+
sealed class SettingsRoutes(
10+
@get:StringRes
11+
val screenTitleRes: Int
12+
) {
13+
@Serializable
14+
object SettingsMainRoute : SettingsRoutes(R.string.settings)
15+
@Serializable
16+
object SettingsDebugRoute : SettingsRoutes(R.string.settings_category_debug_title)
17+
}

app/src/main/java/org/schabi/newpipe/ui/Toolbar.kt

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import androidx.compose.material3.MaterialTheme
1515
import androidx.compose.material3.SearchBar
1616
import androidx.compose.material3.Text
1717
import androidx.compose.material3.TopAppBar
18+
import androidx.compose.material3.TopAppBarDefaults
1819
import androidx.compose.runtime.Composable
1920
import androidx.compose.runtime.getValue
2021
import androidx.compose.runtime.mutableStateOf
@@ -35,11 +36,13 @@ fun TextAction(text: String, modifier: Modifier = Modifier) {
3536
}
3637

3738
@Composable
38-
fun NavigationIcon() {
39-
Icon(
40-
imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back",
41-
modifier = Modifier.padding(horizontal = SizeTokens.SpacingExtraSmall)
42-
)
39+
fun NavigationIcon(navigateBack: () -> Unit) {
40+
IconButton(onClick = navigateBack) {
41+
Icon(
42+
imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back",
43+
modifier = Modifier.padding(horizontal = SizeTokens.SpacingExtraSmall)
44+
)
45+
}
4346
}
4447

4548
@Composable
@@ -53,7 +56,8 @@ fun SearchSuggestionItem(text: String) {
5356
fun Toolbar(
5457
title: String,
5558
modifier: Modifier = Modifier,
56-
hasNavigationIcon: Boolean = true,
59+
// TODO: Handle search in toolbar in a better way.
60+
onNavigateBack: (() -> Unit)? = null,
5761
hasSearch: Boolean = false,
5862
onSearchQueryChange: ((String) -> List<String>)? = null,
5963
actions: @Composable RowScope.() -> Unit = {}
@@ -65,7 +69,14 @@ fun Toolbar(
6569
TopAppBar(
6670
title = { Text(text = title) },
6771
modifier = modifier,
68-
navigationIcon = { if (hasNavigationIcon) NavigationIcon() },
72+
colors = TopAppBarDefaults.topAppBarColors(
73+
containerColor = MaterialTheme.colorScheme.primaryContainer,
74+
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
75+
actionIconContentColor = MaterialTheme.colorScheme.onPrimaryContainer
76+
),
77+
navigationIcon = {
78+
onNavigateBack?.let { NavigationIcon(onNavigateBack) }
79+
},
6980
actions = {
7081
actions()
7182
if (hasSearch) {

app/src/main/java/org/schabi/newpipe/ui/theme/Color.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package org.schabi.newpipe.ui.theme
22

3+
// Color.kt is generated using the Material theme builder https://material-foundation.github.io/material-theme-builder/
4+
// TODO: Update the colors to properly match the existing color scheme + also add colors schemes for other services
5+
36
import androidx.compose.ui.graphics.Color
47

58
val primaryLight = Color(0xFF904A45)

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ markwon = "4.6.2"
3333
material = "1.11.0"
3434
media = "1.7.0"
3535
mockitoCore = "5.6.0"
36-
navigationCompose = "2.8.3"
36+
navigationCompose = "2.9.0"
3737
okhttp = "4.12.0"
3838
pagingCompose = "3.3.2"
3939
preference = "1.2.1"
@@ -137,7 +137,7 @@ kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p
137137
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
138138
kotlinx-coroutines-rx3 = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-rx3", version.ref = "kotlinxCoroutinesRx3" }
139139
kotlinx-serialization = { group = "org.jetbrains.kotlin", name = "kotlin-serialization", version.ref = "kotlin" }
140-
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
140+
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
141141
lazycolumnscrollbar = { group = "com.github.nanihadesuka", name = "LazyColumnScrollbar", version.ref = "lazycolumnscrollbar" }
142142
leakcanary-android-core = { module = "com.squareup.leakcanary:leakcanary-android-core", version.ref = "leakcanary" }
143143
leakcanary-object-watcher = { group = "com.squareup.leakcanary", name = "leakcanary-object-watcher-android", version.ref = "leakcanary" }

0 commit comments

Comments
 (0)