Renovate / renovate (push) Successful in 54s
Release — F-Droid repo + Gitea/Codeberg release + Play / detect (push) Successful in 6s
Release — F-Droid repo + Gitea/Codeberg release + Play / release (push) Successful in 21m44s
Release — F-Droid repo + Gitea/Codeberg release + Play / play (push) Successful in 1m32s
Agendula 1.1.0. Merging this triggers the release pipeline (F-Droid, Codeberg, Play) and mints the v1.1.0 tag. - Tags, synced as CATEGORIES (#35) - Saved filters, also usable in the Tasks widget (#47) - Offline flavor without sync or network, published to Codeberg only (#39) - New Today, Up next, Lists and Week widgets; widgets can show several lists - Synced lists can be renamed and deleted - All-day tasks no longer land a day off west of UTC in smart lists and filters versionName 1.1.0 / versionCode 1010099. CHANGELOG has the 1.1.0 section, and What's New is written for en-US, en-GB, de-DE, pt-BR, plus new fr-FR and ar. After the tag lands, fdroiddata!49998 needs a 1.1.0 build entry with gradle: full. Closes #35, closes #39, closes #47 Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de> Reviewed-on: https://codeberg.org/jlmakiola/agendula/pulls/51
40 lines
1.7 KiB
Kotlin
40 lines
1.7 KiB
Kotlin
package de.jeanlucmakiola.agendula.domain
|
|
|
|
import kotlin.time.Instant
|
|
|
|
/** A due-date bucket a task list groups its rows under. */
|
|
enum class TaskSection { OVERDUE, TODAY, UPCOMING, NO_DATE, COMPLETED }
|
|
|
|
/** A non-empty run of tasks under one [TaskSection], already in display order. */
|
|
data class SectionedTasks(val section: TaskSection, val tasks: List<Task>)
|
|
|
|
/**
|
|
* Group already-sorted tasks into due-date sections (the standard task-app
|
|
* presentation). Pure + side-effect-free so it unit-tests with a fixed clock,
|
|
* mirroring [TaskFiltering] / [DayWindow]. Completed tasks always fall to the
|
|
* [TaskSection.COMPLETED] bucket regardless of their due date.
|
|
*
|
|
* [todayStart] is local midnight today and [todayEnd] local midnight tomorrow
|
|
* (compute with [DayWindow]). Only non-empty sections are returned, in the
|
|
* fixed order Overdue → Today → Upcoming → No date → Completed.
|
|
*/
|
|
object TaskSections {
|
|
|
|
fun of(tasks: List<Task>, todayStart: Instant, todayEnd: Instant): List<SectionedTasks> {
|
|
val bySection = tasks.groupBy { sectionOf(it, todayStart, todayEnd) }
|
|
return TaskSection.entries.mapNotNull { section ->
|
|
bySection[section]?.takeIf { it.isNotEmpty() }?.let { SectionedTasks(section, it) }
|
|
}
|
|
}
|
|
|
|
fun sectionOf(task: Task, todayStart: Instant, todayEnd: Instant): TaskSection {
|
|
if (task.isCompleted) return TaskSection.COMPLETED
|
|
return when (dueWindowOf(task, todayStart, todayEnd)) {
|
|
DueWindow.OVERDUE -> TaskSection.OVERDUE
|
|
DueWindow.TODAY -> TaskSection.TODAY
|
|
DueWindow.UPCOMING -> TaskSection.UPCOMING
|
|
DueWindow.NO_DATE -> TaskSection.NO_DATE
|
|
}
|
|
}
|
|
}
|