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>
146 lines
5.3 KiB
Swift
146 lines
5.3 KiB
Swift
import WidgetKit
|
|
import SwiftUI
|
|
|
|
@main
|
|
struct CalendarrWatchComplicationBundle: WidgetBundle {
|
|
var body: some Widget {
|
|
WatchNextEventWidget()
|
|
WatchCornerCountdownWidget()
|
|
WatchCornerTimeWidget()
|
|
WatchCountdownWidget()
|
|
WatchDateWidget()
|
|
WatchTodayCountWidget()
|
|
WatchNextTwoWidget()
|
|
WatchDatePlusEventWidget()
|
|
}
|
|
}
|
|
|
|
private extension View {
|
|
/// Accessory families paint their own background; ours must stay out of
|
|
/// the way so the watch face's tint comes through.
|
|
func complicationChrome(_ language: String) -> some View {
|
|
containerBackground(for: .widget) { Color.clear }
|
|
.environment(\.locale, WatchL10n.locale(language))
|
|
}
|
|
}
|
|
|
|
struct WatchNextEventWidget: Widget {
|
|
let kind = "WatchNextEvent"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
NextEventComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Nächster Termin")
|
|
.description("Zeit, Titel und Ort des nächsten Termins.")
|
|
.supportedFamilies([.accessoryRectangular, .accessoryInline])
|
|
}
|
|
}
|
|
|
|
struct WatchCornerCountdownWidget: Widget {
|
|
let kind = "WatchCornerCountdown"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
CornerCountdownComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Restzeit (Ecke)")
|
|
.description("Restzeit bis zum nächsten Termin, Name am Rand.")
|
|
.supportedFamilies([.accessoryCorner])
|
|
}
|
|
}
|
|
|
|
struct WatchCornerTimeWidget: Widget {
|
|
let kind = "WatchCornerTime"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
CornerTimeComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Uhrzeit (Ecke)")
|
|
.description("Uhrzeit des nächsten Termins, Name am Rand.")
|
|
.supportedFamilies([.accessoryCorner])
|
|
}
|
|
}
|
|
|
|
struct WatchCountdownWidget: Widget {
|
|
let kind = "WatchCountdown"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
CountdownComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Countdown")
|
|
.description("Ring, der bis zum nächsten Termin leerläuft.")
|
|
.supportedFamilies([.accessoryCircular, .accessoryInline])
|
|
}
|
|
}
|
|
|
|
struct WatchDateWidget: Widget {
|
|
let kind = "WatchDate"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
DateComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Datum")
|
|
.description("Tag und Monat.")
|
|
.supportedFamilies([.accessoryCircular, .accessoryInline])
|
|
}
|
|
}
|
|
|
|
struct WatchTodayCountWidget: Widget {
|
|
let kind = "WatchTodayCount"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
TodayCountComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Termine heute")
|
|
.description("Anzahl der heutigen Termine.")
|
|
.supportedFamilies([.accessoryCircular, .accessoryInline])
|
|
}
|
|
}
|
|
|
|
struct WatchNextTwoWidget: Widget {
|
|
let kind = "WatchNextTwo"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
NextTwoComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Die nächsten zwei")
|
|
.description("Die beiden nächsten Termine.")
|
|
.supportedFamilies([.accessoryRectangular])
|
|
}
|
|
}
|
|
|
|
struct WatchDatePlusEventWidget: Widget {
|
|
let kind = "WatchDatePlusEvent"
|
|
|
|
var body: some WidgetConfiguration {
|
|
AppIntentConfiguration(kind: kind,
|
|
intent: WatchCalendarSelectionIntent.self,
|
|
provider: WatchComplicationProvider()) { entry in
|
|
DatePlusEventComplicationView(entry: entry).complicationChrome(entry.language)
|
|
}
|
|
.configurationDisplayName("Datum + Termin")
|
|
.description("Datum und nächster Termin in einem Slot.")
|
|
.supportedFamilies([.accessoryRectangular])
|
|
}
|
|
}
|