Files
workouts/Workouts Watch Widget/WorkoutsWatchWidget.swift
T
rzen 033b3f3fd3 Tilt the complication dumbbell to match the app icon
Rotate the dumbbell glyph -35° (counter-clockwise) in the circular,
corner, and rectangular accessory families so it runs lower-left to
upper-right like the app icon. Inline stays upright since that template
renders the symbol on the time line.
2026-06-21 06:27:12 -04:00

90 lines
2.8 KiB
Swift

import SwiftUI
import WidgetKit
// A launcher complication: a static button on the watch face that opens the
// Workouts app. It carries no data, so the timeline is a single entry that
// never refreshes. Tapping any accessory widget launches its containing app,
// so no deep link or App Group is needed.
private struct LauncherEntry: TimelineEntry {
let date: Date
}
private struct LauncherProvider: TimelineProvider {
func placeholder(in context: Context) -> LauncherEntry {
LauncherEntry(date: .now)
}
func getSnapshot(in context: Context, completion: @escaping (LauncherEntry) -> Void) {
completion(LauncherEntry(date: .now))
}
func getTimeline(in context: Context, completion: @escaping (Timeline<LauncherEntry>) -> Void) {
// Nothing ever changes one entry, never reload.
completion(Timeline(entries: [LauncherEntry(date: .now)], policy: .never))
}
}
private struct LauncherView: View {
@Environment(\.widgetFamily) private var family
private let glyph = "dumbbell.fill"
// The app icon's dumbbell runs lower-left to upper-right; tilt the glyph
// counter-clockwise to match (SwiftUI rotates clockwise for positive angles).
private var dumbbell: some View {
Image(systemName: glyph)
.rotationEffect(.degrees(-35))
}
var body: some View {
switch family {
case .accessoryInline:
// Inline templates render the symbol upright next to text; leave as-is.
Label("Workouts", systemImage: glyph)
case .accessoryRectangular:
HStack(spacing: 6) {
dumbbell.font(.title3)
Text("Workouts").font(.headline)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
case .accessoryCorner:
dumbbell
.font(.title2)
.widgetLabel("Workouts")
default: // .accessoryCircular and any future families
ZStack {
AccessoryWidgetBackground()
dumbbell
.font(.title3)
}
}
}
}
struct WorkoutsLauncherComplication: Widget {
private let kind = "WorkoutsLauncher"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: LauncherProvider()) { _ in
LauncherView()
.containerBackground(.clear, for: .widget)
}
.configurationDisplayName("Open Workouts")
.description("Tap to open the Workouts app.")
.supportedFamilies([
.accessoryCircular,
.accessoryCorner,
.accessoryInline,
.accessoryRectangular,
])
}
}
@main
struct WorkoutsWatchWidgetBundle: WidgetBundle {
var body: some Widget {
WorkoutsLauncherComplication()
}
}