diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index b097d4ceb..92e8dc7f1 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -49,22 +49,22 @@ kotlin { implementation(libs.jetbrains.lifecycle.viewmodel) // Koin - implementation(project.dependencies.platform(libs.koin.bom)) api(libs.koin.annotations) implementation(libs.koin.core) implementation(libs.koin.compose) implementation(libs.koin.viewmodel) + + // Settings + implementation(libs.russhwolf.settings) } commonTest.dependencies { implementation(libs.kotlin.test) - - // Koin - implementation(project.dependencies.platform(libs.koin.bom)) implementation(libs.koin.test) } androidMain.dependencies { implementation(compose.preview) implementation(libs.androidx.activity) + implementation(libs.androidx.preference) } jvmMain.dependencies { implementation(compose.desktop.currentOs) diff --git a/composeApp/src/androidMain/kotlin/net/newpipe/app/module/Koin.android.kt b/composeApp/src/androidMain/kotlin/net/newpipe/app/module/Koin.android.kt new file mode 100644 index 000000000..4f0c22d40 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/net/newpipe/app/module/Koin.android.kt @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2026 NewPipe e.V. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package net.newpipe.app.module + +import androidx.preference.PreferenceManager +import com.russhwolf.settings.Settings +import com.russhwolf.settings.SharedPreferencesSettings +import org.koin.android.ext.koin.androidContext +import org.koin.dsl.module + +actual val platformModule = module { + single { + SharedPreferencesSettings(PreferenceManager.getDefaultSharedPreferences(androidContext())) + } +} diff --git a/composeApp/src/commonMain/kotlin/net/newpipe/app/App.kt b/composeApp/src/commonMain/kotlin/net/newpipe/app/App.kt index 5ac426ed8..466742c68 100644 --- a/composeApp/src/commonMain/kotlin/net/newpipe/app/App.kt +++ b/composeApp/src/commonMain/kotlin/net/newpipe/app/App.kt @@ -6,7 +6,7 @@ package net.newpipe.app import androidx.compose.runtime.Composable -import net.newpipe.app.module.appModules +import net.newpipe.app.module.platformModule import net.newpipe.app.theme.AppTheme import org.koin.compose.KoinMultiplatformApplication import org.koin.core.annotation.KoinExperimentalAPI @@ -17,7 +17,7 @@ import org.koin.dsl.koinConfiguration fun App() { KoinMultiplatformApplication( config = koinConfiguration { - modules(appModules) + modules(platformModule) } ) { AppTheme { diff --git a/composeApp/src/commonMain/kotlin/net/newpipe/app/module/Koin.kt b/composeApp/src/commonMain/kotlin/net/newpipe/app/module/Koin.kt index 12654bb25..6bc961c9f 100644 --- a/composeApp/src/commonMain/kotlin/net/newpipe/app/module/Koin.kt +++ b/composeApp/src/commonMain/kotlin/net/newpipe/app/module/Koin.kt @@ -5,8 +5,9 @@ package net.newpipe.app.module -import org.koin.dsl.module +import org.koin.core.module.Module -val appModules = module { - -} +/** + * Contains platform specific module; See actual implementation for more details + */ +expect val platformModule: Module diff --git a/composeApp/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt b/composeApp/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt index 2d4356bd6..c3114203e 100644 --- a/composeApp/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt +++ b/composeApp/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt @@ -11,6 +11,9 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import com.russhwolf.settings.Settings +import org.koin.compose.koinInject private val lightScheme = lightColorScheme( primary = primaryLight, @@ -88,12 +91,25 @@ private val darkScheme = darkColorScheme( surfaceContainerHighest = surfaceContainerHighestDark, ) +private val blackScheme = darkScheme.copy(surface = Color.Black) + @Composable -fun AppTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { +fun AppTheme( + useDarkTheme: Boolean = isSystemInDarkTheme(), + settings: Settings = koinInject(), + content: @Composable () -> Unit +) { + val nightScheme = when(settings.getString("night_theme", "dark_theme")) { + "black_theme" -> blackScheme + else -> darkScheme + } + MaterialTheme( - colorScheme = when { - !useDarkTheme -> lightScheme - else -> darkScheme + colorScheme = when(settings.getString("theme", "auto_device_theme")) { + "light_theme" -> lightScheme + "dark_theme" -> darkScheme + "black_theme" -> blackScheme + else -> if (!useDarkTheme) lightScheme else nightScheme }, content = content ) diff --git a/composeApp/src/iosMain/kotlin/net/newpipe/app/module/Koin.ios.kt b/composeApp/src/iosMain/kotlin/net/newpipe/app/module/Koin.ios.kt new file mode 100644 index 000000000..1a8c2e77b --- /dev/null +++ b/composeApp/src/iosMain/kotlin/net/newpipe/app/module/Koin.ios.kt @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2026 NewPipe e.V. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package net.newpipe.app.module + +import com.russhwolf.settings.NSUserDefaultsSettings +import com.russhwolf.settings.Settings +import org.koin.dsl.module +import platform.Foundation.NSUserDefaults + +actual val platformModule = module { + single { + NSUserDefaultsSettings(NSUserDefaults()) + } +} diff --git a/composeApp/src/jvmMain/kotlin/net/newpipe/app/module/Koin.jvm.kt b/composeApp/src/jvmMain/kotlin/net/newpipe/app/module/Koin.jvm.kt new file mode 100644 index 000000000..ee177af78 --- /dev/null +++ b/composeApp/src/jvmMain/kotlin/net/newpipe/app/module/Koin.jvm.kt @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2026 NewPipe e.V. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package net.newpipe.app.module + +import com.russhwolf.settings.PreferencesSettings +import com.russhwolf.settings.Settings +import org.koin.dsl.module +import java.util.prefs.Preferences + +actual val platformModule = module { + single { + PreferencesSettings(Preferences.userRoot()) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8c544195e..9e0efbd77 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,6 +52,7 @@ runner = "1.7.0" rxandroid = "3.0.2" rxbinding = "4.0.0" rxjava = "3.1.12" +settings = "1.3.0" sonarqube = "7.2.1.6560" statesaver = "1.4.1" # TODO: Drop because it is deprecated and incompatible with KSP2 stetho = "1.6.0" @@ -120,12 +121,11 @@ jetbrains-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lif jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } junit = { module = "junit:junit", version.ref = "junit" } koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin-annotations" } -koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" } koin-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koin-annotations" } -koin-compose = { module = "io.insert-koin:koin-compose" } -koin-core = { module = "io.insert-koin:koin-core" } -koin-test = { module = "io.insert-koin:koin-test" } -koin-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel" } +koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin-bom" } +koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin-bom" } +koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin-bom" } +koin-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin-bom" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } lisawray-groupie-core = { module = "com.github.lisawray.groupie:groupie", version.ref = "groupie" } lisawray-groupie-viewbinding = { module = "com.github.lisawray.groupie:groupie-viewbinding", version.ref = "groupie" } @@ -141,6 +141,7 @@ pinterest-ktlint = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = " puppycrawl-checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } reactivex-rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" } reactivex-rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" } +russhwolf-settings = { module = "com.russhwolf:multiplatform-settings", version.ref = "settings" } squareup-leakcanary-core = { module = "com.squareup.leakcanary:leakcanary-android-core", version.ref = "leakcanary" } squareup-leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakcanary" } squareup-leakcanary-watcher = { module = "com.squareup.leakcanary:leakcanary-object-watcher-android", version.ref = "leakcanary" }