I'm writing an iOS WidgetKit widget and I'd like to display the time until a next event (preferably in real time) rounded to the nearest minute. There's 3 cases I'd like to show:
- "in T min" - when the time is in the future
- now - when the time is between 0-1 minutes in the future
- T min ago - when the time is in the past
I've tried a few options so far:
Text(Date, style: Text.DateStyle)
This works as I would hope when I use .timer - it displays the amount of time until given date, counting down, in real time. It doesn't cover the 'now' or 'T min ago' cases though. While I could do a case by case rendering for this, it won't automatically update as soon as a future date falls into the "now" case or "T min ago" case.
However, it seems to display the 2 most significant units of time - which means it will always display mm:ss or hh:mm time formats in my case - I just want to render "in T min" or 'now'. Code used:
@available(iOS 15, *)
public struct RealtimeCountdownView: View {
let dateToRender: Date
public var body: some View {
Text(dateToRender, style: .timer)
}
}
TimelineView
This option just doesn't work at all - the widget doesn't update in real time and only changes when it renders a new timeline entry. I assume this is because the widget is rendered one by WidgetKit, but TimelineView requires active rendering (but I don't understand how this works different to the above case...)
Code used:
@available(iOS 15, *)
public struct RealtimeCountdownView: View {
let dateToRender: Date
public var body: some View {
TimelineView(EveryMinuteTimelineSchedule()) {
context in
Text(dateAsString())
}
}
private func dateAsString() -> String {
let minuteInterval = Int((dateToRender.timeIntervalSince(Date()))/60.0)
if minuteInterval == 0 {
return "now"
}
if minuteInterval < 0 {
return String(minuteInterval) + " min ago"
}
return "in " + String(minuteInterval) + " min"
}
}
Scheduling more TimelineEntries to update the countdown value
In my testing, this doesn't really fix the problem as minute-level granularity updates are too frequent for WidgetKit to schedule. The best I've been able to get for a displayed widget with the app open in the background is around every 5 minutes.