From cc4b0a1ecfbb97d5ba95e86ea2fa23ec81c63f57 Mon Sep 17 00:00:00 2001 From: Rene Luria Date: Wed, 8 Jul 2026 18:12:19 +0200 Subject: [PATCH] fix: chunk large cached events to avoid Preferences 8KB limit on desktop java.util.prefs.Preferences (desktop Settings backend) has an 8KB per-value limit. Schedule JSON exceeds this. Now splits into 8000-char chunks stored as cached_events_chunk__, with a count key. Maintains backward compat with old single-value format. --- .../ch/parano/myice/cache/ScheduleCache.kt | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/cache/ScheduleCache.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/cache/ScheduleCache.kt index f839dba..53ae9d5 100644 --- a/composeApp/src/commonMain/kotlin/ch/parano/myice/cache/ScheduleCache.kt +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/cache/ScheduleCache.kt @@ -9,10 +9,16 @@ import kotlinx.serialization.json.Json class ScheduleCache(private val settings: Settings) { + companion object { + private const val CHUNK_SIZE = 8000 + } + private val json = Json { ignoreUnknownKeys = true } private val eventListSerializer = ListSerializer(Event.serializer()) private fun eventsKey(account: String) = "cached_events_$account" + private fun eventsChunkCountKey(account: String) = "cached_events_count_$account" + private fun eventsChunkKey(account: String, index: Int) = "cached_events_chunk_${account}_$index" private fun agegroupKey(account: String) = "filters_agegroup_$account" private fun subgroupKey(account: String) = "filters_subgroup_$account" private fun typeFilterKey(account: String) = "filters_typefilter_$account" @@ -20,11 +26,31 @@ class ScheduleCache(private val settings: Settings) { @OptIn(ExperimentalTime::class) fun saveEvents(account: String, events: List) { - settings.putString(eventsKey(account), json.encodeToString(eventListSerializer, events)) + val jsonStr = json.encodeToString(eventListSerializer, events) + val chunks = jsonStr.chunked(CHUNK_SIZE) + + settings.remove(eventsKey(account)) + settings.putInt(eventsChunkCountKey(account), chunks.size) + chunks.forEachIndexed { i, chunk -> + settings.putString(eventsChunkKey(account, i), chunk) + } settings.putLong(timestampKey(account), Clock.System.now().toEpochMilliseconds()) } fun loadEvents(account: String): List? { + val chunkCount = settings.getIntOrNull(eventsChunkCountKey(account)) + if (chunkCount != null && chunkCount > 0) { + val jsonStr = (0 until chunkCount).mapNotNull { i -> + settings.getStringOrNull(eventsChunkKey(account, i)) + }.joinToString("") + if (jsonStr.isEmpty()) return null + return try { + json.decodeFromString(eventListSerializer, jsonStr) + } catch (e: Exception) { + null + } + } + val jsonString = settings.getStringOrNull(eventsKey(account)) ?: return null return try { json.decodeFromString(eventListSerializer, jsonString) @@ -58,6 +84,11 @@ class ScheduleCache(private val settings: Settings) { } fun clearCache(account: String) { + val chunkCount = settings.getIntOrNull(eventsChunkCountKey(account)) ?: 0 + for (i in 0 until chunkCount) { + settings.remove(eventsChunkKey(account, i)) + } + settings.remove(eventsChunkCountKey(account)) settings.remove(eventsKey(account)) settings.remove(timestampKey(account)) settings.remove(agegroupKey(account))