Widgets: remove Event Countdown (dots) + Tasks Done Today (KC-17)
Drop the dot-grid EventCountdownWidget and TasksCompleteWidget from the gallery: widget structs, their views, the todayTaskCompletion() helper (only consumer), and bundle registrations. Shared event plumbing (EventConfigIntent/Provider/Entry, CycleCountdownUnitIntent) stays for the surviving Event Countdown (Bars); DotGrid stays for Day Progress. Remaining widgets untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -423,6 +423,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal;
|
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_VERSION = 5.9;
|
SWIFT_VERSION = 5.9;
|
||||||
@@ -505,6 +506,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.KisaniCalWidgets;
|
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.KisaniCalWidgets;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_VERSION = 5.9;
|
SWIFT_VERSION = 5.9;
|
||||||
@@ -594,6 +596,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.KisaniCalWidgets;
|
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.KisaniCalWidgets;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_VERSION = 5.9;
|
SWIFT_VERSION = 5.9;
|
||||||
@@ -627,6 +630,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal;
|
PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_VERSION = 5.9;
|
SWIFT_VERSION = 5.9;
|
||||||
|
|||||||
@@ -523,3 +523,30 @@ Files: `ExerciseModels.swift`, `NotificationManager.swift`, `ContentView.swift`,
|
|||||||
that day now shows the program labeled Compensation (and gets a reminder).
|
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.
|
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.
|
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.
|
||||||
|
|||||||
@@ -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)
|
// MARK: - Event Countdown (Bars)
|
||||||
|
|
||||||
struct EventBarsWidget: Widget {
|
struct EventBarsWidget: Widget {
|
||||||
|
|||||||
@@ -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
|
// MARK: - Lock Screen Widgets
|
||||||
|
|
||||||
struct LockScreenWidget: Widget {
|
struct LockScreenWidget: Widget {
|
||||||
@@ -105,11 +91,9 @@ struct LockScreenCircularWidget: Widget {
|
|||||||
@main
|
@main
|
||||||
struct KisaniWidgetBundle: WidgetBundle {
|
struct KisaniWidgetBundle: WidgetBundle {
|
||||||
var body: some Widget {
|
var body: some Widget {
|
||||||
EventCountdownWidget()
|
|
||||||
EventBarsWidget()
|
EventBarsWidget()
|
||||||
MyTasksWidget()
|
MyTasksWidget()
|
||||||
DayProgressWidget()
|
DayProgressWidget()
|
||||||
TasksCompleteWidget()
|
|
||||||
LockScreenWidget()
|
LockScreenWidget()
|
||||||
LockScreenCircularWidget()
|
LockScreenCircularWidget()
|
||||||
TaskLiveActivity()
|
TaskLiveActivity()
|
||||||
|
|||||||
@@ -138,21 +138,6 @@ private func CloudSyncManager_widgetPush(_ data: Data, _ key: String) {
|
|||||||
kv.synchronize()
|
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
|
// Workout streak count
|
||||||
func loadWorkoutStreak() -> Int {
|
func loadWorkoutStreak() -> Int {
|
||||||
let uid = UserDefaults.kisani.string(forKey: "kisani.activeUserId") ?? "shared"
|
let uid = UserDefaults.kisani.string(forKey: "kisani.activeUserId") ?? "shared"
|
||||||
|
|||||||
@@ -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)
|
// MARK: - Circular dot grid (event countdown motif)
|
||||||
|
|
||||||
struct DotGrid: View {
|
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)
|
// MARK: - Event Countdown — Bars style (medium)
|
||||||
|
|
||||||
struct EventBarsView: View {
|
struct EventBarsView: View {
|
||||||
|
|||||||
Reference in New Issue
Block a user