Trois widgets d'ecran verrouille et une complication Routine
Les familles accessory* n'etaient declarees que cote Watch, alors que ce sont
exactement celles de l'ecran verrouille iOS 16+. Les vues existaient donc
deja : il ne manquait que la declaration cote iPhone.
Ajoutes sur l'ecran verrouille : Forme (circulaire/rectangulaire/inline),
Seance (rectangulaire/inline, avec la bascule doneToday du commit precedent)
et Routine du jour. Sur la Watch : complication Routine, et la seance gagne la
famille circulaire (icone du sport, verte quand elle est faite).
Le snapshot gagne RoutineProgress {done, total} au grain EXERCICE — celui de
la page web et de l'app Watch depuis le 03/08. `fraction` borne le ratio et
protege de la division par zero ; un total nul ne doit pas remplir la jauge.
Meme garde du jour que doneToday : la routine repart a zero au reveil, un
report aveugle afficherait 24/24 des le matin.
Vues dupliquees plutot que partagees entre les deux extensions : elles ne
partagent aucun fichier et l'App Group n'est pas commun entre appareils. Trois
petites vues coutent moins qu'un fichier de plus a cabler dans deux cibles —
et pour la meme raison tout est ajoute a CoachWidgets.swift, deja membre de sa
cible : AUCUN fichier nouveau, donc rien a cabler dans le pbxproj.
⚠️ NON COMPILE — a builder au prochain passage sur le Mac, avec le correctif
« JOUR OFF » (12b56a4).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -146,7 +146,16 @@ struct CoachWatchSessionView: View {
|
||||
let today = entry.snapshot?.today
|
||||
Group {
|
||||
if let s = today {
|
||||
if family == .accessoryInline {
|
||||
if family == .accessoryCircular {
|
||||
// Le cadran ne tient pas un titre : l'icône du sport porte
|
||||
// l'information, la pastille verte dit qu'elle est faite.
|
||||
ZStack {
|
||||
AccessoryWidgetBackground()
|
||||
Image(systemName: watchSportSymbol(s.sport))
|
||||
.font(.title3)
|
||||
.foregroundStyle(s.done ? .green : .primary)
|
||||
}
|
||||
} else if family == .accessoryInline {
|
||||
Label(s.title, systemImage: watchSportSymbol(s.sport))
|
||||
} else { // accessoryRectangular
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
@@ -206,7 +215,59 @@ struct CoachWatchSessionWidget: Widget {
|
||||
}
|
||||
.configurationDisplayName("Séance du jour")
|
||||
.description("La séance prévue aujourd'hui.")
|
||||
.supportedFamilies([.accessoryRectangular, .accessoryInline])
|
||||
.supportedFamilies([.accessoryRectangular, .accessoryInline, .accessoryCircular])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Complication « Routine du jour » (circular / rectangular / inline)
|
||||
|
||||
/// Avancement au grain EXERCICE (14/24) — le même que la page web et l'app
|
||||
/// Watch depuis le 2026-08-03. Un grain « bloc » donnerait un second compte
|
||||
/// du même geste, et les deux finiraient par diverger.
|
||||
struct CoachWatchRoutineView: View {
|
||||
@Environment(\.widgetFamily) private var family
|
||||
var entry: WatchEntry
|
||||
|
||||
var body: some View {
|
||||
let r = entry.snapshot?.routine
|
||||
let text = r.map { "\($0.done)/\($0.total)" } ?? "—"
|
||||
Group {
|
||||
switch family {
|
||||
case .accessoryInline:
|
||||
Label("Routine \(text)", systemImage: "figure.cooldown")
|
||||
case .accessoryRectangular:
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Label("ROUTINE", systemImage: "figure.cooldown")
|
||||
.font(.caption2.weight(.bold)).foregroundStyle(.secondary)
|
||||
Text(text).font(.headline)
|
||||
if let r, r.total > 0 {
|
||||
ProgressView(value: r.fraction).progressViewStyle(.linear)
|
||||
}
|
||||
}
|
||||
default: // accessoryCircular
|
||||
Gauge(value: r?.fraction ?? 0, in: 0...1) {
|
||||
Image(systemName: "figure.cooldown")
|
||||
} currentValueLabel: {
|
||||
Text(r.map { String($0.done) } ?? "—")
|
||||
}
|
||||
.gaugeStyle(.accessoryCircular)
|
||||
.tint(.mint)
|
||||
}
|
||||
}
|
||||
.watchWidgetBackground()
|
||||
.widgetURL(URL(string: "https://coach.hypnotruck.ch/routine"))
|
||||
}
|
||||
}
|
||||
|
||||
struct CoachWatchRoutineWidget: Widget {
|
||||
let kind = "CoachWatchRoutineWidget"
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(kind: kind, provider: WatchProvider()) { entry in
|
||||
CoachWatchRoutineView(entry: entry)
|
||||
}
|
||||
.configurationDisplayName("Routine")
|
||||
.description("Exercices de la routine cochés aujourd'hui.")
|
||||
.supportedFamilies([.accessoryCircular, .accessoryRectangular, .accessoryInline])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,5 +278,6 @@ struct CoachWatchWidgetsBundle: WidgetBundle {
|
||||
var body: some Widget {
|
||||
CoachWatchFormeWidget()
|
||||
CoachWatchSessionWidget()
|
||||
CoachWatchRoutineWidget()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user