diff --git a/KisaniCal.xcodeproj/project.pbxproj b/KisaniCal.xcodeproj/project.pbxproj index 74cd2fd..ded2732 100644 --- a/KisaniCal.xcodeproj/project.pbxproj +++ b/KisaniCal.xcodeproj/project.pbxproj @@ -423,6 +423,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 2; PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal; SDKROOT = iphoneos; SWIFT_VERSION = 5.9; @@ -505,6 +506,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); + MARKETING_VERSION = 2; PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.KisaniCalWidgets; SDKROOT = iphoneos; SWIFT_VERSION = 5.9; @@ -594,6 +596,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); + MARKETING_VERSION = 2; PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.KisaniCalWidgets; SDKROOT = iphoneos; SWIFT_VERSION = 5.9; @@ -627,6 +630,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 2; PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal; SDKROOT = iphoneos; SWIFT_VERSION = 5.9; diff --git a/KisaniCal/ISSUES.md b/KisaniCal/ISSUES.md index a53b745..ff3dc56 100644 --- a/KisaniCal/ISSUES.md +++ b/KisaniCal/ISSUES.md @@ -523,3 +523,30 @@ Files: `ExerciseModels.swift`, `NotificationManager.swift`, `ContentView.swift`, that day now shows the program labeled Compensation (and gets a reminder). 3. Long-press the workout card in Today/Calendar → Done / Not Done / Compensate. 4. Long-press an exercise card in Workout → Mark as Done / Not Done. + +--- + +## KC-17 — Remove Event Countdown (dots) + Tasks Done Today widgets + +**Status:** Resolved (build-verified) +**Reported by:** User +**Area:** Widgets + +### Description +The dot-grid "Event Countdown" and "Tasks Done Today" widgets were judged not up +to standard and removed entirely from the gallery. + +### Removal +- `EventCountdownWidget` struct (kind `KisaniEventCountdown`) + `EventCountdownView`. +- `TasksCompleteWidget` (kind `KisaniTasksComplete`) + `TasksCompleteView` + + its only consumer `todayTaskCompletion()` in WidgetData.swift. +- Both deregistered from `KisaniWidgetBundle`. +- Kept (shared by the surviving bars widget): `EventConfigIntent`, `EventEntity`, + `EventQuery`, `EventProvider`, `EventEntry`, `CycleCountdownUnitIntent`, + `BarGrid`; `DotGrid` kept (used by Day Progress). +- Untouched: Event Countdown (Bars), My Tasks, Day Progress, Lock Screen rect + + circular, Task Live Activity. + +Files modified: `KisaniCalWidgets.swift`, `EventCountdownWidget.swift`, +`WidgetViews.swift`, `WidgetData.swift`. No files deleted (shared code remains +in EventCountdownWidget.swift). No app-side settings referenced these widgets. diff --git a/KisaniCalWidgets/EventCountdownWidget.swift b/KisaniCalWidgets/EventCountdownWidget.swift index dc2e831..e3e52a9 100644 --- a/KisaniCalWidgets/EventCountdownWidget.swift +++ b/KisaniCalWidgets/EventCountdownWidget.swift @@ -252,21 +252,6 @@ struct EventProvider: AppIntentTimelineProvider { } } -// MARK: - Widget - -struct EventCountdownWidget: Widget { - let kind = "KisaniEventCountdown" - - var body: some WidgetConfiguration { - AppIntentConfiguration(kind: kind, intent: EventConfigIntent.self, provider: EventProvider()) { entry in - EventCountdownView(entry: entry) - } - .configurationDisplayName("Event Countdown") - .description("Track the days until any upcoming event with a dot grid.") - .supportedFamilies([.systemMedium, .systemSmall]) - } -} - // MARK: - Event Countdown (Bars) struct EventBarsWidget: Widget { diff --git a/KisaniCalWidgets/KisaniCalWidgets.swift b/KisaniCalWidgets/KisaniCalWidgets.swift index b858023..85e9fd9 100644 --- a/KisaniCalWidgets/KisaniCalWidgets.swift +++ b/KisaniCalWidgets/KisaniCalWidgets.swift @@ -48,20 +48,6 @@ struct DayProgressWidget: Widget { } } -// MARK: - Tasks Done Today Widget ("Tasks complete %") - -struct TasksCompleteWidget: Widget { - let kind = "KisaniTasksComplete" - var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: KisaniProvider()) { _ in - TasksCompleteView() - } - .configurationDisplayName("Tasks Done Today") - .description("Percentage of today's tasks you've completed.") - .supportedFamilies([.systemSmall, .systemMedium]) - } -} - // MARK: - Lock Screen Widgets struct LockScreenWidget: Widget { @@ -105,11 +91,9 @@ struct LockScreenCircularWidget: Widget { @main struct KisaniWidgetBundle: WidgetBundle { var body: some Widget { - EventCountdownWidget() EventBarsWidget() MyTasksWidget() DayProgressWidget() - TasksCompleteWidget() LockScreenWidget() LockScreenCircularWidget() TaskLiveActivity() diff --git a/KisaniCalWidgets/WidgetData.swift b/KisaniCalWidgets/WidgetData.swift index 1d6b83f..befa114 100644 --- a/KisaniCalWidgets/WidgetData.swift +++ b/KisaniCalWidgets/WidgetData.swift @@ -138,21 +138,6 @@ private func CloudSyncManager_widgetPush(_ data: Data, _ key: String) { kv.synchronize() } -// Today's task completion: (done, total) for tasks due today. -func todayTaskCompletion() -> (done: Int, total: Int) { - let cal = Calendar.current - let start = cal.startOfDay(for: Date()) - let end = cal.date(byAdding: .day, value: 1, to: start)! - let tasks = loadWidgetTasks() - func dueToday(_ t: WidgetTask) -> Bool { - guard let due = t.dueDate else { return false } - return due >= start && due < end - } - let active = tasks.filter { !$0.isComplete && dueToday($0) } - let completed = tasks.filter { $0.isComplete && dueToday($0) } - return (completed.count, active.count + completed.count) -} - // Workout streak count func loadWorkoutStreak() -> Int { let uid = UserDefaults.kisani.string(forKey: "kisani.activeUserId") ?? "shared" diff --git a/KisaniCalWidgets/WidgetViews.swift b/KisaniCalWidgets/WidgetViews.swift index f2f5bb2..d51ad19 100644 --- a/KisaniCalWidgets/WidgetViews.swift +++ b/KisaniCalWidgets/WidgetViews.swift @@ -102,52 +102,6 @@ struct ProgressDotView: View { } } -// MARK: - Tasks completed today - -struct TasksCompleteView: View { - @Environment(\.widgetFamily) private var family - private let teal = WidgetTheme.accent - - private var stats: (done: Int, total: Int) { todayTaskCompletion() } - private var percent: Int { - let s = stats - guard s.total > 0 else { return 0 } - return Int((Double(s.done) / Double(s.total) * 100).rounded()) - } - - var body: some View { - let s = stats - let isMedium = family == .systemMedium - VStack(alignment: .leading, spacing: isMedium ? 10 : 6) { - HStack(alignment: .firstTextBaseline) { - Text("Today's Tasks") - .font(.system(size: isMedium ? 22 : 14, weight: .bold)) - .foregroundColor(.white) - .lineLimit(1) - Spacer() - Text("\(percent)%") - .font(.system(size: isMedium ? 22 : 13, weight: .bold)) - .foregroundColor(Color(white: 0.5)) - } - if s.total == 0 { - Spacer(minLength: 0) - Text("No tasks due today") - .font(.system(size: 12)) - .foregroundColor(Color(white: 0.5)) - Spacer(minLength: 0) - } else { - Text("\(s.done) of \(s.total) done") - .font(.system(size: 12)) - .foregroundColor(teal) - Spacer(minLength: 2) - DotGrid(total: s.total, filled: s.done, color: teal) - } - } - .padding(.horizontal, isMedium ? 4 : 0) - .containerBackground(WidgetTheme.background, for: .widget) - } -} - // MARK: - Circular dot grid (event countdown motif) struct DotGrid: View { @@ -205,75 +159,6 @@ struct DotGrid: View { } } -// MARK: - Event Countdown Widget (small + medium) - -struct EventCountdownView: View { - let entry: EventEntry - @Environment(\.widgetFamily) var family - - private let teal = WidgetTheme.accent - - private var percent: Int { Int((entry.progress * 100).rounded()) } - - var body: some View { - Group { - if family == .systemSmall { - small - } else { - medium - } - } - .containerBackground(WidgetTheme.background, for: .widget) - } - - 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, spacing: 8) { - Text(LocalizedStringKey(entry.eventName)) - .font(.system(size: 20, weight: .bold)) - .foregroundColor(teal) - .lineLimit(1) - 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: filled, color: teal) - } - .padding(.horizontal, 4) - } - - private var small: some View { - VStack(alignment: .leading, spacing: 6) { - Text(LocalizedStringKey(entry.eventName)) - .font(.system(size: 14, weight: .bold)) - .foregroundColor(teal) - .lineLimit(2) - 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: filled, color: teal) - } - } -} - // MARK: - Event Countdown — Bars style (medium) struct EventBarsView: View {