033b3f3fd3
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.
90 lines
2.8 KiB
Swift
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()
|
|
}
|
|
}
|