Commit Graph

24 Commits

Author SHA1 Message Date
kutesir
839ac72846 analytics(healthkit): wire historical HealthKit reference into reports (KC-51 ph4e)
Some checks failed
CI / build-and-test (push) Has been cancelled
Completes 'available HealthKit trends' for weekly/monthly reports. Adds
HealthKitManager.dailyReference (3 parallel bucketed HKStatisticsCollectionQuery
for steps/active-calories/resting-HR over ~13 months), AnalyticsService.
refreshHealthReference to cache and merge it into DaySamples, and avgSteps/
avgActiveCalories/avgRestingHR on PeriodSummary (nil when absent — honest).
Surfaced in AnalyticsView's weekly/monthly cards.

Verified standalone (swiftc, 8/8): aggregation correct when present, nil when
absent, workout metrics unaffected, reports stay deterministic. Tests added to
AnalyticsEngineTests. This completes all analytics logic — remaining work is the
first Xcode build (device, user-run) to catch any SwiftUI compile issues.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:39:00 +03:00
kutesir
c56a6a9d21 analytics(deeplink): route report notification tap to its report (KC-51 ph4c)
Some checks failed
CI / build-and-test (push) Has been cancelled
Completes deep-link routing (goal #7): AnalyticsDeepLink is Identifiable; a
tapped weekly/monthly report notification is consumed in ContentView on
launch/active and presents AnalyticsView opened to that area. Core round-trip
re-verified standalone; SwiftUI wiring needs an Xcode build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:36:45 +03:00
kutesir
d25cf9ba80 analytics(app): AnalyticsService + lifecycle reconcile + deep-linked notifications (KC-51 ph4a)
Some checks failed
CI / build-and-test (push) Has been cancelled
Wires the verified analytics core into the app: AnalyticsService feeds live
WorkoutViewModel data into the reconcile coordinator and exposes UI reads;
ContentView reconciles on launch + foreground; NotificationManager fires one
permission-aware, deduped weekly/monthly report notification carrying an
AnalyticsDeepLink, captured on tap for routing.

NOT build-verified (no iOS runtime; app-module/SwiftUI deps). Logged in
ISSUES.md; historical HealthKit reference + user-scheduled notification time are
follow-ups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:05:02 +03:00
kutesir
ad304913e4 Voice: show dictated transcript in the Quick Add field
The mic captured speech and the transcript reached rawText, but it never appeared
in the field. NLTaskField.updateUIView (UITextView representable) returned early
when the field wasn't focused (`guard coordinator.isEditing`), so externally-set
text (voice dictation, the normal not-focused case) was dropped and the
placeholder stayed.

Fix: render non-empty `text` even when not editing, placing the caret at the end;
keep the cursor-preserving fast path while actively editing. No new voice system —
this only fixes the existing mic button's transcript→field binding.

Verified on simulator via the real speech.transcript path: "Buy milk tomorrow" →
field shows it (chip: Tomorrow); "Call Romeo at 11 AM" → field shows it (chip:
Today 11:00). Adds DEBUG-only test hooks KISANI_AUTOADD / KISANI_VOICE_SIM
(compiled out of Release). Logged under KC-38.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 21:22:45 +03:00
kutesir
38db257c4a Calendar: fix weekday-header/week-number alignment to firstWeekday + tests
Root cause: a data-integrity bug, not visual. The month grid is built from
.weekOfMonth (respects Calendar.current.firstWeekday), but the weekday header
was hardcoded Sunday-first ("S M T W T F S") and the week-number label was gated
on isSunday (weekday == 1). On any non-Sunday-first locale (or when the user sets
"Start Week On" = Monday) every column was mislabeled by one and the W-number
landed on the wrong column — e.g. June 1 2026 (a Monday) appearing under "S".

Fix:
- Extract pure, testable date math into CalendarGrid (monthGrid + weekdaySymbols).
- Header now derived from firstWeekday, so it always matches the grid.
- Week-number label gated on isWeekStart (weekday == firstWeekday), not Sunday.
- Document that week numbers are locale weekOfYear (consistent with the layout),
  not ISO.
- gridDays() and the year-view mini-month dedupe to CalendarGrid.

Verification:
- New KisaniCalTests target with 9 tests, all passing on simulator: exact
  Sunday-first June 2026 grid, header↔grid alignment for firstWeekday 1...7,
  cell date identity, month navigation (May/Jul/Feb 2026 + Feb 2028 leap +
  Dec 2026→Jan 2027), and event-day bucketing (all-day, late-night, midnight-
  crossing) across 4 timezones.
- Verified in the running app: header S M T W T F S, May 31 in the Sunday
  column, June 1 under Monday, June 24 (Wednesday) selected.

Adds a DEBUG-only KISANI_INITIAL_TAB launch env (compiled out of Release) used
to screenshot the calendar past the sign-in gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 19:24:49 +03:00
kutesir
81813530c8 Rebrand app to "Wenza" (display name + user-facing copy)
Renames the user-facing app to Wenza without changing identity:
- CFBundleDisplayName → "Wenza" (app) and "Wenza Widgets" (widget extension).
- Calendar/Health permission prompts now reference Wenza.
- In-app copy updated: sidebar title, Auth + Onboarding screens, Settings
  about/help rows, feedback email subject, tutorial text, widget description.

Bundle identifier, App Group, UserDefaults storage keys, team ID, and the
internal Xcode target/project names are intentionally unchanged, so this stays
the same App Store app with no user data loss. App Store listing name must be
changed separately in App Store Connect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:31:51 +03:00
kutesir
443fe8504f Workout check-in: missed state + rest-day compensation (KC-16)
- Notification actions on workout reminders/check-ins: "Yes, I completed
  it", "No, I didn't" (marks the day missed, then asks to compensate on a
  rest day), "Remind me in 1 hour" (snooze).
