package ritm.schedule.data import android.content.Context import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import kotlinx.serialization.Serializable import java.io.File import java.util.UUID /** * A homework task or a plain note the student pinned to one lesson: the subject, * the lesson's date and start time. Tasks can be ticked off; notes just remind. */ @Serializable data class Note( val id: String = UUID.randomUUID().toString(), /** "docId|group": notes of one group never show up in another. */ val group: String, val subject: String, val date: String, val start: String, val text: String, val task: Boolean = true, val done: Boolean = false, val created: Long = System.currentTimeMillis(), ) fun groupKey(g: SavedGroup) = "${g.docId}|${g.group}" /** Notes live only on the device, in one small JSON file. */ class NotesStore(context: Context) { private val file = File(context.filesDir, "notes.json") private val lock = Mutex() private val _notes = MutableStateFlow(read()) val notes: StateFlow> = _notes private fun read(): List = runCatching { json.decodeFromString>(file.readText()) }.getOrDefault(emptyList()) private suspend fun change(block: (List) -> List) = withContext(Dispatchers.IO) { lock.withLock { val next = block(_notes.value) file.writeText(json.encodeToString(next)) _notes.value = next } } suspend fun save(note: Note) = change { list -> if (list.any { it.id == note.id }) list.map { if (it.id == note.id) note else it } else list + note } suspend fun delete(id: String) = change { list -> list.filterNot { it.id == id } } suspend fun toggle(id: String) = change { list -> list.map { if (it.id == id) it.copy(done = !it.done) else it } } }