diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt index 367285066..49f6f0900 100644 --- a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt +++ b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt @@ -15,9 +15,13 @@ import net.newpipe.app.model.License @Serializable sealed interface Destination : NavKey { + @Serializable + data object AppearanceSettings : Destination + @Serializable data object Settings : Destination @Serializable data object About : Destination } + diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt index fe1f30f91..d7f6f3b61 100644 --- a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt +++ b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt @@ -8,6 +8,7 @@ package net.newpipe.app.navigation import androidx.compose.runtime.mutableStateListOf import co.touchlab.kermit.Logger import net.newpipe.app.screen.about.AboutScreen +import net.newpipe.app.screen.settings.AppearanceSettingsScreen import net.newpipe.app.screen.settings.SettingsHomeScreen import org.koin.core.annotation.KoinExperimentalAPI import org.koin.core.annotation.Provided @@ -32,6 +33,10 @@ fun navModule() = module { navigation { SettingsHomeScreen() } + + navigation { + AppearanceSettingsScreen() + } } /** diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreen.kt b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreen.kt index 1eea3c149..520aee0f1 100644 --- a/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreen.kt +++ b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.tooling.preview.PreviewWrapper import androidx.lifecycle.compose.collectAsStateWithLifecycle import net.newpipe.app.composable.PreferenceRow import net.newpipe.app.composable.TopAppBar +import net.newpipe.app.navigation.Destination import net.newpipe.app.navigation.Navigator import net.newpipe.app.preview.ThemePreviewProvider import net.newpipe.app.screen.settings.model.SettingsCategory @@ -49,8 +50,14 @@ fun SettingsHomeScreen( SettingsCategory( title = type.title, icon = type.icon, - // TODO: Replace with a Destination once sub-screens are migrated - onClick = {} + onClick = { + when (type) { + SettingsCategoryType.APPEARANCE -> + navigator.navigateTo(Destination.AppearanceSettings) + // TODO: wire remaining sub-screens as they are migrated + else -> Unit + } + } ) }, onNavigateUp = { navigator.navigateUp() } diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt b/shared/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt index b6f3c74be..6501a6255 100644 --- a/shared/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt +++ b/shared/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt @@ -16,6 +16,12 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalInspectionMode import com.russhwolf.settings.Settings import org.koin.compose.koinInject +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import com.russhwolf.settings.ObservableSettings private val lightScheme = lightColorScheme( primary = primaryLight, @@ -103,12 +109,15 @@ fun currentColorScheme( useDarkTheme: Boolean = isSystemInDarkTheme(), settings: Settings = koinInject() ): ColorScheme { - val nightScheme = when (settings.getString("night_theme", "dark_theme")) { + val theme = rememberSettingString(settings, "theme", "auto_device_theme") + val nightTheme = rememberSettingString(settings, "night_theme", "dark_theme") + + val nightScheme = when (nightTheme) { "black_theme" -> blackScheme else -> darkScheme } - return when (settings.getString("theme", "auto_device_theme")) { + return when (theme) { "light_theme" -> lightScheme "dark_theme" -> darkScheme "black_theme" -> blackScheme @@ -116,6 +125,27 @@ fun currentColorScheme( } } +/** + * Reads a string setting as Compose state, updating when the stored value changes so theme + * edits made elsewhere (e.g. the Appearance screen) apply live without recreating the host. + */ +@Composable +private fun rememberSettingString( + settings: Settings, + key: String, + defaultValue: String +): String { + var value by remember(key) { mutableStateOf(settings.getString(key, defaultValue)) } + val observable = settings as? ObservableSettings + if (observable != null) { + DisposableEffect(key, observable) { + val listener = observable.addStringListener(key, defaultValue) { value = it } + onDispose { listener.deactivate() } + } + } + return value +} + /** * Default app theme for the NewPipe composables * @param isPreview Whether the theme is being used in preview mode