App/Widgets/LaunchLiveActivity.swift
56 lines · 2646 bytes
2 symbols in this file
1import ActivityKit
2import SwiftUI
3import WidgetKit
4
5struct LaunchLiveActivity: Widget {
6 private let ink = Color(red: 0.95, green: 0.95, blue: 0.93)
7 private let accent = Color(red: 0.88, green: 0.24, blue: 0.19)
8
9 var body: some WidgetConfiguration {
10 ActivityConfiguration(for: LaunchActivityAttributes.self) { context in
11 HStack(alignment: .center, spacing: 12) {
12 VStack(alignment: .leading, spacing: 2) {
13 Text(context.attributes.rocket).font(.system(size: 17, weight: .medium))
14 Text(context.attributes.mission).font(.system(size: 13)).lineLimit(1).opacity(0.8)
15 Text(context.attributes.location).font(.system(size: 11)).lineLimit(1).opacity(0.6)
16 }
17 Spacer()
18 VStack(alignment: .trailing, spacing: 2) {
19 Text(context.state.status.uppercased()).font(.system(size: 10, weight: .medium)).tracking(0.6)
20 .foregroundStyle(context.state.status == "Hold" ? accent : ink)
21 HStack(spacing: 2) {
22 Text(context.state.net > .now ? "T−" : "T+")
23 countdown(context.state.net)
24 }
25 .font(.system(size: 22, weight: .medium).monospacedDigit())
26 }
27 }
28 .padding(16)
29 .foregroundStyle(ink)
30 .activityBackgroundTint(Color(red: 0.043, green: 0.078, blue: 0.141))
31 } dynamicIsland: { context in
32 DynamicIsland {
33 DynamicIslandExpandedRegion(.leading) {
34 Text(context.attributes.rocket).font(.system(size: 14, weight: .medium))
35 }
36 DynamicIslandExpandedRegion(.trailing) {
37 countdown(context.state.net).font(.system(size: 14, weight: .medium).monospacedDigit())
38 }
39 DynamicIslandExpandedRegion(.bottom) {
40 Text(context.attributes.mission).font(.system(size: 12)).lineLimit(1).opacity(0.8)
41 }
42 } compactLeading: {
43 Text("T−").font(.system(size: 12, weight: .medium))
44 } compactTrailing: {
45 countdown(context.state.net).font(.system(size: 12).monospacedDigit()).frame(maxWidth: 64)
46 } minimal: {
47 Image(systemName: "arrow.up")
48 }
49 }
50 }
51
52 /// Counts down to T-0, then shows elapsed time.
53 private func countdown(_ net: Date) -> Text {
54 net > .now ? Text(timerInterval: Date.now...net, countsDown: true) : Text(net, style: .timer)
55 }
56}