Initial commit

This commit is contained in:
weishaupt
2026-09-01 12:32:15 -04:00
commit defdefdb28
33 changed files with 3540 additions and 0 deletions
@@ -0,0 +1,103 @@
package data
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import org.json.JSONObject
import java.io.File
import java.util.concurrent.ConcurrentHashMap
data class WindowDisplaySettings(
val backgroundAlpha: Float = 0.85f, // 0f = fully transparent, 1f = fully opaque
val textColorMircIndex: Int = 0, // index into the standard mIRC palette; 0 = white
val fontSize: Float = 14f,
val showUserList: Boolean = true,
val mentionHighlightColorArgb: Int = 0x40FFA500.toInt(), // translucent orange
val nickColorsEnabled: Boolean = true,
val showImagePreviews: Boolean = false // opt-in: auto-loading images reveals your IP to the host
)
/**
* Desktop equivalent of the Android DataStore-backed repository. Settings for every
* buffer are kept as one JSON file (rootDir/window_prefs.json), keyed by buffer storage
* id, loaded once at startup and rewritten on every change. Each buffer's settings are
* exposed as a StateFlow so every open window for that buffer updates live, same as
* DataStore's Flow did on Android.
*/
class WindowPrefsRepository(rootDir: File) {
private val file = File(rootDir, "window_prefs.json")
private val lock = Any()
private val flows = ConcurrentHashMap<String, MutableStateFlow<WindowDisplaySettings>>()
private var stored: MutableMap<String, WindowDisplaySettings> = loadAll()
fun settingsFor(bufferKeyId: String): StateFlow<WindowDisplaySettings> = flowFor(bufferKeyId).asStateFlow()
fun setAlpha(bufferKeyId: String, alpha: Float) = update(bufferKeyId) { it.copy(backgroundAlpha = alpha) }
fun setTextColorMircIndex(bufferKeyId: String, index: Int) = update(bufferKeyId) { it.copy(textColorMircIndex = index) }
fun setFontSize(bufferKeyId: String, fontSize: Float) = update(bufferKeyId) { it.copy(fontSize = fontSize) }
fun setShowUserList(bufferKeyId: String, show: Boolean) = update(bufferKeyId) { it.copy(showUserList = show) }
fun setMentionHighlightColor(bufferKeyId: String, colorArgb: Int) = update(bufferKeyId) { it.copy(mentionHighlightColorArgb = colorArgb) }
fun setNickColorsEnabled(bufferKeyId: String, enabled: Boolean) = update(bufferKeyId) { it.copy(nickColorsEnabled = enabled) }
fun setShowImagePreviews(bufferKeyId: String, show: Boolean) = update(bufferKeyId) { it.copy(showImagePreviews = show) }
private fun flowFor(bufferKeyId: String): MutableStateFlow<WindowDisplaySettings> =
flows.getOrPut(bufferKeyId) { MutableStateFlow(stored[bufferKeyId] ?: WindowDisplaySettings()) }
private fun update(bufferKeyId: String, transform: (WindowDisplaySettings) -> WindowDisplaySettings) {
synchronized(lock) {
val updated = transform(stored[bufferKeyId] ?: WindowDisplaySettings())
stored[bufferKeyId] = updated
flowFor(bufferKeyId).value = updated
persist()
}
}
private fun loadAll(): MutableMap<String, WindowDisplaySettings> {
if (!file.exists()) return mutableMapOf()
return try {
val obj = JSONObject(file.readText())
val result = mutableMapOf<String, WindowDisplaySettings>()
obj.keys().forEach { key ->
val o = obj.getJSONObject(key)
result[key] = WindowDisplaySettings(
backgroundAlpha = o.optDouble("backgroundAlpha", 0.85).toFloat(),
textColorMircIndex = o.optInt("textColorMircIndex", 0),
fontSize = o.optDouble("fontSize", 14.0).toFloat(),
showUserList = o.optBoolean("showUserList", true),
mentionHighlightColorArgb = o.optLong("mentionHighlightColorArgb", 0x40FFA500L).toInt(),
nickColorsEnabled = o.optBoolean("nickColorsEnabled", true),
showImagePreviews = o.optBoolean("showImagePreviews", false)
)
}
result
} catch (e: Exception) {
mutableMapOf()
}
}
private fun persist() {
val obj = JSONObject()
stored.forEach { (key, settings) ->
obj.put(key, JSONObject().apply {
put("backgroundAlpha", settings.backgroundAlpha)
put("textColorMircIndex", settings.textColorMircIndex)
put("fontSize", settings.fontSize)
put("showUserList", settings.showUserList)
put("mentionHighlightColorArgb", settings.mentionHighlightColorArgb)
put("nickColorsEnabled", settings.nickColorsEnabled)
put("showImagePreviews", settings.showImagePreviews)
})
}
file.parentFile?.mkdirs()
file.writeText(obj.toString())
}
}
fun BufferKey.storageId(): String = "${serverId}__${name}"