- VM: missedDates + compensations (persisted/synced), per-date
  markWorkoutDone/Missed, workoutStatus, upcomingRestDays,
  scheduleCompensation, promptCompensation, checkPendingMissed.
  program(for:) returns a compensation program on its rest day.
- CompensationSheet: pick a rest day or keep as missed; compensation days
  get a one-off "Missed workout recovery" reminder.
- Long-press menus: workout row (Done / Not Done / Compensate) in Today +
  Calendar; exercise cards (Mark as Done / Not Done). All actions are
  per-date — one occurrence never affects another.
- Workout row shows Pending / Done / Missed + "Compensation" label.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:06:58 +03:00
kutesir
800c7db76d fix: reset workout log each new day + new app logo
KC-1: Set completion was stored permanently on the program, so the same
program scheduled on back-to-back days (e.g. Shoulders Mon + Tue) kept
yesterday's checkmarks. Add resetSetsForNewDayIfNeeded() to clear every
set's isDone when the calendar day changes (cold launch, onAppear, and
scenePhase active). Streak history is untouched.

KC-2: Replace all 12 AppIcon sizes with the new KisaniCal mark, alpha
flattened onto RGB(26,29,34) so the 1024 App Store icon is fully opaque.

Add KisaniCal/ISSUES.md tracker (KC-1, KC-2: In Progress).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:29:25 +03:00
Robin Kutesa
646cdf6a9b 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>
2026-06-03 13:31:04 +03:00
Robin Kutesa
8b094691f5 feat: home/lock widgets, Health-aware streaks, workout editor, and entitlement fixes
Widgets (new KisaniCalWidgets extension)
- Event Countdown widget: configurable via AppIntent, pick from your events
  or set a custom name/date; dot-grid progress toward the event.
- Day Progress and Tasks-Done-Today widgets; lock screen widgets.
- Shared dot grid sizes circles to fill the widget evenly at any count.
- Tasks/calendar prefs now persist to the App Group so widgets read live data.

Health & streaks
- Persist HealthKit authorization and re-establish on launch (fixes the
  Today dashboard and streak sync disappearing after relaunch).
- Add a Health permission toggle to onboarding; unify Settings/Profile on the
  manager's state.
- Day streak counts from a logged Health workout OR marking all exercises
  complete; nudge to mark exercises complete even when Health logged the workout.

Workout editor
- Drag to reorder exercises and move them across sections (drag-and-drop);
  swipe to delete.
- Add-exercise sheet: global search and keep-adding-multiple with a running count.

