- Remove @MainActor from class (caused all Sendable/isolation cascade)
- Keep @MainActor only on reschedule() where VM access is needed
- Snapshot tasks in reschedule() so scheduleTasks() never captures
a non-Sendable TaskViewModel across async boundaries
- Capture center locally in scheduleTasks() to avoid @MainActor
property access inside the @Sendable getPendingNotificationRequests callback
- Mark UNUserNotificationCenterDelegate methods nonisolated to satisfy
protocol conformance without actor crossing
Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
Snapshot WorkoutViewModel's schedule/programs/progress before the
async getNotificationSettings callback so scheduleWorkout receives
plain value types instead of MainActor-isolated properties.
Also fix unused-mutation warning: email in handleApple changed to let.
Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
Profile header and ProfileStatsSheet now read displayName and email
from AuthManager.shared instead of hardcoded "Robin Kutesa" / "RK".
Initials are computed dynamically from the user's display name.
Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
- Remove leftover Self. prefix on instance storage keys in save()
- Mark TaskViewModel and WorkoutViewModel @MainActor so init() can
safely access AuthManager.shared without isolation violations
Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
- Remove all personal sampleTasks from TaskViewModel (tasks start empty)
- Namespace UserDefaults keys by Apple ID for task and workout data isolation
- Add ProfileSetupView for name capture after first Sign in with Apple
- Add updateDisplayName() to AuthManager
- Route to ProfileSetupView when user has no display name yet
Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
- Tab bar: TickTick-style floating pill (cornerRadius 28, shadow, systemGray5 active highlight)
- NLP: month+day parsing (8th June, June 8), recurrence (every year/week/etc), intent stripping (remind me of)
- Recurrence chip in add-task toolbar; isRecurring saved with task
- Date chip defaults to Today on new tasks; tapping opens full date picker
- Date picker: calendar grid, inline time wheel, Repeat menu (Date tab)
- Duration tab: Start/End column selector, live duration counter, All Day toggle
- TaskItem: added endDate and isAllDay fields
- Fixed hidden Unicode character corrupting + operator in TodayView
Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
Default view shows the next 5 upcoming tasks. If more exist, a
"N more ↓" button expands the full list; tapping again collapses
back to 5. The section header is tappable to fully hide the list
(only title + count badge remain visible). Collapsed state is
persisted via @AppStorage so it survives app restarts.
Adds four UIApplicationShortcutItems registered dynamically at launch:
• Add Task — opens the add-task sheet immediately, any tab
• Today — switches to the Today tab
• Calendar — switches to the Calendar tab
• Workout — switches to the Workout tab (only registered if the
workout tab is enabled in settings; re-registers when the setting changes)
Cold-launch and foreground-activation paths both handled via AppDelegate.
ShortcutHandler singleton bridges UIKit callbacks to SwiftUI via @Published.
Selected-day panel below the month grid now renders as a proper vertical
timeline: time labels in the left gutter, continuous track line with
circle markers, and white cards for each item. All-day tasks and events
get a stroke circle; timed entries get a solid colored dot; workout gets
a dumbbell icon; completed items show a checkmark circle with strikethrough.
Tasks can be toggled directly from the timeline card. Cal events show
end time as subtitle. Empty state shows a calendar icon.
DotGridProgress replaced GeometryReader + 200+ Circle view nodes with a
single Canvas draw call. Canvas receives its own size parameter so no
GeometryReader is needed; SwiftUI interpolates the progress value through
the .animation modifier for smooth fill transitions.
FloatingTabState ScrollYKey made private to TabBarScrollModifier to limit
its PreferenceKey scope and prevent unintended propagation across unrelated
subtrees.
Replace ProgressRingCard in WorkoutView with DotProgressCard using the
same dot grid as the workout session sheet. Remove private from DotRow
so it's accessible across view files.
iOS auto-snaps to the next larger detent when keyboard appears over a
text field. Removing .large locks the sheet to .height(150) so it
stays compact and hugs the keyboard like the reference app.
Also removed the Description label and reduced input maxHeight to 72pt
so all content fits within the 150pt detent.
Use UIDevice.userInterfaceIdiom instead of hSizeClass so large iPhones
in landscape keep the iPhone layout. Move tabState environmentObject to
the top-level Group so both layouts always have it in scope.
Tasks now survive app restarts via UserDefaults JSON. Each task with a
due time fires a notification at that exact time; date-only tasks fire
at 9am on the due date. Completing or deleting a task cancels its
pending notification. ContentView now reschedules on any task change.
- Widget extension: 16.0 → 17.0 (containerBackground/widget API require 17)
- xcodegen re-run picks up FloatingTabState.swift (was on disk but
not registered in project.pbxproj after previous xcodegen run)
- KisaniCalWidget: 3 sizes sharing the app's design language
Small: date badge + kisaniCAL. wordmark + task count
Medium: badge + task list (3 items) + workout row
Large: badge + full task list (6 items) + workout row
- WidgetDataStore (Shared/): lightweight Codable types for App Group
UserDefaults cross-process data exchange
- WidgetBridge: TaskViewModel/WorkoutViewModel extensions that sync
data into App Group and call WidgetCenter.reloadAllTimelines()
- ContentView: calls syncWidget() on appear and scene becoming active
- project.yml + entitlements updated; project regenerated via xcodegen
7 rows of dots fill left-to-right, top-to-bottom as sets complete.
Filled dots: AppColors.green solid. Empty: green at 12% opacity.
Also: strip emoji from completion banner, tighten copy.
Sheet was 500pt tall with ~145pt of content, leaving ~355pt blank.
Dropping to height(150) makes the sheet hug its content and sit flush
above the keyboard like the reference design.
Break SplashCalendarCard body into monthHeader/weekdayRow/dayGrid
computed vars and extract SplashWeekRow to help the type-checker.
Rename DayCell -> SplashDayCell to avoid collision with CalendarView.
Using self.programs on the RHS of activeSections assignment violated
Swift's two-phase init rule (self is partially initialized). Use local
`migrated` array instead, then assign programs and activeSections in
the correct order.
Replace the emoji tile on CalendarWorkoutBlock and WorkoutSessionSheet
header with WorkoutSectionBar — a stack of N horizontal segments, one
per workout section. No emojis, no custom per-program images.
UserDefaults retained the old 🔥/💥 emojis from before the sample data
was cleaned. On init, replace those emojis in loaded programs and persist
the result so they don't reappear after restart.
WorkoutTodayBanner: progress ring replaces emoji cell as the lead
visual. Card background is now surface/border, not blue-tinted.
StreakBannerView: strip gradient, dot trail, and "Don't break the
chain". Replace with clean number + 7-tick week bar.
ProgressRingCard: "Keep going 🔥" / "Workout complete! 🎉" removed;
replaced with "N sets remaining" / "All sets done".
Sample programs: 🔥 Shoulders & Arms -> 🔄, 💥 Full Body -> 🏋️.
Emoji picker: 🔥 replaced with 🫀 (heart/cardio) as last option.
Replace full-form AddTaskSheet with a compact NL input sheet.
Type "meeting today at 1500" — the words "today" and "at 1500"
highlight inline in blue, the toolbar shows "Today, 15:00", and
the mic button becomes a submit arrow when the title is non-empty.
Parser handles: today/tomorrow, weekday names (mon–sun),
times as at 3pm / at 15:00 / at 1500 / 3:30pm.
Clean title strips the date tokens before saving.
Sheet uses height(500) detent so it floats above the keyboard.
iPadLayout was rendering TodayView without workoutVM, crashing with
a fatal EnvironmentObject error on any device where hSizeClass goes
.regular (iPad, iPhone Plus/Max in landscape). Rewrote to use proper
NavigationSplitView with List(selection:) driving the detail column.
Also caches calendarIcon as a static func + @State instead of
recomputing UIGraphicsImageRenderer on every body evaluation.