From f9d339f111eee23aee7a769094388e38d8e21bb7 Mon Sep 17 00:00:00 2001 From: Yiqun Zhang Date: Fri, 1 Dec 2023 19:19:23 +0800 Subject: [PATCH 1/2] :sparkles: Support for switching themes --- composeApp/build.gradle.kts | 7 +++ .../kotlin/com/clipevery/ClipeveryApp.kt | 6 +- .../kotlin/com/clipevery/model/AppConfig.kt | 5 +- .../kotlin/com/clipevery/ui/ClipeveryTheme.kt | 63 +++++++++++++++++++ .../kotlin/com/clipevery/ui/HomeUI.kt | 6 +- .../kotlin/com/clipevery/ui/SettingsItemUI.kt | 12 ++-- .../kotlin/com/clipevery/ui/SettingsUI.kt | 21 ++++--- .../kotlin/com/clipevery/ui/TabsUI.kt | 4 +- .../com/clipevery/ui/ThemeSegmentedControl.kt | 22 +++---- .../com/clipevery/ui/WindowDecoration.kt | 4 +- .../com/clipevery/log/Logger.desktop.kt | 3 + .../desktopMain/kotlin/com/clipevery/main.kt | 3 + .../clipevery/ui/ClipeveryTheme.desktop.kt | 42 +++++++++++++ 13 files changed, 164 insertions(+), 34 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt create mode 100644 composeApp/src/desktopMain/kotlin/com/clipevery/ui/ClipeveryTheme.desktop.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index c94954cf2..349edf11a 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -1,5 +1,11 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.compose.ExperimentalComposeLibrary +import java.net.URI + +repositories { + mavenCentral() + maven { url = URI("https://jitpack.io") } +} plugins { alias(libs.plugins.kotlinMultiplatform) @@ -38,6 +44,7 @@ kotlin { implementation("io.insert-koin:koin-core:3.5.0") implementation("com.github.kwhat:jnativehook:2.2.2") implementation("app.cash.sqldelight:sqlite-driver:2.0.0") + implementation("com.github.Dansoftowner:jSystemThemeDetector:3.8") } commonMain.dependencies { implementation(compose.runtime) diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt index 30a89492a..b00ab065d 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt @@ -23,6 +23,8 @@ import androidx.compose.ui.graphics.toComposeImageBitmap import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import com.clipevery.ui.AboutUI +import com.clipevery.ui.ClipeveryTheme +import com.clipevery.ui.ClipeveryTheme import com.clipevery.ui.HomeUI import com.clipevery.ui.SettingsUI import org.koin.core.KoinApplication @@ -38,7 +40,7 @@ fun ClipeveryApp(koinApplication: KoinApplication, hideWindow: () -> Unit) { @Composable fun ClipeveryWindow(hideWindow: () -> Unit) { - MaterialTheme { + ClipeveryTheme { Box(modifier = Modifier .background(Color.Transparent) .pointerInput(Unit) { @@ -77,7 +79,7 @@ fun ClipeveryWindow(hideWindow: () -> Unit) { ) { Column(Modifier .clip(RoundedCornerShape(10.dp)) - .background(Color.White) + .background(MaterialTheme.colors.background) .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { ClipeveryContent() diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/model/AppConfig.kt b/composeApp/src/commonMain/kotlin/com/clipevery/model/AppConfig.kt index 5d745220e..87822f82c 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/model/AppConfig.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/model/AppConfig.kt @@ -6,4 +6,7 @@ import java.util.Locale @Serializable data class AppConfig( val bindingState: Boolean = false, - val language: String = Locale.getDefault().language,) + val language: String = Locale.getDefault().language, + val isFollowSystem: Boolean = true, + val isDark: Boolean = false +) diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt new file mode 100644 index 000000000..9e63b79af --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt @@ -0,0 +1,63 @@ +package com.clipevery.ui + +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import com.clipevery.LocalKoinApplication + + +private val LightColorPalette = lightColors( + primary = Color(0xFF1672FF), + primaryVariant = Color(0xFF247CFF), + secondary = Color(0xFFFF9DC0), + secondaryVariant = Color(0xFFFFACB5), +) + +private val DarkColorPalette = darkColors( + primary = Color(0xFFBB86FC), + primaryVariant = Color(0xFF3700B3), + secondary = Color(0xFF363B3E), + secondaryVariant = Color(0xFF363B3E), + background = Color(0xFF202326), + surface = Color(0xFF2F3338) +) + +@Composable +fun ClipeveryTheme(content: @Composable () -> Unit) { + val current = LocalKoinApplication.current + val themeDetector = current.koin.get() + + val colors = if (themeDetector.isFollowSystem()) { + if (themeDetector.isSystemInDark()) { + DarkColorPalette + } else { + LightColorPalette + } + } else { + if (themeDetector.isUserInDark()) { + DarkColorPalette + } else { + LightColorPalette + } + } + MaterialTheme( + colors = colors, + content = content + ) +} + +interface ThemeDetector { + fun isSystemInDark(): Boolean + + fun isFollowSystem(): Boolean + + fun isUserInDark(): Boolean + + fun isCurrentThemeDark(): Boolean { + return isFollowSystem() && isSystemInDark() || !isFollowSystem() && isUserInDark() + } + + fun setThemeConfig(isFollowSystem: Boolean, isUserInDark: Boolean = false) +} diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/HomeUI.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/HomeUI.kt index 6df8c6b25..3da71ab7b 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/HomeUI.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/HomeUI.kt @@ -25,6 +25,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -187,7 +188,7 @@ fun TitleUI(currentPage: MutableState) { .width(180.dp) .wrapContentHeight() .clip(RoundedCornerShape(5.dp)) - .background(Color.White) + .background(MaterialTheme.colors.surface) ) { MenuItem(copywriter.getText("Check_for_updates")) { // TODO: check for updates @@ -223,10 +224,11 @@ fun TitleUI(currentPage: MutableState) { fun MenuItem(text: String, onClick: () -> Unit) { val interactionSource = remember { MutableInteractionSource() } val isHovered by interactionSource.collectIsHoveredAsState() - val backgroundColor = if (isHovered) Color(0xFFE8F5FF) else Color.Transparent + val backgroundColor = if (isHovered) MaterialTheme.colors.secondaryVariant else Color.Transparent Text( text = text, + color = MaterialTheme.colors.onBackground, fontSize = 12.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light), diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsItemUI.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsItemUI.kt index d4a5cb55f..f67032cc1 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsItemUI.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsItemUI.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -20,7 +21,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.onPointerEvent @@ -39,7 +39,7 @@ fun SettingsItemUI(title: String, val current = LocalKoinApplication.current val copywriter = current.koin.get() var hover by remember { mutableStateOf(false) } - val backgroundColor = if (hover) Color(0xFFE8F5FF) else Color.White + val backgroundColor = if (hover) MaterialTheme.colors.secondaryVariant else MaterialTheme.colors.background var openSettings by remember { mutableStateOf(false) } @@ -80,10 +80,10 @@ fun SettingsItemUI(title: String, .size(15.dp), imageVector = languageArrow, contentDescription = null, - tint = Color.Gray - ) - Text( - text = copywriter.getText(title), + tint = MaterialTheme.colors.onBackground + ) + Text(text = copywriter.getText(title), + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light) diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsUI.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsUI.kt index 3b69ca44f..87f3bcd10 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsUI.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/SettingsUI.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme import androidx.compose.material.Switch import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -95,6 +96,7 @@ fun SettingsContentUI(currentPage: MutableState) { Row(modifier = Modifier.fillMaxWidth().padding(25.dp, 5.dp, 0.dp, 5.dp), verticalAlignment = Alignment.CenterVertically) { Text(text = "${copywriter.getText("Language")}:", + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light)) @@ -113,8 +115,8 @@ fun SettingsContentUI(currentPage: MutableState) { languageSize = coordinates.size.toSize() }, verticalAlignment = Alignment.CenterVertically) { - Text( - text = copywriter.getText("CurrentLanguage"), + Text(text = copywriter.getText("CurrentLanguage"), + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light) @@ -125,7 +127,7 @@ fun SettingsContentUI(currentPage: MutableState) { .size(15.dp), imageVector = languageArrow, contentDescription = null, - tint = Color.Black + tint = MaterialTheme.colors.onBackground ) } @@ -151,7 +153,7 @@ fun SettingsContentUI(currentPage: MutableState) { .width(180.dp) .wrapContentHeight() .clip(RoundedCornerShape(5.dp)) - .background(Color.White) + .background(MaterialTheme.colors.surface) ) { val allLanguages = copywriter.getAllLanguages() allLanguages.forEachIndexed { _, language -> @@ -169,6 +171,7 @@ fun SettingsContentUI(currentPage: MutableState) { Row(modifier = Modifier.fillMaxWidth().padding(25.dp, 5.dp, 0.dp, 5.dp), verticalAlignment = Alignment.CenterVertically) { Text(text = "${copywriter.getText("Theme")}:", + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light)) @@ -187,6 +190,7 @@ fun SettingsContentUI(currentPage: MutableState) { ) Text(text = copywriter.getText("Boot_start_up"), + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light)) @@ -202,6 +206,7 @@ fun SettingsContentUI(currentPage: MutableState) { ) Text(text = copywriter.getText("AutomaticUpdate"), + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light)) @@ -211,8 +216,8 @@ fun SettingsContentUI(currentPage: MutableState) { SettingsItemUI("Network") { Row(modifier = Modifier.fillMaxWidth().padding(16.dp)) { - Text( - text = copywriter.getText("Network"), + Text(text = copywriter.getText("Network"), + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light) @@ -222,8 +227,8 @@ fun SettingsContentUI(currentPage: MutableState) { Spacer(modifier = Modifier.height(10.dp)) SettingsItemUI("Store") { Row(modifier = Modifier.fillMaxWidth().padding(16.dp)) { - Text( - text = copywriter.getText("Store"), + Text(text = copywriter.getText("Store"), + color = MaterialTheme.colors.onBackground, fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light) diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/TabsUI.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/TabsUI.kt index 61357be30..89b5bd470 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/TabsUI.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/TabsUI.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.shape.GenericShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme import androidx.compose.material.Tab import androidx.compose.material.TabRow import androidx.compose.material.Text @@ -95,7 +96,7 @@ fun TabUI(isSelect: Boolean, title: String, clickable: () -> Unit) { if (isSelect) { textStyle = TextStyle(fontWeight = FontWeight.Bold) - modifier = modifier.border(5.dp, Color(0xFF70b0f3), bottomBorderShape) + modifier = modifier.border(5.dp, MaterialTheme.colors.primary, bottomBorderShape) textUnit = 16.sp } else { textStyle = TextStyle(fontWeight = FontWeight.Normal) @@ -105,6 +106,7 @@ fun TabUI(isSelect: Boolean, title: String, clickable: () -> Unit) { Box(modifier = modifier) { Text( text = title, + color = MaterialTheme.colors.onBackground, fontSize = textUnit, style = textStyle, fontFamily = FontFamily.SansSerif, diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/ThemeSegmentedControl.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/ThemeSegmentedControl.kt index 8656038cb..623d95e6d 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/ThemeSegmentedControl.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/ThemeSegmentedControl.kt @@ -10,8 +10,6 @@ import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -27,17 +25,17 @@ import com.clipevery.i18n.GlobalCopywriter fun ThemeSegmentedControl() { val current = LocalKoinApplication.current val copywriter = current.koin.get() - val selectedOption = remember { mutableStateOf("System") } + val themeDetector = current.koin.get() Row(verticalAlignment = Alignment.CenterVertically) { // Light Button Button( modifier = Modifier.height(28.dp), - onClick = { selectedOption.value = "Light" }, + onClick = { themeDetector.setThemeConfig(isFollowSystem = false, isUserInDark = false) }, // Apply the shape only to the left side for the first button shape = RoundedCornerShape(topStart = 4.dp, bottomStart = 4.dp, topEnd = 0.dp, bottomEnd = 0.dp), // Change the background and content colors based on selection - colors = if (selectedOption.value == "Light") ButtonDefaults.buttonColors(backgroundColor = Color(0xff1672ff)) + colors = if (!themeDetector.isFollowSystem() && !themeDetector.isCurrentThemeDark()) ButtonDefaults.buttonColors(backgroundColor = Color(0xff1672ff)) else ButtonDefaults.buttonColors(backgroundColor = Color.White), border = BorderStroke(1.dp, Color(0xFFAFCBE1)), contentPadding = PaddingValues(horizontal = 8.dp, vertical = 0.dp), @@ -47,16 +45,16 @@ fun ThemeSegmentedControl() { fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light), - color = if (selectedOption.value == "Light") Color.White else Color.Black) + color = if (!themeDetector.isFollowSystem() && !themeDetector.isCurrentThemeDark()) Color.White else Color.Black) } // System Button Button( modifier = Modifier.height(28.dp).offset(x = (-1).dp), - onClick = { selectedOption.value = "System" }, + onClick = { themeDetector.setThemeConfig(isFollowSystem = true) }, // No shape for the middle button to keep it rectangular shape = RoundedCornerShape(0.dp), - colors = if (selectedOption.value == "System") ButtonDefaults.buttonColors(backgroundColor = Color(0xff1672ff)) + colors = if (themeDetector.isFollowSystem()) ButtonDefaults.buttonColors(backgroundColor = Color(0xff1672ff)) else ButtonDefaults.buttonColors(backgroundColor = Color.White), border = BorderStroke(1.dp, Color(0xFFAFCBE1)), contentPadding = PaddingValues(horizontal = 8.dp, vertical = 0.dp), @@ -66,16 +64,16 @@ fun ThemeSegmentedControl() { fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light), - color = if (selectedOption.value == "System") Color.White else Color.Black) + color = if (themeDetector.isFollowSystem()) Color.White else Color.Black) } // Dark Button Button( modifier = Modifier.height(28.dp).offset(x = (-2).dp), - onClick = { selectedOption.value = "Dark" }, + onClick = { themeDetector.setThemeConfig(isFollowSystem = false, isUserInDark = true) }, // Apply the shape only to the right side for the last button shape = RoundedCornerShape(topStart = 0.dp, bottomStart = 0.dp, topEnd = 4.dp, bottomEnd = 4.dp), - colors = if (selectedOption.value == "Dark") ButtonDefaults.buttonColors(backgroundColor = Color(0xff1672ff)) + colors = if (!themeDetector.isFollowSystem() && themeDetector.isCurrentThemeDark()) ButtonDefaults.buttonColors(backgroundColor = Color(0xff1672ff)) else ButtonDefaults.buttonColors(backgroundColor = Color.White), border = BorderStroke(1.dp, Color(0xFFAFCBE1)), contentPadding = PaddingValues(horizontal = 8.dp, vertical = 0.dp), @@ -85,7 +83,7 @@ fun ThemeSegmentedControl() { fontSize = 14.sp, fontFamily = FontFamily.SansSerif, style = TextStyle(fontWeight = FontWeight.Light), - color = if (selectedOption.value == "Dark") Color.White else Color.Black) + color = if (!themeDetector.isFollowSystem() && themeDetector.isCurrentThemeDark()) Color.White else Color.Black) } } } diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/WindowDecoration.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/WindowDecoration.kt index f8e54d4ec..2cac1d013 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/WindowDecoration.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/WindowDecoration.kt @@ -84,10 +84,10 @@ fun DecorationUI(currentPage: MutableState, title: String) { .clickable { currentPage.value = PageType.HOME }) { Icon(imageVector = arrowLeft(), contentDescription = null, - tint = Color(0xFF70b0f3)) + tint = Color(0xFF1672FF)) Text( text = copywriter.getText("Return"), - color = Color(0xFF70b0f3), + color = Color(0xFF1672FF), fontWeight = FontWeight.Light ) } diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/log/Logger.desktop.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/log/Logger.desktop.kt index 61eb436b1..a27439c00 100644 --- a/composeApp/src/desktopMain/kotlin/com/clipevery/log/Logger.desktop.kt +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/log/Logger.desktop.kt @@ -35,4 +35,7 @@ actual fun initLogger(logPath: String) { val rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger rootLogger.level = Level.DEBUG rootLogger.addAppender(rollingFileAppender) + + val jThemeLogger = context.getLogger("com.jthemedetecor") as ch.qos.logback.classic.Logger + jThemeLogger.level = Level.OFF } \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt index b469a7e6d..1b45aa906 100644 --- a/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt @@ -38,6 +38,8 @@ import com.clipevery.path.getPathProvider import com.clipevery.platform.currentPlatform import com.clipevery.presist.DesktopFilePersist import com.clipevery.presist.FilePersist +import com.clipevery.ui.DesktopThemeDetector +import com.clipevery.ui.ThemeDetector import com.clipevery.ui.getTrayMouseAdapter import com.clipevery.utils.DesktopQRCodeGenerator import com.clipevery.utils.QRCodeGenerator @@ -70,6 +72,7 @@ fun initKoinApplication(ioScope: CoroutineScope): KoinApplication { single { DesktopTransferableConsumer() } single { GlobalListener() } single { DriverFactory() } + single { DesktopThemeDetector(get()) } } return startKoin { modules(appModule) diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/ui/ClipeveryTheme.desktop.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/ui/ClipeveryTheme.desktop.kt new file mode 100644 index 000000000..ba33593fb --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/ui/ClipeveryTheme.desktop.kt @@ -0,0 +1,42 @@ +package com.clipevery.ui + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import com.clipevery.config.ConfigManager +import com.jthemedetecor.OsThemeDetector + +class DesktopThemeDetector(private val configManager: ConfigManager): ThemeDetector { + + private val detector = OsThemeDetector.getDetector() + + private var _isFollowSystem: Boolean by mutableStateOf(configManager.config.isFollowSystem) + + private var _isSystemInDark: Boolean by mutableStateOf(detector.isDark) + + private var _isUserInDark: Boolean by mutableStateOf(configManager.config.isDark) + + init { + detector.registerListener { isDark: Boolean -> + _isSystemInDark = isDark + } + } + + override fun isSystemInDark(): Boolean { + return _isSystemInDark + } + + override fun isFollowSystem(): Boolean { + return _isFollowSystem + } + + override fun isUserInDark(): Boolean { + return _isUserInDark + } + + override fun setThemeConfig(isFollowSystem: Boolean, isUserInDark: Boolean) { + _isFollowSystem = isFollowSystem + _isUserInDark = isUserInDark + configManager.updateConfig { it.copy(isFollowSystem = isFollowSystem, isDark = isUserInDark) } + } +} \ No newline at end of file From 4aa4106be295fa0046d163546c81a0071698c9a1 Mon Sep 17 00:00:00 2001 From: Yiqun Zhang Date: Fri, 1 Dec 2023 19:56:29 +0800 Subject: [PATCH 2/2] :sparkles: Support for switching themes --- .../src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt index 9e63b79af..650cef1d7 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/ClipeveryTheme.kt @@ -11,8 +11,7 @@ import com.clipevery.LocalKoinApplication private val LightColorPalette = lightColors( primary = Color(0xFF1672FF), primaryVariant = Color(0xFF247CFF), - secondary = Color(0xFFFF9DC0), - secondaryVariant = Color(0xFFFFACB5), + secondaryVariant = Color(0xFFE8F5FF), ) private val DarkColorPalette = darkColors(