import WidgetKit import SwiftUI struct TaskEntry: TimelineEntry { let date: Date let tasks: [TaskItem] } struct TaskProvider: TimelineProvider { func placeholder(in context: Context) -> TaskEntry { TaskEntry(date: .now, tasks: [TaskItem(title: "Plan the next task")]) } func getSnapshot(in context: Context, completion: @escaping (TaskEntry) -> Void) { completion(TaskEntry(date: .now, tasks: openTasks())) } func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { let entry = TaskEntry(date: .now, tasks: openTasks()) let refresh = Calendar.current.date(byAdding: .minute, value: 15, to: .now)! completion(Timeline(entries: [entry], policy: .after(refresh))) } private func openTasks() -> [TaskItem] { TaskStore.loadTasks().filter { $0.list != .done } } } struct UTrelloTasksWidget: Widget { let kind = "UTrelloTasksWidget" var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: TaskProvider()) { entry in TaskWidgetView(entry: entry) } .configurationDisplayName("UTrello Tasks") .description("Your unfinished tasks at a glance.") .supportedFamilies([.systemSmall, .systemMedium, .systemLarge]) } } private struct TaskWidgetView: View { let entry: TaskEntry var body: some View { VStack(alignment: .leading, spacing: 8) { Text("My tasks") .font(.headline) if entry.tasks.isEmpty { Spacer() Text("All caught up") .foregroundStyle(.secondary) Spacer() } else { ForEach(entry.tasks.prefix(4)) { task in Label(task.title, systemImage: task.list == .doing ? "play.circle" : "circle") .lineLimit(1) } } Spacer(minLength: 0) Text("\(entry.tasks.count) open") .font(.caption) .foregroundStyle(.secondary) } .containerBackground(for: .widget) { Color.clear } } }