package com.vgmlr.stave
import android.content.Context
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Typography
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.Color
import androidx.core.content.edit
import androidx.core.graphics.toColorInt
@Composable
fun StaveTheme(
themeManager: StaveThemeManager,
content: @Composable () -> Unit
) {
val colorScheme = darkColorScheme(
primary = Color(0xFF486860),
background = themeManager.backgroundColor.value,
onBackground = themeManager.textColor.value,
surface = themeManager.backgroundColor.value,
onSurface = themeManager.textColor.value
)
MaterialTheme(
colorScheme = colorScheme,
typography = Typography(),
content = content
)
}
class StaveThemeManager(private val context: Context) {
private val prefs = context.getSharedPreferences("stave_prefs", Context.MODE_PRIVATE)
var backgroundColor = mutableStateOf(Color(context.getColor(R.color.background_color)))
var textColor = mutableStateOf(Color(context.getColor(R.color.text_color)))
var accentColor = mutableStateOf(Color(context.getColor(R.color.accent_color)))
var fontSize = mutableFloatStateOf(15.5f)
var lineSpacing = mutableFloatStateOf(0.2f)
var isMonospace = mutableStateOf(false)
var isNewestFirst = mutableStateOf(true)
var hexBgColor = hexOf(context.getColor(R.color.background_color))
var hexTextColor = hexOf(context.getColor(R.color.text_color))
var hexAccentColor = hexOf(context.getColor(R.color.accent_color))
init {
refresh()
}
fun lineHeightSp(): Float = fontSize.floatValue * (LINE_HEIGHT + lineSpacing.floatValue)
fun rowGapDp(): Float = fontSize.floatValue * lineSpacing.floatValue
private fun getSafeString(key: String, default: String): String =
prefs.getString(key, default) ?: default
private fun formatHex(hex: String): String = if (hex.startsWith("#")) hex else "#$hex"
private fun formatNum(num: String): String = num.replace(Regex("[^0-9.]"), "")
fun saveTheme(
bg: String,
text: String,
accent: String,
mono: Boolean,
size: String,
newestFirst: Boolean
) {
prefs.edit {
putString("main_background", formatHex(bg))
putString("main_color", formatHex(text))
putString("accent_color", formatHex(accent))
putBoolean("is_monospace", mono)
putString("main_size", formatNum(size))
putBoolean("newest_first", newestFirst)
}
refresh()
}
fun refresh() {
val defaultBg = hexOf(context.getColor(R.color.background_color))
val defaultText = hexOf(context.getColor(R.color.text_color))
val defaultAccent = hexOf(context.getColor(R.color.accent_color))
hexBgColor = getSafeString("main_background", defaultBg)
hexTextColor = getSafeString("main_color", defaultText)
hexAccentColor = getSafeString("accent_color", defaultAccent)
backgroundColor.value = parse(hexBgColor, R.color.background_color)
textColor.value = parse(hexTextColor, R.color.text_color)
accentColor.value = parse(hexAccentColor, R.color.accent_color)
isMonospace.value = prefs.getBoolean("is_monospace", false)
isNewestFirst.value = prefs.getBoolean("newest_first", true)
fontSize.floatValue = getSafeString("main_size", "15.5").toFloatOrNull() ?: 15.5f
lineSpacing.floatValue = getSafeString("line_spacing", "0.2").toFloatOrNull() ?: 0.2f
}
private fun parse(hex: String, fallback: Int): Color =
try { Color(hex.toColorInt()) } catch (_: Exception) { Color(context.getColor(fallback)) }
private fun hexOf(argb: Int): String = "#%06X".format(0xFFFFFF and argb)
companion object {
const val LINE_HEIGHT = 1.35f
}
}