Widgets/notifications: tracked-event auto-advance, lock-screen dots, Snooze labels, period milestones

- Bars widget: tracked ("Track Countdown") events now also advance — a completed
  or past (non-recurring) tracked event falls through to the next-nearest, and the
  refresh boundary covers the tracked event's expiry. Recurring tracked events
  still roll forward. Completes the KC-26 auto-advance for all paths.
- Progress Dots on the lock screen (accessoryRectangular): show 28 larger dots
  instead of 100 tiny ones, render with .primary for the vibrant tint, and use
  AccessoryWidgetBackground so it's legible (Home Screen keeps the 100-dot grid).
- Notifications: snooze action labels now read "Snooze 15 min/30 min/1 hour/
  2 hours" (lock screen) and "Snooze 15 Minutes…" (in-app Postpone menu).
- New period milestone notifications: recurring "One more week/month/year passed"
  at end of week (Sun 20:00), month (1st 09:00), and year (Jan 1 09:00); gated by
  a kisani.periodMilestones flag, scheduled via the existing reschedule path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
kutesir
2026-06-16 02:12:52 +03:00
parent 87c999c676
commit 48e2f4fc10
7 changed files with 122 additions and 52 deletions

View File

@@ -77,25 +77,33 @@ struct ProgressDotView: View {
}
}
private var isAccessory: Bool { family == .accessoryRectangular }
// 100 tiny dots are illegible in a lock-screen pill show a coarse grid there.
private var dotCount: Int { isAccessory ? 28 : entry.totalDots }
var body: some View {
let percent = Int((entry.progress * 100).rounded(.down))
VStack(alignment: .leading, spacing: spacing) {
HStack(alignment: .firstTextBaseline) {
Text(entry.title)
.font(headerFont)
.foregroundColor(.white)
.foregroundColor(isAccessory ? .primary : .white)
.lineLimit(1)
.minimumScaleFactor(0.72)
Spacer()
Text("\(percent)%")
.font(headerFont)
.foregroundColor(Color(white: 0.5))
.foregroundColor(isAccessory ? .primary.opacity(0.7) : Color(white: 0.5))
.lineLimit(1)
}
DotGridView(progress: entry.progress, totalDots: entry.totalDots, color: accent)
DotGridView(progress: entry.progress, totalDots: dotCount,
color: isAccessory ? .primary : accent)
}
.padding(.horizontal, horizontalPadding)
.containerBackground(WidgetTheme.background, for: .widget)
.containerBackground(for: .widget) {
if isAccessory { AccessoryWidgetBackground() } else { WidgetTheme.background }
}
}
}