Files
psu-schedule/android/app/src/main/kotlin/ritm/schedule/data/Notes.kt
Zakhar Timoshenko 29df0aa61f feat: add tasks and notes management for lessons
- Introduced a new feature for managing tasks and notes associated with lessons.
- Added a `NotesStore` class to handle local storage of notes in JSON format.
- Implemented UI components for displaying, adding, editing, and deleting notes.
- Enhanced the `HomeScreen`, `ScheduleScreen`, and `SubjectsScreen` to integrate notes functionality.
- Updated the API to handle versioning and added error handling for outdated endpoints.
- Improved the overall user experience with visual indicators for tasks and notes in the schedule.
2026-10-17 13:35:49 +03:00

60 lines
2.0 KiB
Kotlin

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<List<Note>> = _notes
private fun read(): List<Note> =
runCatching { json.decodeFromString<List<Note>>(file.readText()) }.getOrDefault(emptyList())
private suspend fun change(block: (List<Note>) -> List<Note>) = 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 } }
}