Skip to content

Commit

Permalink
主题跟随系统
Browse files Browse the repository at this point in the history
  • Loading branch information
tangshimin committed Sep 24, 2024
1 parent 461af8f commit 1214cf7
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 82 deletions.
5 changes: 3 additions & 2 deletions src/main/kotlin/state/AppState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class AppState {
var global: GlobalState = loadGlobalState()

/** Material 颜色 */
var colors by mutableStateOf(createColors(global.isDarkTheme, global.primaryColor,global.backgroundColor,global.onBackgroundColor))
var colors by mutableStateOf(createColors(global))

/** 视频播放窗口,使用 JFrame 的一个原因是 swingPanel 重组的时候会产生闪光,
* 相关 Issue: https://github.com/JetBrains/compose-jb/issues/1800,
Expand All @@ -51,7 +51,7 @@ class AppState {
var videoPlayerComponent = createMediaPlayerComponent()

/** 文件选择器,如果不提前加载反应会很慢 */
var futureFileChooser: FutureTask<JFileChooser> = initializeFileChooser(global.isDarkTheme)
var futureFileChooser: FutureTask<JFileChooser> = initializeFileChooser(global.isDarkTheme,global.isFollowSystemTheme)

/** 困难词库 */
var hardVocabulary = loadMutableVocabularyByName("HardVocabulary")
Expand Down Expand Up @@ -142,6 +142,7 @@ class AppState {
val globalData = GlobalData(
global.type,
global.isDarkTheme,
global.isFollowSystemTheme,
global.audioVolume,
global.videoVolume,
global.keystrokeVolume,
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/state/GlobalState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import kotlinx.serialization.Serializable
data class GlobalData(
val type: ScreenType = ScreenType.WORD,
val isDarkTheme: Boolean = true,
val isFollowSystemTheme: Boolean = false,
val audioVolume: Float = 0.8F,
val videoVolume: Float = 80F,
val keystrokeVolume: Float = 0.75F,
Expand Down Expand Up @@ -53,6 +54,11 @@ class GlobalState(globalData: GlobalData) {
*/
var isDarkTheme by mutableStateOf(globalData.isDarkTheme)

/**
* 是否跟随系统主题
*/
var isFollowSystemTheme by mutableStateOf(globalData.isFollowSystemTheme)

/**
* 单词发音的音量
*/
Expand Down
81 changes: 80 additions & 1 deletion src/main/kotlin/theme/colors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@ import androidx.compose.material.Colors
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.ui.graphics.Color
import org.slf4j.LoggerFactory
import state.GlobalState


val IDEADarkThemeOnBackground = Color(133, 144, 151)

fun createColors(
isDarkTheme: Boolean,
isFollowSystemTheme:Boolean = true,
primary: Color,
background:Color,
onBackground:Color
): Colors {
return if (isDarkTheme) {
val isDark = if (isFollowSystemTheme) {
isSystemDarkMode()
} else isDarkTheme

return if (isDark) {
darkColors(
primary = primary,
onBackground = IDEADarkThemeOnBackground
Expand All @@ -28,10 +36,81 @@ fun createColors(
}
}


fun createColors(
global: GlobalState
): Colors {
val isDark = if (global.isFollowSystemTheme) {
isSystemDarkMode()
} else global.isDarkTheme

return if (isDark) {
darkColors(
primary = global.primaryColor,
onBackground = IDEADarkThemeOnBackground
)
} else {
lightColors(
primary = global.primaryColor,
background = global.backgroundColor,
surface = global.backgroundColor,
onBackground = global.onBackgroundColor
)
}
}

fun java.awt.Color.toCompose(): Color {
return Color(red, green, blue)
}

fun Color.toAwt(): java.awt.Color {
return java.awt.Color(red, green, blue)
}

fun isSystemDarkMode(): Boolean {
val logger = LoggerFactory.getLogger("isSystemDarkMode")
return when {
System.getProperty("os.name").contains("Mac", ignoreCase = true) -> {
val command = arrayOf("/usr/bin/defaults", "read", "-g", "AppleInterfaceStyle")
try {
val process = Runtime.getRuntime().exec(command)
process.inputStream.bufferedReader().use { it.readText().trim() == "Dark" }
} catch (e: Exception) {
logError(e, logger)
false
}
}
System.getProperty("os.name").contains("Windows", ignoreCase = true) -> {
val command = "reg query HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize /v AppsUseLightTheme"
try {
val process = Runtime.getRuntime().exec(command)
process.inputStream.bufferedReader().use { reader ->
val output = reader.readText()
!output.contains("0x1")
}
} catch (e: Exception) {
logError(e, logger)
false
}
}
System.getProperty("os.name").contains("Linux", ignoreCase = true) -> {
// 还没有在Linux上测试
val command = arrayOf("gsettings", "get", "org.gnome.desktop.interface", "gtk-theme")
try {
val process = Runtime.getRuntime().exec(command)
process.inputStream.bufferedReader().use { reader ->
val output = reader.readText().trim()
output.contains("dark", ignoreCase = true)
}
} catch (e: Exception) {
logError(e, logger)
false
}
}
else -> false
}
}

fun logError(e: Exception, logger: org.slf4j.Logger) {
logger.error("Error StackTrace: ${e.stackTraceToString()}\n")
}
16 changes: 13 additions & 3 deletions src/main/kotlin/ui/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,12 @@ fun App(
vocabularyPath = chosenPath,
isDarkTheme = appState.global.isDarkTheme,
updateFlatLaf = {
updateFlatLaf(appState.global.isDarkTheme,appState.global.backgroundColor.toAwt(),appState.global.onBackgroundColor.toAwt())
updateFlatLaf(
darkTheme = appState.global.isDarkTheme,
isFollowSystemTheme = appState.global.isFollowSystemTheme,
background = appState.global.backgroundColor.toAwt(),
onBackground = appState.global.onBackgroundColor.toAwt()
)
}
)
}else{
Expand All @@ -318,8 +323,13 @@ fun App(
}

// 改变主题后,更新菜单栏、标题栏的样式
LaunchedEffect(appState.global.isDarkTheme){
updateFlatLaf(appState.global.isDarkTheme,appState.global.backgroundColor.toAwt(),appState.global.onBackgroundColor.toAwt())
LaunchedEffect(appState.global.isDarkTheme,appState.global.isFollowSystemTheme){
updateFlatLaf(
darkTheme = appState.global.isDarkTheme,
isFollowSystemTheme = appState.global.isFollowSystemTheme,
background = appState.global.backgroundColor.toAwt(),
onBackground = appState.global.onBackgroundColor.toAwt()
)
appState.futureFileChooser = setupFileChooser()
}
}
Expand Down
Loading

0 comments on commit 1214cf7

Please sign in to comment.