Archived
The watch receives the phone's payload over WatchConnectivity and writes it into its own App Group container through the same SnapshotStore, so there is one wire format and one reader. The agenda, the detail screen and the filter all read that; the complications read what the app last wrote, since an extension cannot run a WCSession of its own. Complication timelines land on event boundaries rather than a schedule, so the next appointment flips in the exact minute it changes without spending refresh budget. CalendarrWatchShared holds what both watch targets need, attached to each the way Shared/ is attached to the app and the widgets. recommendations() is implemented because watchOS requires it — iOS has a default, the watch does not, since the complication gallery has to be populated. Found by building, not by reading. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
45 lines
1.8 KiB
Swift
45 lines
1.8 KiB
Swift
import AppIntents
|
|
import WidgetKit
|
|
import CalendarrCore
|
|
|
|
/// One calendar option in a complication's configuration.
|
|
struct WatchCalendarEntity: AppEntity, Identifiable {
|
|
let id: String
|
|
let name: String
|
|
|
|
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Kalender"
|
|
static var defaultQuery = WatchCalendarEntityQuery()
|
|
|
|
var displayRepresentation: DisplayRepresentation {
|
|
DisplayRepresentation(title: LocalizedStringResource(stringLiteral: name))
|
|
}
|
|
}
|
|
|
|
/// Reads the calendars from this watch's App Group container, so configuration
|
|
/// needs no network call and no phone.
|
|
struct WatchCalendarEntityQuery: EntityQuery {
|
|
func entities(for identifiers: [String]) async throws -> [WatchCalendarEntity] {
|
|
let wanted = Set(identifiers)
|
|
return SnapshotStore().readCalendars()
|
|
.filter { wanted.contains($0.id) }
|
|
.map { WatchCalendarEntity(id: $0.id, name: $0.name) }
|
|
}
|
|
|
|
func suggestedEntities() async throws -> [WatchCalendarEntity] {
|
|
SnapshotStore().readCalendars().map { WatchCalendarEntity(id: $0.id, name: $0.name) }
|
|
}
|
|
}
|
|
|
|
/// Per-complication override of the calendar selection. The in-app toggles are
|
|
/// the primary path — intent configuration on a watch face is awkward to
|
|
/// operate — so an empty selection means "whatever the app is set to".
|
|
struct WatchCalendarSelectionIntent: WidgetConfigurationIntent {
|
|
static var title: LocalizedStringResource = "Kalender auswählen"
|
|
static var description = IntentDescription("Leer = die Auswahl aus der Watch-App.")
|
|
|
|
// Must be optional: WidgetConfigurationIntent requires optional parameter
|
|
// types, and the watchOS SDK enforces it where iOS lets a bare array pass.
|
|
@Parameter(title: "Kalender")
|
|
var selectedCalendars: [WatchCalendarEntity]?
|
|
}
|