Archived
The position asked for is the bezel slot: a circular complication plus a label that arcs across the top, where the tick marks otherwise are. ClockKit called that family graphicBezel; in WidgetKit it is an accessoryCircular widget with .widgetLabel attached. Nothing was attached, so that arc stayed empty while Apple's Calendar fills it — which is the difference that was visible on the watch and invisible in every check made here. All three circular kinds now carry it. Faces without a bezel slot ignore the label, so there is no cost to always providing it. cornerLabel becomes eventLabel: the same text serves the corner edge and the bezel arc, and the old name claimed otherwise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
133 lines
4.8 KiB
Swift
133 lines
4.8 KiB
Swift
import SwiftUI
|
|
import WidgetKit
|
|
import CalendarrCore
|
|
|
|
/// Attaches the curved bezel label that a face with a bezel slot — Infograph —
|
|
/// renders across the top, where the tick marks otherwise are. Faces without
|
|
/// that slot ignore it, so it costs nothing to always provide.
|
|
private extension View {
|
|
func eventBezelLabel(_ entry: WatchComplicationEntry) -> some View {
|
|
let next = WatchComplicationSupport.nextEvent(in: entry.snapshot, at: entry.date)
|
|
return widgetLabel {
|
|
Text(WatchComplicationSupport.eventLabel(next, at: entry.date, language: entry.language))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A draining ring plus the remaining time.
|
|
struct CountdownComplicationView: View {
|
|
let entry: WatchComplicationEntry
|
|
@Environment(\.widgetFamily) private var family
|
|
|
|
var body: some View {
|
|
let next = WatchComplicationSupport.nextEvent(in: entry.snapshot, at: entry.date)
|
|
switch family {
|
|
case .accessoryInline:
|
|
inline(next)
|
|
default:
|
|
circular(next)
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func circular(_ next: SnapshotEvent?) -> some View {
|
|
if let next {
|
|
let target = WatchComplicationSupport.countdownTarget(next, at: entry.date)
|
|
Gauge(value: WatchComplicationSupport.gaugeFraction(to: target, at: entry.date)) {
|
|
Image(systemName: "calendar")
|
|
} currentValueLabel: {
|
|
Text(WatchComplicationSupport.compactCountdown(to: target, at: entry.date,
|
|
language: entry.language))
|
|
.font(.system(size: 13))
|
|
.lineLimit(1)
|
|
.minimumScaleFactor(0.6)
|
|
}
|
|
.gaugeStyle(.accessoryCircularCapacity)
|
|
.widgetAccentable()
|
|
.eventBezelLabel(entry)
|
|
} else {
|
|
ZStack {
|
|
AccessoryWidgetBackground()
|
|
Image(systemName: "calendar").font(.system(size: 18))
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func inline(_ next: SnapshotEvent?) -> some View {
|
|
if let next {
|
|
Label {
|
|
Text(WatchComplicationSupport.countdownTarget(next, at: entry.date), style: .timer)
|
|
} icon: {
|
|
Image(systemName: "timer")
|
|
}
|
|
} else {
|
|
Label(WatchL10n.t("watch.no_events", entry.language), systemImage: "calendar")
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Day number and month. No appointment information — a date replacement.
|
|
struct DateComplicationView: View {
|
|
let entry: WatchComplicationEntry
|
|
@Environment(\.widgetFamily) private var family
|
|
|
|
private var day: Int {
|
|
Calendar(identifier: .gregorian).component(.day, from: entry.date)
|
|
}
|
|
|
|
var body: some View {
|
|
switch family {
|
|
case .accessoryInline:
|
|
Label("\(WatchComplicationSupport.monthAbbreviation(entry.date, language: entry.language)) \(day)",
|
|
systemImage: "calendar")
|
|
default:
|
|
// A closed gauge, filling the slot edge to edge — the WidgetKit
|
|
// equivalent of ClockKit's ClosedGaugeText, which no longer exists.
|
|
// The ring is not decoration: it drains as the day does.
|
|
Gauge(value: WatchComplicationSupport.dayRemainingFraction(at: entry.date)) {
|
|
Text(WatchComplicationSupport.monthAbbreviation(entry.date, language: entry.language))
|
|
} currentValueLabel: {
|
|
Text("\(day)")
|
|
.font(.system(size: 20, weight: .semibold))
|
|
.lineLimit(1)
|
|
.minimumScaleFactor(0.6)
|
|
}
|
|
.gaugeStyle(.accessoryCircularCapacity)
|
|
.widgetAccentable()
|
|
.eventBezelLabel(entry)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// How many appointments today. Says "busy", not "what".
|
|
struct TodayCountComplicationView: View {
|
|
let entry: WatchComplicationEntry
|
|
@Environment(\.widgetFamily) private var family
|
|
|
|
private var count: Int {
|
|
WatchComplicationSupport.todayCount(in: entry.snapshot, at: entry.date)
|
|
}
|
|
|
|
var body: some View {
|
|
switch family {
|
|
case .accessoryInline:
|
|
Label("\(count) \(WatchL10n.t("watch.events_today", entry.language))",
|
|
systemImage: "calendar")
|
|
default:
|
|
Gauge(value: WatchComplicationSupport.todayRemainingFraction(in: entry.snapshot,
|
|
at: entry.date)) {
|
|
Image(systemName: "calendar")
|
|
} currentValueLabel: {
|
|
Text("\(count)")
|
|
.font(.system(size: 20, weight: .semibold))
|
|
.lineLimit(1)
|
|
.minimumScaleFactor(0.6)
|
|
}
|
|
.gaugeStyle(.accessoryCircularCapacity)
|
|
.widgetAccentable()
|
|
.eventBezelLabel(entry)
|
|
}
|
|
}
|
|
}
|