// // LaunchWidget.swift // LaunchWidget // // Created by Laurent Morvillier on 25/01/2023. // import WidgetKit import SwiftUI import Intents struct Provider: IntentTimelineProvider { func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(timers: [], date: Date(), configuration: SelectTimerIntent()) } func getSnapshot(for configuration: SelectTimerIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { guard let cp = configuration.timer else { completion(placeholder(in: context)) return } let timers: [AbstractTimer] = cp.compactMap { if let id = $0.identifier { return IntentDataProvider.main.timer(id: id) } else { return nil } } let entry = SimpleEntry(timers: timers, date: Date(), configuration: configuration) completion(entry) } func getTimeline(for configuration: SelectTimerIntent, in context: Context, completion: @escaping (Timeline) -> ()) { getSnapshot(for: configuration, in: context) { entry in let timeline = Timeline(entries: [entry], policy: .atEnd) completion(timeline) } } } struct SimpleEntry: TimelineEntry { let timers: [AbstractTimer] let date: Date let configuration: SelectTimerIntent } struct CountdownSimpleWidgetView: View { let timer: AbstractTimer var body: some View { SingleTimerView(timer: timer) .widgetURL(timer.url) } } struct CountdownMultiWidgetView: View { let timers: [AbstractTimer] var body: some View { MultiCountdownView(timers: timers) } } struct LaunchWidgetEntryView : View { @Environment(\.widgetFamily) var family: WidgetFamily var entry: Provider.Entry let backgroundOpacity = 0.3 @ViewBuilder var body: some View { switch family { case .systemSmall, .accessoryInline: if let timer = entry.timers.first { CountdownSimpleWidgetView(timer: timer) } else { DefaultView() } case .accessoryCircular: Group { if let countdown = entry.timers.first { LockScreenCountdownView(timer: countdown) } else { DefaultView() } } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.white.opacity(backgroundOpacity)) .cornerRadius(16.0) case .accessoryRectangular: Group { if let timer = entry.timers.first { LockScreenCountdownView(timer: timer) } else { DefaultView() } } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.white.opacity(backgroundOpacity)) .cornerRadius(16.0) default: MultiCountdownView(timers: entry.timers) } } } struct LaunchWidget: Widget { let kind: String = "com.staxriver.launch-widget" var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: SelectTimerIntent.self, provider: Provider()) { entry in LaunchWidgetEntryView(entry: entry) } .configurationDisplayName("Launch Widget") .description("Select and launch your timers") .supportedFamilies([.systemSmall, .systemMedium, .systemLarge, .accessoryRectangular, .accessoryCircular]) } } struct LaunchWidget_Previews: PreviewProvider { static var previews: some View { let fake = Countdown.fake(context: PersistenceController.preview.container.viewContext) LaunchWidgetEntryView(entry: SimpleEntry(timers: [fake], date: Date(), configuration: SelectTimerIntent())) .previewContext(WidgetPreviewContext(family: .systemSmall)) LaunchWidgetEntryView(entry: SimpleEntry(timers: [fake, fake, fake, fake], date: Date(), configuration: SelectTimerIntent())) .previewContext(WidgetPreviewContext(family: .systemMedium)) LaunchWidgetEntryView(entry: SimpleEntry(timers: [fake], date: Date(), configuration: SelectTimerIntent())) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) LaunchWidgetEntryView(entry: SimpleEntry(timers: [fake], date: Date(), configuration: SelectTimerIntent())) .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) } }