feat: My Tasks widget, event countdown redesign, completed section

- My Tasks widget: today's tasks with interactive check-off (ToggleTaskIntent)
  and a "+" that opens the app's add-task sheet; writes preserve all task
  fields and sync via the App Group.
- Event Countdown: AZURE/AWS-style header (accent name + countdown label +
  percent); tap the label to cycle days → weeks → time remaining.
- Today: collapsible "Completed" archive section below Upcoming.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Robin Kutesa
2026-06-03 13:31:04 +03:00
parent 8b094691f5
commit 646cdf6a9b
10 changed files with 386 additions and 44 deletions

View File

@@ -191,22 +191,31 @@ struct EventCountdownView: View {
.containerBackground(.black, for: .widget)
}
// Wide layout that mirrors the reference: title + percent, then a dot grid.
private var filled: Int { Int(entry.progress * Double(entry.totalDays)) }
// Wide layout: event name + days-left countdown, then the dot-grid progress.
private var medium: some View {
VStack(alignment: .leading, spacing: 10) {
HStack(alignment: .firstTextBaseline) {
HStack(alignment: .firstTextBaseline, spacing: 8) {
Text(LocalizedStringKey(entry.eventName))
.font(.system(size: 22, weight: .bold))
.foregroundColor(.white)
.font(.system(size: 20, weight: .bold))
.foregroundColor(teal)
.lineLimit(1)
Spacer()
Text("\(percent)%")
.font(.system(size: 22, weight: .bold))
.foregroundColor(Color(white: 0.5))
Spacer(minLength: 4)
VStack(alignment: .trailing, spacing: 1) {
Button(intent: CycleCountdownUnitIntent()) {
Text(entry.timeLeftLabel)
.font(.system(size: 14, weight: .semibold))
.foregroundColor(Color(white: 0.62))
.lineLimit(1)
}
.buttonStyle(.plain)
Text("\(percent)%")
.font(.system(size: 11, weight: .bold))
.foregroundColor(Color(white: 0.4))
}
}
DotGrid(total: entry.totalDays,
filled: Int(entry.progress * Double(entry.totalDays)),
color: teal)
DotGrid(total: entry.totalDays, filled: filled, color: teal)
}
.padding(.horizontal, 4)
}
@@ -215,20 +224,17 @@ struct EventCountdownView: View {
VStack(alignment: .leading, spacing: 6) {
Text(LocalizedStringKey(entry.eventName))
.font(.system(size: 14, weight: .bold))
.foregroundColor(.white)
.foregroundColor(teal)
.lineLimit(2)
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text("\(entry.daysLeft)")
.font(.system(size: 28, weight: .bold, design: .rounded))
.foregroundColor(teal)
Text(entry.daysLeft == 1 ? "day" : "days")
.font(.system(size: 12))
.foregroundColor(Color(white: 0.5))
Button(intent: CycleCountdownUnitIntent()) {
Text(entry.timeLeftLabel)
.font(.system(size: 12, weight: .semibold))
.foregroundColor(Color(white: 0.62))
.lineLimit(1)
}
.buttonStyle(.plain)
Spacer(minLength: 2)
DotGrid(total: entry.totalDays,
filled: Int(entry.progress * Double(entry.totalDays)),
color: teal)
DotGrid(total: entry.totalDays, filled: filled, color: teal)
}
}
}