Fixes
- Restore app entitlements link (Sign in with Apple, HealthKit, App Group, iCloud).
- Add HealthKit usage strings; widget Info.plist NSExtension + nested bundle id.
- Calendar "Connect" routes to Settings when access was denied.
- Bake DEVELOPMENT_TEAM and shared versions into project.yml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 12:27:45 +03:00
Robin Kutesa
e5bd739499 feat: HealthKit workout sync, confirmation notification, health stats on Today dashboard
- HealthKitManager: add fetchWorkoutDates(from:to:) to read past workouts from Apple Health
- WorkoutViewModel: syncFromHealthKit() merges HealthKit workout dates into streak (runs on every foreground); checkPendingHealthConfirm() picks up confirmed workouts from notification action
- NotificationManager: WORKOUT_CONFIRM category with 'Yes, log it' action; scheduleWorkoutConfirm() fires weekly on scheduled workout days at configurable time (default 8pm); LOG_WORKOUT action writes pendingConfirm to UserDefaults
- SettingsView (Workout Settings): new HEALTH SYNC section with 'Sync now' button and 'Workout confirmation reminder' toggle + time picker
- TodayView: TodayHealthStrip shows steps, active calories, resting HR, and workout streak in a 4-pill row below the date header (only shown when HealthKit is authorized); refreshes on appear and foreground
- FAB: Matrix FAB padding fixed to match Today/Calendar position (.bottom 10)

Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
2026-06-02 13:10:32 +03:00
Robin Kutesa
0647583036 feat: iCloud KV Store sync for tasks, workout data, and settings
- Add NSUbiquitousKeyValueStore entitlement to KisaniCal.entitlements
- New CloudSyncManager: mirrors UserDefaults to iCloud KV Store on every save; restores to UserDefaults on fresh install when local data is missing; observes external changes to pull updates in real-time; guards against 1 MB limit
- TaskViewModel: restore from iCloud on init, push to iCloud on every save
- WorkoutViewModel: restore programs/schedule/activePid/completedDates from iCloud on init, push all four keys on every save
- ContentView: restoreSettings() + backupSettings() on appear and foreground — syncs ~18 small settings keys (appearance, tabs, tutorial flags, calendar prefs, workout notifications)

Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
2026-06-01 20:45:26 +03:00
Robin Kutesa
0c48ca888b Fix: tapping task notification now marks it complete
Tap body → marks complete + navigates to tasks.
Swipe action 'Mark Complete' → marks complete without opening app.
TaskViewModel.reload() called on foreground to sync UserDefaults changes
made while app was backgrounded.

Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
2026-06-01 03:52:10 +03:00
Robin Kutesa
8f8825ac04 Add tooltip coach mark tutorial for new users
- TutorialManager: tracks 4 steps (NLP, Calendar, Matrix, Workout)
  persisted via AppStorage; shown once then never again
- TutorialView: fullscreen overlay with even-odd spotlight cutout,
  animated accent border, ultraThinMaterial callout card, pill progress
  dots, Next/Get started button, and Skip
- TutorialFrameKey: PreferenceKey collects CGRect for each anchor index;
  .tutorialAnchor() modifier wired to FAB (step 0) and all 4 tab buttons
- Callout auto-positions above or below the spotlight based on screen half
- ContentView collects frames via onPreferenceChange and layers the overlay

Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
2026-06-01 02:23:12 +03:00
Robin Kutesa
68efa02803 feat: floating tab bar, NLP date parsing, and task date picker
- 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>
2026-05-30 23:49:30 +03:00
kutesir
cab5c4ef05 feat: home screen quick actions (long press app icon)
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.
2026-05-30 02:38:15 +03:00
kutesir
875f562801 Add profile stats sheet with task and workout analytics
Tapping the profile card opens a full stats sheet showing:
Tasks — completed this week, overdue count, done rate, 7-day bar
chart, open count by Eisenhower quadrant.
Workouts — streak, sets today, today % progress, weekly schedule
grid (dumbbell = scheduled, checkmark = done), active program summary.
2026-05-29 12:06:34 +03:00
kutesir
b6c90a4177 Fix FloatingTabState crash + landscape layout on iPhone
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.
2026-05-29 11:01:58 +03:00
kutesir
28f8b4a0f1 Remove widget extension
Delete KisaniCalWidget target, Shared/WidgetDataStore, WidgetBridge,
App Group entitlements, and all syncWidget() calls.
2026-05-29 10:36:39 +03:00
kutesir
1d4d7f07c5 Add task persistence and per-task reminder notifications
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.
2026-05-29 10:33:55 +03:00
kutesir
dc99a3f1f0 fix: widget iOS 17 deployment target + register FloatingTabState
- 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)
2026-05-28 20:35:44 +03:00
kutesir
5e232f2d81 feat: add widget extension — small, medium, large
- 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
2026-05-28 19:48:01 +03:00
kutesir
d7ec351dd4 fix(layout): fix rotation crash and improve iPad split view
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.
2026-05-27 14:01:34 +03:00
kutesir
f67429de0b Initial commit: KisaniCal iOS app
Task management, Eisenhower matrix, workout logging with persistence,
and calendar with 6 view modes (Month, List, Year, Week, 3 Day, Day).
Custom floating tab bar, dynamic calendar icon, and workout data seeded.
2026-05-27 02:09:44 +03:00