esc

Beside the notch

A live activity is a compact row beside the notch, like Ledge's own volume or charging: a symbol, a few words and, if you want, a progress ring. Ledge's own activities always come first.

1The notch's wings, or the island on a display without a notch"activity" · LedgeKit 0.10.0

Showing an activity

Send the activities you have up. Each send replaces the last, and one you leave out is taken down:

AddOnSession.show(activities: [
    LiveActivity("countdown", symbol: "timer", text: "4:59", progress: .fraction(0.2), importance: .high)
])
AddOnSession.show(activities: [])   // take them all down
FieldWhat it is
idStable while it's up, so Ledge updates it in place
symbolAn SF Symbol name
textUp to 60 characters. Keep it to a few words or a number
progress.fraction(0…1) fills a ring that far, .indeterminate spins an arc, .done fills the ring. Nil draws none
importance.low, .normal, .high or .attention, against other add-ons' activities. .attention is for something to act on now, and lets the add-on open its page (0.13.0)
lastsSeconds it stays after this send, 1 to 600. Nil keeps it up until you take it down

Where it goes

The centre beside the notch belongs to the most important activity up, and up to two more sit in side pills. Every add-on activity ranks below every one of Ledge's, so music, volume or a low battery always win the centre. Ledge tells you where each of yours is whenever that changes:

PlacementMeans
centerBeside the notch
sideIn a side pill, next to something more important
outrankedUp, but waiting: more important activities fill every place
suppressedThe user turned off this add-on's activities on its settings page
idleDown: it ended, ran out its time, or you took it down
duplicatesBuiltInNot shown while Ledge's own activity of the same kind is up. 0.13.0
staleStepped aside after saying the same thing for half an hour. 0.13.0
handlers.onActivityPlacement = { change in
    if change.placement == .suppressed { await countdown.stopSendingActivities() }
}

One of each thing

When your activity is something Ledge shows itself, say so with kind: .nowPlaying for a podcast or a song, .download or .recording. While Ledge's own of that kind is up, yours steps aside with duplicatesBuiltIn and comes back when Ledge's ends, so there are never two of the same thing beside the notch. A kind never wins a place. Leave it out for anything else.

LiveActivity("episode", symbol: "headphones", text: "12:40", kind: .nowPlaying,
             accessibilityValue: "12 minutes 40 seconds left")

accessibilityValue is what VoiceOver says for the activity when its text alone doesn't, like a time read as words. Up to 120 characters.

Rows that stop changing

A .high or .attention activity that says exactly the same thing for half an hour steps aside, placed stale, until you send something different. A build that moves or a countdown that ticks never goes stale. This applies to add-ons built with LedgeKit 0.13.0 or later; older ones hear outranked for either new placement.

Good manners

  • Take an activity down as soon as it has nothing to say. One that's up for no reason pushes the user's own away.
  • For something brief, like “Done”, set lasts instead of sending it and taking it down yourself.
  • While you're suppressed, stop sending updates. When the user turns activities back on you're told, so send the current state then.
  • If something important ends while you're outranked or suppressed, say so another way, such as with LedgeHost.notify.