11import androidx.compose.runtime.Immutable
2+ import com.akuleshov7.ktoml.Toml
3+ import com.akuleshov7.ktoml.TomlInputConfig
4+ import com.akuleshov7.ktoml.annotations.TomlMultiline
25import io.github.oshai.kotlinlogging.KotlinLogging
36import io.github.xn32.json5k.Json5
47import io.github.xn32.json5k.SerialComment
@@ -13,12 +16,18 @@ import kotlinx.coroutines.flow.launchIn
1316import kotlinx.coroutines.flow.onEach
1417import kotlinx.coroutines.flow.sample
1518import kotlinx.coroutines.plus
19+ import kotlinx.serialization.ExperimentalSerializationApi
20+ import kotlinx.serialization.SerialName
1621import kotlinx.serialization.Serializable
22+ import kotlinx.serialization.json.Json
23+ import kotlinx.serialization.json.JsonNames
1724import nestdrop.deck.Deck
1825import nestdrop.deck.applyConfig
1926import nestdrop.deck.configFlow
2027import utils.LOOM
2128import tags.PresetPlaylist
29+ import tags.Term
30+ import tags.TermDouble
2231import ui.screens.customSearches
2332import utils.prettyPrint
2433import kotlin.time.Duration.Companion.seconds
@@ -47,8 +56,23 @@ data class Config(
4756 val deck4 : DeckConfig = DeckConfig (
4857 triggerTime = 0.25f + 0.125f
4958 ),
50- val presetPlaylists : List <PresetPlaylist > = emptyList()
51- )
59+ @TomlMultiline
60+ @SerialName(" presetPlaylists" )
61+ @Deprecated(" to be removed" ) val presetPlaylistsOld : List <PresetPlaylistDouble > = emptyList(),
62+ val playlists : Map <String , List <Term >> = emptyMap()
63+ ) {
64+ val presetPlaylists by lazy {
65+ playlists.entries.map {
66+ PresetPlaylist (it.key, it.value)
67+ }
68+ }
69+
70+ @Serializable
71+ data class PresetPlaylistDouble (
72+ val label : String ,
73+ val terms : List <TermDouble >
74+ )
75+ }
5276
5377@Immutable
5478@Serializable
@@ -72,10 +96,13 @@ data class DeckConfig(
7296) {
7397 @Immutable
7498 @Serializable
75- data class SearchConfig (
99+ data class SearchConfig @OptIn( ExperimentalSerializationApi :: class ) constructor (
76100 val autoChange : Boolean = false ,
77- val name : String? = null ,
101+ @JsonNames(" name" , " label" )
102+ val label : String? = null ,
103+ // val enabledFragments: Set<String> = emptySet(),
78104 )
105+
79106 @Immutable
80107 @Serializable
81108 data class PresetQueue (
@@ -118,6 +145,7 @@ data class DeckConfig(
118145 val autoChange : Boolean = false ,
119146 val index : Int = -1 ,
120147 val name : String? = null ,
148+ @TomlMultiline
121149 val toggles : Set <String > = emptySet(),
122150 )
123151
@@ -142,15 +170,28 @@ data class DeckConfig(
142170 val autoChange : Boolean = false ,
143171 val blendMode : Boolean = false ,
144172 val index : Int = -1 ,
173+ @TomlMultiline
145174 val toggles : Set <Int > = emptySet(),
146175 )
147176}
148177
149178val config = MutableStateFlow (Config ())
150179
151- // val json = Json {
180+ private val json = Json {
181+ allowComments = true
182+ prettyPrint = true
183+ allowTrailingComma = true
184+ encodeDefaults = true
185+ useAlternativeNames = true
186+ isLenient = true
187+ // this.explicitNulls = false
152188// namingStrategy = JsonNamingStrategy.SnakeCase
153- // }
189+ }
190+ val toml = Toml (
191+ inputConfig = TomlInputConfig (
192+ allowEmptyToml = false
193+ )
194+ )
154195val json5 = Json5 {
155196 prettyPrint = true
156197 encodeDefaults = true
@@ -175,16 +216,36 @@ suspend fun Deck.updateConfig(deckConfig: DeckConfig) {
175216@OptIn(FlowPreview ::class )
176217suspend fun loadConfig () {
177218 logger.info { " load config" }
178- if (configFile.exists()) {
219+ val newConfigValue = if (configFile.exists()) {
179220 logger.info { " loading: $configFile " }
180221// configFile.readText()
181- config.value = json5 .decodeFromString(
222+ json .decodeFromString(
182223 Config .serializer(),
183224 configFile.readText(),
184225 )
226+ } else if (configFileJson5.exists()) {
227+ logger.info { " loading: $configFileJson5 " }
228+ // configFile.readText()
229+ json.decodeFromString(
230+ Config .serializer(),
231+ configFileJson5.readText(),
232+ )
185233 } else {
234+ logger.info { " does not exist: $configFile $configFileJson5 " }
235+ null
236+ }
186237
187- logger.info { " does not exist: $configFile " }
238+ if (newConfigValue != null ) {
239+ config.value = newConfigValue.let { c ->
240+ if (c.playlists.isEmpty()) {
241+ c.copy(
242+ playlists = c.presetPlaylistsOld.associate { it.label to it.terms.map { it.toTerm() } },
243+ presetPlaylistsOld = emptyList()
244+ )
245+ } else {
246+ c
247+ }
248+ }
188249 }
189250
190251 config
@@ -229,14 +290,17 @@ suspend fun loadConfig() {
229290
230291 customSearches.onEach { searches ->
231292 updateConfig {
232- copy(presetPlaylists = searches)
293+ copy(playlists = searches.associate { it.label to it.terms } )
233294 }
234295 }.launchIn(configScope)
235296}
236297
237298fun saveConfig (config : Config ) {
238299 configFile.parentFile.mkdirs()
239300 configFile.writeText(
240- json5.encodeToString(Config .serializer(), config)
301+ json.encodeToString(Config .serializer(), config)
302+ )
303+ configFileToml.writeText(
304+ toml.encodeToString(Config .serializer(), config)
241305 )
242306}
0 commit comments