// // CountdownView.swift // LeCountdown // // Created by Laurent Morvillier on 25/01/2023. // import SwiftUI import WidgetKit import CoreData struct GradientView: View { private static let backgroundGradientColors: [Color] = [.red, .purple] var body: some View { ZStack { GeometryReader { reader in let gradient: Gradient = Gradient(colors: GradientView.backgroundGradientColors) RadialGradient(gradient: gradient, center: .init(x: 0.0, y: 0.0), startRadius: 0, endRadius: reader.size.width) } } } } extension View { var linearGradient: LinearGradient { LinearGradient(colors: [Color(red: 255, green: 128, blue: 223), Color(red: 255, green: 180, blue: 78)], startPoint: .topLeading, endPoint: .bottomTrailing) } var radialGradient: some View { RadialGradient(colors: [Color(red: 255, green: 128, blue: 223), Color(red: 255, green: 86, blue: 61), Color(red: 255, green: 180, blue: 78)], center: .bottomLeading, startRadius: Angle.degrees(0).degrees, endRadius: Angle.degrees(90).degrees) } } 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.hourMinuteSecond) } } Spacer() } Spacer() } .padding() .monospaced() .foregroundColor(.white) .background(GradientView()) // .background(.white.opacity(0.5)) .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 { let title = self.timer.displayName.uppercased() switch self.family { case .accessoryCircular: Text(title) default: Text(title) if let countdown = self.timer as? Countdown { Text(countdown.duration.hourMinuteSecond) .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 { return .system(size: 14.0, weight: .medium) // return .body // switch self.family { // case .systemSmall, .systemMedium, .systemLarge, .systemExtraLarge: // return .body // case .accessoryCircular: // return Font.system(.body, 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 { DefaultView() } 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()).lineLimit(1) if let countdown = timer as? Countdown { Text(countdown.duration.hourMinuteSecond) } Spacer() } Spacer() } .padding(.horizontal, 12.0) .padding(.vertical, 4.0) .font(.footnote) .background(Color.white.opacity(0.1)) .foregroundColor(.white) .monospaced() .cornerRadius(16.0) } } } .padding(.horizontal, 12.0) .padding(.vertical, 16.0) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(GradientView()) // .background(.white.opacity(0.5)) } } 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) MultiCountdownView(timers: self.countdowns(context: PersistenceController.preview.container.viewContext)).previewContext(WidgetPreviewContext(family: .systemMedium)) 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)) } static func countdowns(context: NSManagedObjectContext) -> [Countdown] { return (0..<4).map { _ in Countdown.fake(context: context) } } }