Search code examples
iosswiftuiswiftui-textactivitykit

How can I control the date format when selecting .timer style in SwiftUI in ActivityKit


In my SwiftUI iOS 17 app, I am displaying a timer in my ActivityWidget so that the user can see a countdown timer when the phone screen is locked.

In order to display the widget, I am only passing the end Date to the Activity Widget and using the Text date style to display the timer countdown:

import ActivityKit
import WidgetKit
import SwiftUI

struct TimerAttributes: ActivityAttributes {
        
    let endDate: Date
    
    public struct ContentState: Codable, Hashable {
    }
}

struct TimerWidgetLiveActivity: Widget {
    
    var body: some WidgetConfiguration {
        
        ActivityConfiguration(for: TimerAttributes.self) { context in
            Text(context.attributes.endDate, style: .timer)
        } dynamicIsland: { context in
            DynamicIsland {
                DynamicIslandExpandedRegion(.leading) {
                    
                }
                DynamicIslandExpandedRegion(.center) {
                    
                }
                DynamicIslandExpandedRegion(.trailing) {
                    
                }
                DynamicIslandExpandedRegion(.bottom) {
                    
                }
            } compactLeading: {
                
            } compactTrailing: {
                
            } minimal: {
                
            }
        }
    }
}

The issue I am having is with the inconsistent format of the text. What I would like is for it to display like 03:32:44.

It does display like this when the screen has just been locked. But when the screen goes to the always on state in the new iPhone it displays '3 hours, 32 minutes'.

I understand dropping the seconds to save battery but I want 3:32:-- which is what the native timer app does. Is there anyway to change this formatting?

I have tried firing a timer and updating every second but that seems also like using too much battery and I prefer dropping seconds when it goes to the always on state which it seems to manage well itself using the Text styling.

Just wonder what the best approach is to show timer with seconds if just sleep and timer replacing seconds with -- in the always on state instead of writing out 'hours and minutes' which takes too much space and ruins the limited UI.


Solution

  • spent a bit of time on this and found out how to get the XX:-- format on the lock screen with Always on display.

    The trick is not to use the Text initializer with Date but rather use the one with the timerInterval.

    See example below:

      Text(
        timerInterval: Date.now...Date(timeInterval: 3600, since: .now),
        countsDown: false
        )
    

    This example will count up from zero to 1 hour when the screen is unlocked and switch to 0:-- when the screen gets locked. (You'll probably be using the date from your context object). If you want to count down instead just flip the countsDown value. I believe this is what Apple uses in their Timer app live activity.

    Hope this helps!