// // 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(countdowns: [], date: Date(), configuration: SelectCountdownIntent()) } func getSnapshot(for configuration: SelectCountdownIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { guard let cp = configuration.countdown else { completion(placeholder(in: context)) return } let countdowns: [Countdown] = cp.compactMap { if let id = $0.identifier { return IntentDataProvider.main.countdown(id: id) } else { return nil } } let entry = SimpleEntry(countdowns: countdowns, date: Date(), configuration: configuration) completion(entry) } func getTimeline(for configuration: SelectCountdownIntent, 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 countdowns: [Countdown] let date: Date let configuration: SelectCountdownIntent } struct CountdownSimpleWidgetView: View { let countdown: Countdown var body: some View { SingleCountdownView(countdown: countdown) .widgetURL(countdown.url) } } struct CountdownMultiWidgetView: View { let countdowns: [Countdown] var body: some View { MultiCountdownView(countdowns: countdowns) } } struct VoidView : View { var body: some View { VStack { Text("Tea!") Text("4:00") } } } struct LaunchWidgetEntryView : View { @Environment(\.widgetFamily) var family: WidgetFamily var entry: Provider.Entry @ViewBuilder var body: some View { switch family { case .systemSmall, .accessoryInline: if let countdown = entry.countdowns.first { CountdownSimpleWidgetView(countdown: countdown) } else { VoidView() } case .accessoryCircular: if let countdown = entry.countdowns.first { CountdownSimpleWidgetView(countdown: countdown) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.black) } else { VoidView() } case .accessoryRectangular: if let countdown = entry.countdowns.first { CountdownSimpleWidgetView(countdown: countdown) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.black) .cornerRadius(16.0) } else { VoidView() } default: MultiCountdownView(countdowns: entry.countdowns) // case .systemMedium: GameStatusWithLastTurnResult(gameStatus) // case .systemLarge: GameStatusWithStatistics(gameStatus) // case .systemExtraLarge: GameStatusWithStatisticsExtraLarge(gameStatus) // case .accessoryCircular: HealthLevelCircular(selectedCharacter) // case .accessoryRectangular: HealthLevelRectangular(selectedCharacter) // case .accessoryInline: HealthLevelInline(selectedCharacter) } } } struct LaunchWidget: Widget { let kind: String = "com.staxriver.launch-widget" var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: SelectCountdownIntent.self, provider: Provider()) { entry in LaunchWidgetEntryView(entry: entry) } .configurationDisplayName("Launch Widget") .description("Select and launch your countdowns") .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(countdowns: [fake], date: Date(), configuration: SelectCountdownIntent())) .previewContext(WidgetPreviewContext(family: .systemSmall)) LaunchWidgetEntryView(entry: SimpleEntry(countdowns: [fake, fake, fake, fake], date: Date(), configuration: SelectCountdownIntent())) .previewContext(WidgetPreviewContext(family: .systemMedium)) LaunchWidgetEntryView(entry: SimpleEntry(countdowns: [fake], date: Date(), configuration: SelectCountdownIntent())) .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) } }