DroppyCompactClock

A clock for compact live-activity content that the host drives (DroppyKit 1.23.0).

@MainActor struct DroppyCompactClock<Content> where Content : View

Available from DroppyKit 1.23.0.

Droppy's own compact rows (the meeting timer, the calendar ring, the recording waveform) never run a timer of their own. Each draws from a timeline that ticks only while the row is up and at rest, and holds still while the host reveals it, takes it away, moves the notch for a shelf spring or conceals the notch. This is that timeline, for a droplet:

public func makeCompactTrailing(context: CompactLiveActivityContext) -> AnyView {
    AnyView(
        DroppyCompactClock { now in
            Text(timer.remaining(at: now))
                .font(.system(size: DroppyLiveActivityMetrics.labelFontSize, weight: .medium))
                .monospacedDigit()
        }
    )
}

Use it instead of a Timer, a Timer.publish sink, a repeatForever animation or a TimelineView(.animation) in a compact view. Those keep running while nobody can see the row, and the host cannot stop them; this one stops on pausesLiveContent, which the host sets through EnvironmentValues.dropletCompactPresentation.

  • Ticks land on whole multiples of interval (whole seconds by default), so a clock flips its digit when the wall clock does, never up to a second late.
  • While paused, content keeps the date of the last tick.
  • The shortest interval is compactClockMinimumInterval (30 a second), and Reduce Motion holds anything faster than a second to one tick a second.
  • Outside a compact mount (a settings preview, the harness) nothing pauses it, so it simply ticks.

Initializers

init(every:content:)

@MainActor init(every interval: TimeInterval = 1, @ViewBuilder content: @escaping (Date) -> Content)

Creates a clock that ticks every interval seconds while the compact surface it is in is up and at rest.

Properties

body

@MainActor var body: some View { get }