med-det-samme/app/src/main/java/no/naiv/meddetsamme/domain/ScheduleText.kt

75 lines
2.9 KiB
Kotlin
Raw Normal View History

package no.naiv.meddetsamme.domain
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.Locale
import no.naiv.meddetsamme.data.DoseTime
/**
* Human-readable schedule descriptions (Norwegian, 24h) for the doctor
* summary and the UI. Pure unit-tested like the engine, since a wrong
* description on a doctor's desk is a clinical communication error.
*/
object ScheduleText {
/** Mask bit order matches ScheduleEngine: bit 0 = Sunday. */
private val DAY_ABBREV = listOf("søn", "man", "tir", "ons", "tor", "fre", "lør")
// Locale-pinned to nb so month names don't come out English on a foreign locale.
private val dateFmt = DateTimeFormatter.ofPattern("d. MMM", Locale.forLanguageTag("nb"))
fun describe(doseTime: DoseTime): String =
"${"%02d:%02d".format(doseTime.minuteOfDay / 60, doseTime.minuteOfDay % 60)} " +
"${daysText(doseTime)}${cycleText(doseTime)}${windowText(doseTime)}"
/** " · syklus 21/28" when cyclic, else "". */
fun cycleText(doseTime: DoseTime): String {
val length = doseTime.cycleLengthDays
val active = doseTime.cycleActiveDays
return if (length > 0 && active in 1 until length) " · syklus $active/$length" else ""
}
/** " · 1.14. jun", " · f.o.m. 1. jun", " · t.o.m. 14. jun" for a validity window. */
fun windowText(doseTime: DoseTime): String {
val start = doseTime.startEpochDay?.let { LocalDate.ofEpochDay(it) }
val end = doseTime.endEpochDay?.let { LocalDate.ofEpochDay(it) }
return when {
start != null && end != null -> " · ${dateFmt.format(start)}${dateFmt.format(end)}"
start != null -> " · f.o.m. ${dateFmt.format(start)}"
end != null -> " · t.o.m. ${dateFmt.format(end)}"
else -> ""
}
}
fun daysText(doseTime: DoseTime): String {
if (doseTime.intervalDays > 1) {
return "(hver ${doseTime.intervalDays}. dag)"
}
return when (val mask = doseTime.daysOfWeekMask and 0x7F) {
0x7F -> "(daglig)"
0x3E -> "(manfre)"
0x41 -> "(lørsøn)"
0 -> "(aldri)"
else -> {
// Week listed Monday-first for humans, despite bit 0 = Sunday.
val days = (1..7).map { it % 7 }
.filter { mask and (1 shl it) != 0 }
.map { DAY_ABBREV[it] }
"(${days.joinToString(", ")})"
}
}
}
/** "1 dag", "3 dager" — norsk flertall. */
fun daysCount(days: Int): String = if (days == 1) "1 dag" else "$days dager"
/** "1 tablett", "2,5 ml" — norsk desimalkomma. */
fun amountText(amount: Double, unit: String): String {
val number = if (amount == amount.toLong().toDouble()) {
amount.toLong().toString()
} else {
amount.toString().replace('.', ',')
}
return "$number $unit"
}
}