Skip to content

Commit

Permalink
refactor: apply custom yaml config parser to Theme
Browse files Browse the repository at this point in the history
  • Loading branch information
WhiredPlanck committed Mar 15, 2024
1 parent 0cb8802 commit 51ec079
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 187 deletions.
43 changes: 20 additions & 23 deletions app/src/main/java/com/osfans/trime/data/theme/ColorManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import com.osfans.trime.util.isNightMode
import splitties.dimensions.dp
import timber.log.Timber
import java.io.File
import java.lang.IllegalArgumentException

object ColorManager {
private val theme get() = ThemeManager.activeTheme
Expand Down Expand Up @@ -71,11 +70,10 @@ object ColorManager {
private val currentColors: MutableMap<String, Any> = hashMapOf()

/** 获取当前主题所有配色 */
fun getPresetColorSchemes(): List<Pair<String, String>> {
return theme.presetColorSchemes.map { (key, value) ->
Pair(key, value!!["name"] as String)
}
}
val presetColorSchemes get() =
theme.presetColorSchemes?.entries?.associate { (k, v) ->
k to v!!.configMap.entries.associate { (s, n) -> s to n!!.configValue.getString() }
} ?: mapOf()

fun interface OnColorChangeListener {
fun onColorChange()
Expand Down Expand Up @@ -112,15 +110,14 @@ object ColorManager {
lastDarkColorSchemeId = null
lastLightColorSchemeId = null

var colorScheme = prefs.selectedColor
if (!theme.presetColorSchemes.containsKey(colorScheme)) colorScheme = theme.style.getString("color_scheme") // 主題中指定的配色
if (!theme.presetColorSchemes.containsKey(colorScheme)) colorScheme = "default" // 主題中的default配色
// 配色表中没有这个 id
if (!theme.presetColorSchemes.containsKey(colorScheme)) {
Timber.e("Color scheme %s not found", colorScheme)
throw IllegalArgumentException("Color scheme $colorScheme not found!")
}
selectedColor = colorScheme
val selected = prefs.selectedColor
val fromStyle = theme.style.getString("color_scheme") // 主題中指定的配色
val default = "default" // 主題中的 default 配色

selectedColor = arrayOf(selected, fromStyle, default)
.firstOrNull { presetColorSchemes.containsKey(it) }
?: throw NoSuchElementException("No such color scheme found!")

switchNightMode(isNightMode)
}

Expand All @@ -129,7 +126,7 @@ object ColorManager {
* @param colorSchemeId 配色 id
* */
fun setColorScheme(colorSchemeId: String) {
if (!theme.presetColorSchemes.containsKey(colorSchemeId)) {
if (!presetColorSchemes.containsKey(colorSchemeId)) {
Timber.w("Color scheme %s not found", colorSchemeId)
return
}
Expand Down Expand Up @@ -169,7 +166,7 @@ object ColorManager {
* @return 切换深色/亮色模式后配色的 id
*/
private fun getColorSchemeId(): String? {
val colorMap = theme.presetColorSchemes[selectedColor] as Map<String, Any>
val colorMap = presetColorSchemes[selectedColor] as Map<String, Any>
if (isNightMode) {
if (colorMap.containsKey("dark_scheme")) {
return colorMap["dark_scheme"] as String?
Expand All @@ -190,16 +187,16 @@ object ColorManager {

private fun refreshColorValues() {
currentColors.clear()
val colorMap = theme.presetColorSchemes[selectedColor] as Map<String, Any>
colorMap.forEach { (key, value) ->
val colorMap = presetColorSchemes[selectedColor]
colorMap?.forEach { (key, value) ->
when (key) {
"name", "author", "light_scheme", "dark_scheme", "sound" -> {}
else -> currentColors[key] = value
}
}
theme.fallbackColors?.forEach { (key, value) ->
if (!currentColors.containsKey(key)) {
if (value != null) currentColors[key] = value
if (value != null) currentColors[key] = value.configValue.getString()
}
}
defaultFallbackColors.forEach { (key, value) ->
Expand Down Expand Up @@ -229,7 +226,7 @@ object ColorManager {
}

// sound
if (colorMap.containsKey("sound")) currentColors["sound"] = colorMap["sound"]!!
if (colorMap?.containsKey("sound") == true) currentColors["sound"] = colorMap["sound"]!!
}

/** 获取参数的真实value,如果是色彩返回int,如果是背景图返回drawable,都不是则进行 fallback
Expand Down Expand Up @@ -341,7 +338,7 @@ object ColorManager {
): Drawable? {
val value = getColorValue(key)
if (value is Drawable) {
if (alphaKey.isNotEmpty() && theme.style.getObject(alphaKey) != null) {
if (alphaKey.isNotEmpty() && theme.style.getString(alphaKey).isNotEmpty()) {
value.alpha = theme.style.getInt(alphaKey).coerceIn(0, 255)
}
return value
Expand All @@ -359,7 +356,7 @@ object ColorManager {
gradient.setStroke(border.toInt(), stroke)
}
}
if (alphaKey.isNotEmpty() && theme.style.getObject(alphaKey) != null) {
if (alphaKey.isNotEmpty() && theme.style.getString(alphaKey).isNotEmpty()) {
gradient.alpha = theme.style.getInt(alphaKey).coerceIn(0, 255)
}
return gradient
Expand Down
51 changes: 23 additions & 28 deletions app/src/main/java/com/osfans/trime/data/theme/FontManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import android.graphics.fonts.FontFamily
import android.os.Build
import androidx.annotation.RequiresApi
import com.osfans.trime.data.DataManager
import com.osfans.trime.util.config.ConfigList
import com.osfans.trime.util.config.ConfigValue
import timber.log.Timber
import java.io.File

Expand All @@ -19,7 +21,7 @@ object FontManager {

fun refresh() {
typefaceCache.clear()
fontFamiliyCache.clear()
fontFamilyCache.clear()
hanBFont = getTypefaceOrDefault("hanb_font")
latinFont = getTypefaceOrDefault("latin_font")
}
Expand Down Expand Up @@ -63,7 +65,14 @@ object FontManager {
}

private fun getTypefaceOrDefault(key: String): Typeface {
val fonts = ThemeManager.activeTheme.style.getObject(key)
val fonts =
ThemeManager.activeTheme.style.getItem(key).run {
return@run when (this) {
is ConfigValue -> listOf(getString())
is ConfigList -> this.mapNotNull { it?.configValue?.getString() }
else -> emptyList()
}
}

fun handler(fontName: String): Typeface? {
val fontFile = File(fontDir, fontName)
Expand All @@ -74,23 +83,15 @@ object FontManager {
return null
}

if (fonts is String) return handler(fonts) ?: Typeface.DEFAULT
if (fonts is List<*>) {
for (font in fonts as List<String>) {
handler(font).let {
if (it != null) return it
}
}
}
return Typeface.DEFAULT
return fonts.firstNotNullOfOrNull { handler(it) } ?: Typeface.DEFAULT
}

private val fontFamiliyCache = mutableMapOf<String, FontFamily>()
private val fontFamilyCache = mutableMapOf<String, FontFamily>()

@RequiresApi(Build.VERSION_CODES.Q)
private fun getFontFamily(fontName: String): FontFamily? {
if (fontFamiliyCache.containsKey(fontName)) {
return fontFamiliyCache[fontName]!!
if (fontFamilyCache.containsKey(fontName)) {
return fontFamilyCache[fontName]!!
}
val fontFile = File(fontDir, fontName)
if (fontFile.exists()) {
Expand All @@ -102,21 +103,15 @@ object FontManager {

@RequiresApi(Build.VERSION_CODES.Q)
private fun getFontFamilies(key: String): List<FontFamily> {
val fonts = ThemeManager.activeTheme.style.getObject(key)
val fontFamilies = mutableListOf<FontFamily>()

fun handler(fontName: String) {
getFontFamily(fontName)?.let {
fontFamilies.add(it)
val fonts =
ThemeManager.activeTheme.style.getItem(key).run {
return@run when (this) {
is ConfigValue -> listOf(getString())
is ConfigList -> this.mapNotNull { it?.configValue?.getString() }
else -> emptyList()
}
}
}

if (fonts is String) handler(fonts)
if (fonts is List<*>) {
for (font in fonts as List<String>) {
handler(font)
}
}
return fontFamilies
return fonts.mapNotNull { getFontFamily(it) }
}
}
143 changes: 59 additions & 84 deletions app/src/main/java/com/osfans/trime/data/theme/Theme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,121 +19,96 @@ package com.osfans.trime.data.theme

import com.osfans.trime.core.Rime
import com.osfans.trime.data.AppPrefs
import com.osfans.trime.util.CollectionUtils
import com.osfans.trime.util.config.Config
import com.osfans.trime.util.config.ConfigItem
import com.osfans.trime.util.config.ConfigList
import com.osfans.trime.util.config.ConfigMap
import timber.log.Timber
import kotlin.system.measureTimeMillis

/** 主题和样式配置 */
class Theme(var name: String) {
private var generalStyle: Map<String, Any?>? = null
private var presetKeyboards: Map<String, Any?>? = null
private var liquidKeyboard: Map<String, Any?>? = null
class Theme(name: String) {
val style: Style
val liquid: Liquid
val keyboards: Keyboards

var presetKeys: Map<String, Map<String, Any?>?>? = null
var presetKeys: ConfigMap? = null
private set
var fallbackColors: Map<String, String?>? = null
var fallbackColors: ConfigMap? = null
private set
lateinit var presetColorSchemes: Map<String, Map<String, Any>?>
var presetColorSchemes: ConfigMap? = null
private set
var allKeyboardIds: List<String> = listOf()
var presetKeyboards: ConfigMap? = null
private set

val style = Style(this)
val liquid = Liquid(this)
val keyboards = Keyboards(this)

companion object {
private val prefs = AppPrefs.defaultInstance().theme
private const val VERSION_KEY = "config_version"
private const val DEFAULT_THEME_NAME = "trime"
}

init {
if (name.isEmpty()) {
name = prefs.selectedTheme
private fun deploy(active: String): Config? {
val nameWithExtension = "$active.yaml"
val isDeployed: Boolean
measureTimeMillis {
isDeployed = Rime.deployRimeConfigFile(nameWithExtension, VERSION_KEY)
}.also {
if (isDeployed) {
Timber.i("Deployed theme file '$nameWithExtension' in $it ms")
} else {
Timber.w("Failed to deploy theme file '$nameWithExtension'")
}
}
return Config.create(active)
}
init(name)
}

fun init(active: String) {
Timber.i("Initializing theme, currentThemeName=%s ...", active)
val themeFileName = "$active.yaml"
Timber.i("Deploying theme '%s' ...", themeFileName)
var isDeployed: Boolean
measureTimeMillis {
isDeployed = Rime.deployRimeConfigFile(themeFileName, VERSION_KEY)
}.also {
if (isDeployed) {
Timber.i("Deployed theme '%s' in %dms", themeFileName, it)
init {
Timber.i("Initializing current theme '$name'")
val config =
if (name != DEFAULT_THEME_NAME) {
deploy(name) ?: deploy(DEFAULT_THEME_NAME)
} else {
Timber.w("Failed to deploy theme: '%s'", themeFileName)
}
}

Timber.d("Fetching global theme config map ...")
val fullThemeConfigMap = Rime.getRimeConfigMap(themeFileName, "")
if (fullThemeConfigMap == null) {
if (active != DEFAULT_THEME_NAME) {
Timber.w("Failed to parse the theme: '%s', fallback to trime.yaml", active)
init(DEFAULT_THEME_NAME)
return
}
Timber.e("Failed to parse default theme: trime.yaml")
return
}
Timber.d("Fetching done")

generalStyle = fullThemeConfigMap["style"] as Map<String, Any?>?
fallbackColors = fullThemeConfigMap["fallback_colors"] as Map<String, String?>?
presetKeys = fullThemeConfigMap["preset_keys"] as Map<String, Map<String, Any?>?>?
presetColorSchemes = fullThemeConfigMap["preset_color_schemes"] as Map<String, Map<String, Any>?>
presetKeyboards = fullThemeConfigMap["preset_keyboards"] as Map<String, Any?>?
liquidKeyboard = fullThemeConfigMap["liquid_keyboard"] as Map<String, Any?>?
// 将 presetKeyboards 的所有 key 转为 allKeyboardIds
allKeyboardIds = presetKeyboards?.keys?.toList()!!
deploy(name)
} ?: Config()

style = Style(config)
liquid = Liquid(config)
keyboards = Keyboards(config)
fallbackColors = config.getMap("fallback_colors")
presetKeys = config.getMap("preset_keys")
presetColorSchemes = config.getMap("preset_color_schemes")
presetKeyboards = config.getMap("preset_keyboards")
Timber.i("The theme is initialized")
prefs.selectedTheme = active
prefs.selectedTheme = name
}

class Style(private val theme: Theme) {
fun getString(key: String): String {
return CollectionUtils.obtainString(theme.generalStyle, key, "")
}
class Style(private val config: Config) {
fun getString(key: String): String = config.getString("style/$key")

fun getInt(key: String): Int {
return CollectionUtils.obtainInt(theme.generalStyle, key, 0)
}
fun getInt(key: String): Int = config.getInt("style/$key")

fun getFloat(key: String): Float {
return CollectionUtils.obtainFloat(theme.generalStyle, key, 0f)
}
fun getFloat(key: String): Float = config.getFloat("style/$key")

fun getBoolean(key: String): Boolean {
return CollectionUtils.obtainBoolean(theme.generalStyle, key, false)
}
fun getBoolean(key: String): Boolean = config.getBool("style/$key")

fun getObject(key: String): Any? {
return CollectionUtils.obtainValue(theme.generalStyle, key)
}
fun getList(key: String): ConfigList? = config.getList("style/$key")

fun getMap(key: String): ConfigMap? = config.getMap("style/$key")

fun getItem(key: String): ConfigItem? = config.getItem("style/$key")
}

class Liquid(private val theme: Theme) {
fun getObject(key: String): Any? {
return CollectionUtils.obtainValue(theme.liquidKeyboard, key)
}
class Liquid(private val config: Config) {
fun getInt(key: String): Int = config.getInt("liquid_keyboard/$key")

fun getInt(key: String): Int {
return CollectionUtils.obtainInt(theme.liquidKeyboard, key, 0)
}
fun getFloat(key: String): Float = config.getFloat("liquid_keyboard/$key")

fun getFloat(key: String): Float {
return CollectionUtils.obtainFloat(theme.liquidKeyboard, key, theme.style.getFloat(key))
}
fun getList(key: String): ConfigList? = config.getList("liquid_keyboard/$key")

fun getMap(key: String): ConfigMap? = config.getMap("liquid_keyboard/$key")
}

class Keyboards(private val theme: Theme) {
fun getObject(key: String): Any? {
return CollectionUtils.obtainValue(theme.presetKeyboards, key)
}
class Keyboards(private val config: Config) {
fun getMap(key: String): ConfigMap? = config.getMap("preset_keyboards/$key")
}
}
Loading

0 comments on commit 51ec079

Please sign in to comment.