WidgetKit display realtime countdown in "x min" format?

29 views Asked by At

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.

0

There are 0 answers