Tidy IcsParser day arithmetic, index scans and wire lookups
This commit is contained in:
1 parent
9b04b2a419
commit
ee5b25e54f
2 files changed
+18
-46
No files matched your search
@@ -65,13 +65,8 @@ fun parseSimpleRecurrence(
|
||||
return null
|
||||
}
|
||||
|
||||
val freq = when (parts["FREQ"]?.uppercase()) {
|
||||
"DAILY" -> RecurrenceFreq.Daily
|
||||
"WEEKLY" -> RecurrenceFreq.Weekly
|
||||
"MONTHLY" -> RecurrenceFreq.Monthly
|
||||
"YEARLY" -> RecurrenceFreq.Yearly
|
||||
else -> return null
|
||||
}
|
||||
val freq = RecurrenceFreq.entries.firstOrNull { it.name.equals(parts["FREQ"], ignoreCase = true) }
|
||||
?: return null
|
||||
val interval = parts["INTERVAL"]?.let { it.toIntOrNull()?.takeIf { n -> n >= 1 } ?: return null } ?: 1
|
||||
|
||||
// BYDAY is simple only as plain weekday picks on a weekly rule; ordinal
|
||||
|
||||
@@ -9,10 +9,10 @@ import kotlinx.datetime.atStartOfDayIn
|
||||
import kotlinx.datetime.toInstant
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import kotlin.math.ceil
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Instant
|
||||
|
||||
/** Milliseconds in a calendar day; all-day times are UTC midnights, so this is exact. */
|
||||
private const val DAY_MILLIS = 86_400_000L
|
||||
private const val MINUTES_PER_DAY = 1_440
|
||||
|
||||
/**
|
||||
@@ -316,13 +316,9 @@ class IcsParser(private val deviceZone: TimeZone = TimeZone.currentSystemDefault
|
||||
dtEnd: IcsDateTime?,
|
||||
duration: String?,
|
||||
): Instant {
|
||||
val explicit = dtEnd?.instant ?: duration?.let {
|
||||
Instant.fromEpochMilliseconds(
|
||||
start.instant.toEpochMilliseconds() + parseRfc2445DurationMillis(it),
|
||||
)
|
||||
}
|
||||
val explicit = dtEnd?.instant ?: duration?.let { start.instant + parseRfc2445DurationMillis(it).milliseconds }
|
||||
if (!start.isAllDay) return explicit ?: start.instant
|
||||
return explicit?.takeIf { it > start.instant } ?: start.instant.plusDays(1)
|
||||
return explicit?.takeIf { it > start.instant } ?: (start.instant + 1.days)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -419,9 +415,6 @@ class IcsParser(private val deviceZone: TimeZone = TimeZone.currentSystemDefault
|
||||
fun IcsContentLine.isBegin(component: String) =
|
||||
name == "BEGIN" && value.trim().equals(component, true)
|
||||
|
||||
fun Instant.plusDays(days: Int): Instant =
|
||||
Instant.fromEpochMilliseconds(toEpochMilliseconds() + days * DAY_MILLIS)
|
||||
|
||||
/**
|
||||
* A single-valued `CATEGORIES`, which is what the Fossify family writes
|
||||
* for the source calendar's name. A multi-item list is a tag list and
|
||||
@@ -440,42 +433,26 @@ class IcsParser(private val deviceZone: TimeZone = TimeZone.currentSystemDefault
|
||||
.takeIf { it.isNotEmpty() && !it.equals("null", true) }
|
||||
}
|
||||
|
||||
/** Index of the matching `END:<component>` at/after [from], or list end. */
|
||||
/**
|
||||
* Where an unterminated component's body has to stop: the next top-level
|
||||
* `VEVENT` / `VTODO` in `[from, end)`, or [end] when there is none. A
|
||||
* nested `VALARM` is part of the body and is not a boundary.
|
||||
*/
|
||||
fun indexOfNextComponent(lines: List<String>, from: Int, end: Int): Int {
|
||||
var i = from
|
||||
while (i < end) {
|
||||
fun indexOfNextComponent(lines: List<String>, from: Int, end: Int): Int =
|
||||
(from until end).firstOrNull { i ->
|
||||
val line = parseContentLine(lines[i])
|
||||
if (line != null && (line.isBegin("VEVENT") || line.isBegin("VTODO"))) {
|
||||
return i
|
||||
}
|
||||
i++
|
||||
}
|
||||
return end
|
||||
}
|
||||
line != null && (line.isBegin("VEVENT") || line.isBegin("VTODO"))
|
||||
} ?: end
|
||||
|
||||
fun indexOfEnd(lines: List<String>, from: Int, component: String): Int {
|
||||
var i = from
|
||||
while (i < lines.size) {
|
||||
/** Index of the matching `END:<component>` at/after [from], or list end. */
|
||||
fun indexOfEnd(lines: List<String>, from: Int, component: String): Int =
|
||||
(from until lines.size).firstOrNull { i ->
|
||||
val line = parseContentLine(lines[i])
|
||||
if (line != null && line.name == "END" &&
|
||||
line.value.trim().equals(component, true)
|
||||
) {
|
||||
return i
|
||||
}
|
||||
i++
|
||||
}
|
||||
return lines.size
|
||||
}
|
||||
line != null && line.name == "END" && line.value.trim().equals(component, true)
|
||||
} ?: lines.size
|
||||
|
||||
fun mapIcsStatus(value: String): EventStatus = when (value.trim().uppercase()) {
|
||||
"TENTATIVE" -> EventStatus.Tentative
|
||||
"CANCELLED" -> EventStatus.Cancelled
|
||||
else -> EventStatus.Confirmed
|
||||
}
|
||||
fun mapIcsStatus(value: String): EventStatus =
|
||||
EventStatus.entries.firstOrNull { it.name.equals(value.trim(), ignoreCase = true) }
|
||||
?: EventStatus.Confirmed
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user