diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 67eba5cbf..85ee408bc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -55,6 +55,7 @@ runner = "1.7.0" rxandroid = "3.0.2" rxbinding = "4.0.0" rxjava = "3.1.12" +settings = "1.3.0" sonarqube = "7.3.0.8198" statesaver = "1.4.1" # TODO: Drop because it is deprecated and incompatible with KSP2 stetho = "1.6.0" @@ -156,6 +157,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" } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 8848e9ac5..2cd31027e 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -15,6 +15,9 @@ kotlin { jvmToolchain(21) compilerOptions { + freeCompilerArgs.addAll( + "-Xexpect-actual-classes" + ) optIn.addAll( "androidx.compose.material3.ExperimentalMaterial3Api", "androidx.compose.material3.ExperimentalMaterial3ExpressiveApi", @@ -80,6 +83,8 @@ kotlin { implementation(libs.koin.compose.viewmodel) implementation(libs.koin.annotations) + + implementation(libs.russhwolf.settings) } } commonTest.dependencies { @@ -89,6 +94,7 @@ kotlin { androidMain.dependencies { implementation(libs.jetbrains.compose.preview) implementation(libs.androidx.activity) + implementation(libs.androidx.preference) } val androidDeviceTest by getting { dependencies { diff --git a/shared/src/androidMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt b/shared/src/androidMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt new file mode 100644 index 000000000..e69de29bb diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt b/shared/src/commonMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt new file mode 100644 index 000000000..e69de29bb 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 28088a6d0..5500ffeff 100644 --- a/shared/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt +++ b/shared/src/commonMain/kotlin/net/newpipe/app/theme/Theme.kt @@ -7,11 +7,15 @@ package net.newpipe.app.theme import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialExpressiveTheme -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 androidx.compose.ui.platform.LocalInspectionMode +import com.russhwolf.settings.Settings +import org.koin.compose.koinInject private val lightScheme = lightColorScheme( primary = primaryLight, @@ -89,13 +93,43 @@ private val darkScheme = darkColorScheme( surfaceContainerHighest = surfaceContainerHighestDark ) +private val blackScheme = darkScheme.copy(surface = Color.Black) + +/** + * Gets current color scheme chosen by the user + */ @Composable -fun AppTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { +fun currentColorScheme( + useDarkTheme: Boolean = isSystemInDarkTheme(), + settings: Settings = koinInject() +): ColorScheme { + val nightScheme = when (settings.getString("night_theme", "dark_theme")) { + "black_theme" -> blackScheme + else -> darkScheme + } + + return when (settings.getString("theme", "auto_device_theme")) { + "light_theme" -> lightScheme + "dark_theme" -> darkScheme + "black_theme" -> blackScheme + else -> if (!useDarkTheme) lightScheme else nightScheme + } +} + +/** + * Default app theme for the NewPipe composables + * @param isPreview Whether the theme is being used in preview mode + * @param colorScheme Color scheme to use for theme, defaults to light in preview mode + * @param content Composable content to show to the user + */ +@Composable +fun AppTheme( + isPreview: Boolean = LocalInspectionMode.current, + colorScheme: ColorScheme = if (isPreview) lightScheme else currentColorScheme(), + content: @Composable () -> Unit +) { MaterialExpressiveTheme( - colorScheme = when { - !useDarkTheme -> lightScheme - else -> darkScheme - }, + colorScheme = colorScheme, content = content ) } diff --git a/shared/src/iosMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt b/shared/src/iosMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt new file mode 100644 index 000000000..e69de29bb diff --git a/shared/src/jvmMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt b/shared/src/jvmMain/kotlin/net/newpipe/app/di/settings/SettingsModule.kt new file mode 100644 index 000000000..e69de29bb