iosswiftswiftuiwidgetkit

Stopping a SwiftUI Widget's relative textfield counter when hits zero?


I am creating a Widget that has a textfield that counts down from a date like so:

Text(endDate, style: .relative)

This works fine, however as its relative, once it hits zero, it will continue to count back up again as the endDate becomes in the past.

Is there a way to terminate the text when it hits zero? Or do I have to rebuild this feature with a timer?

All I need to do is count down from a start date to and end date then invalidate the text field or show a message.


Solution

  • Here is how you can create a countdown and when the time is over display some other text.

    1. Create an Entry where endDate is optional - if it's nil it means that the countdown is over:
    struct SimpleEntry: TimelineEntry {
        let date: Date
        var endDate: Date?
    }
    
    1. In your Provider create two Entries - one for the countdown time and one for when the countdown is over:
    struct SimpleProvider: TimelineProvider {
        ...
    
        func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
            let currentDate = Date()
            let endDate = Calendar.current.date(byAdding: .second, value: 15, to: currentDate)!
    
            let entries = [
                SimpleEntry(date: currentDate, endDate: endDate),
                SimpleEntry(date: endDate),
            ]
    
            let timeline = Timeline(entries: entries, policy: .never)
            completion(timeline)
        }
    }
    
    1. Use it in your view:
    struct WidgetEntryView: View {
        var entry: Provider.Entry
    
        var body: some View {
            if let endDate = entry.endDate {
                Text(endDate, style: .relative)
            } else {
                Text("Timer finished")
            }
        }
    }