feat: production-grade Live Activity with type-safe phases, decomposed views, previews, and alert transitions
- Replace raw string phase model with WorkoutPhase enum (Codable, Sendable, CaseIterable) with built-in .capitalized display name and SwiftUI .color per phase - Decompose WorkoutLiveActivity into reusable view structs: PhasePill, CountdownText, WorkoutProgressBar, MusicInfoRow, HeartRateBadge, PhaseIndicatorDot, WorkoutLockScreenView, WorkoutSmallView — following CraftingSwift iOS 26 architecture patterns - Add AlertConfiguration on work/rest/complete phase transitions so Dynamic Island expands and lights up at key moments - Add 13 #Preview blocks across both widgets covering all presentation types: lock screen, expanded, compact, minimal — for instant Xcode Canvas feedback - Add stale state handling (context.isStale shows 'Last updated' indicator) - MusicLiveActivity: 5 new #Preview blocks for playing/paused/expanded/compact/minimal
This commit is contained in:
@@ -186,3 +186,36 @@ struct LiveActivityMusicBars: View {
|
||||
private let barMaxHeights: [CGFloat] = [8, 14, 6, 12]
|
||||
private let barMin: CGFloat = 3
|
||||
private let barSpeeds: [Double] = [2.2, 1.8, 2.8, 1.5]
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
#Preview("Lock Screen — Playing", as: .content, using: MusicActivityAttributes()) {
|
||||
MusicLiveActivity()
|
||||
} contentStates: {
|
||||
MusicActivityAttributes.ContentState(title: "Lose Yourself", artist: "Eminem", isPlaying: true)
|
||||
}
|
||||
|
||||
#Preview("Lock Screen — Paused", as: .content, using: MusicActivityAttributes()) {
|
||||
MusicLiveActivity()
|
||||
} contentStates: {
|
||||
MusicActivityAttributes.ContentState(title: "Stronger", artist: "Kanye West", isPlaying: false)
|
||||
}
|
||||
|
||||
#Preview("Dynamic Island Expanded", as: .dynamicIsland(.expanded), using: MusicActivityAttributes()) {
|
||||
MusicLiveActivity()
|
||||
} contentStates: {
|
||||
MusicActivityAttributes.ContentState(title: "Till I Collapse", artist: "Eminem", isPlaying: true)
|
||||
MusicActivityAttributes.ContentState(title: "Eye of the Tiger", artist: "Survivor", isPlaying: false)
|
||||
}
|
||||
|
||||
#Preview("Dynamic Island Compact", as: .dynamicIsland(.compact), using: MusicActivityAttributes()) {
|
||||
MusicLiveActivity()
|
||||
} contentStates: {
|
||||
MusicActivityAttributes.ContentState(title: "Lose Yourself", artist: "Eminem", isPlaying: true)
|
||||
}
|
||||
|
||||
#Preview("Dynamic Island Minimal", as: .dynamicIsland(.minimal), using: MusicActivityAttributes()) {
|
||||
MusicLiveActivity()
|
||||
} contentStates: {
|
||||
MusicActivityAttributes.ContentState(title: "Lose Yourself", artist: "Eminem", isPlaying: true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user