// // CountdownView.swift // LeCountdown // // Created by Laurent Morvillier on 25/01/2023. // import SwiftUI import WidgetKit import CoreData struct SingleTimerView: View { @Environment(\.widgetFamily) var family: WidgetFamily var timer: AbstractTimer var body: some View { VStack { HStack { VStack(alignment: .leading) { Text(timer.displayName.uppercased()) if let countdown = timer as? Countdown { Text(countdown.duration.minuteSecond) } } Spacer() } Spacer() } .padding() .monospaced() .foregroundColor(Color.white) .font(self.font) .widgetURL(timer.url) } private var font: Font { switch family { case .systemSmall, .systemMedium, .systemLarge, .systemExtraLarge: return .body case .accessoryCircular: return .footnote default: return .body } } } struct LockScreenCountdownView: View { @Environment(\.widgetFamily) var family: WidgetFamily var timer: AbstractTimer var body: some View { VStack { Text(activityName.uppercased()) if let countdown = self.timer as? Countdown { Text(countdown.duration.minuteSecond) .monospaced() } } .multilineTextAlignment(.center) .foregroundColor(Color.white) .font(self.font) .widgetURL(self.timer.url) } private var activityName: String { switch self.family { case .accessoryCircular: let reduced = self.timer.displayName if reduced.contains(" ") { let initials = reduced.components(separatedBy: " ").compactMap { $0.first }.map { String($0) } return initials.joined(separator: "") } else { return String(reduced.prefix(5)) } default: return self.timer.displayName } } private var font: Font { switch self.family { case .systemSmall, .systemMedium, .systemLarge, .systemExtraLarge: return .body case .accessoryCircular: return Font.system(.callout, weight: .medium) default: return .body } } } struct MultiCountdownView: View { @Environment(\.widgetFamily) var family: WidgetFamily private let columns: [GridItem] = [ GridItem(spacing: 10.0), GridItem(spacing: 10.0), ] var timers: [AbstractTimer] var body: some View { if self.timers.isEmpty { VoidView() } else { LazyVGrid( columns: self.columns, spacing: 10.0 ) { ForEach(self.timers) { timer in Link(destination: timer.url) { HStack { VStack(alignment: .leading) { Spacer() Text(timer.displayName.uppercased()) if let countdown = timer as? Countdown { Text(countdown.duration.minuteSecond) } Spacer() } Spacer() } .padding(.horizontal) .font(.callout) .background(Image(timer.imageName)) .foregroundColor(.white) .monospaced() .cornerRadius(16.0) } } }.padding() } } private var font: Font { switch family { case .systemSmall, .systemMedium, .systemLarge, .systemExtraLarge: return .title2 default: return .body } } } struct CountdownView_Previews: PreviewProvider { static var previews: some View { SingleTimerView(timer: Countdown.fake(context: PersistenceController.preview.container.viewContext)).previewContext(WidgetPreviewContext(family: .systemSmall)).background(.black) LockScreenCountdownView(timer: Countdown.fake(context: PersistenceController.preview.container.viewContext)).previewContext(WidgetPreviewContext(family: .accessoryRectangular)) LockScreenCountdownView(timer: Countdown.fake(context: PersistenceController.preview.container.viewContext)).previewContext(WidgetPreviewContext(family: .accessoryCircular)) MultiCountdownView(timers: self.countdowns(context: PersistenceController.preview.container.viewContext)).previewContext(WidgetPreviewContext(family: .systemMedium)) } static func countdowns(context: NSManagedObjectContext) -> [Countdown] { return (0..<4).map { _ in Countdown.fake(context: context) } } }