Commit Graph

280 Commits

Author SHA1 Message Date
Trey t
bfa172de38 update icon shit 2026-01-21 18:07:13 -06:00
Trey t
e1d84ac769 feat(ui): apply animated background to all screens via themedBackground modifier
Extract AnimatedSportsBackground components to shared file and update
ThemedBackground modifier to conditionally show animations when enabled
in settings. All views using .themedBackground() now get animated background.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 18:06:58 -06:00
Trey t
3a135743f8 add in icon pxd file 2026-01-21 17:59:20 -06:00
Trey t
d97dec44b2 fix(planning): gameFirst mode now uses full date range and shows correct month
Two bugs fixed in "By Games" trip planning mode:

1. Calendar navigation: DateRangePicker now navigates to the selected
   game's month when startDate changes externally, instead of staying
   on the current month.

2. Date range calculation: Fixed race condition where date range was
   calculated before games were loaded. Now updateDateRangeForSelectedGames()
   is called after loadSummaryGames() completes.

3. Bonus games: planTrip() now uses the UI-selected 7-day date range
   instead of overriding it with just the anchor game dates. This allows
   ScenarioBPlanner to find additional games within the trip window.

Added regression tests to verify gameFirst mode includes bonus games.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 16:37:19 -06:00
Trey t
4d097883a6 fix(data): add timezone handling for Sports-Reference scrapers and new stadiums
- Add ET timezone (America/New_York) to all Sports-Reference scrapers:
  - NBA: Basketball-Reference times parsed as ET
  - NFL: Pro-Football-Reference times parsed as ET
  - NHL: Hockey-Reference times parsed as ET
  - MLB: Baseball-Reference times parsed as ET
- Document source timezones in scraper docstrings
- Add 11 new stadiums to STADIUM_MAPPINGS:
  - NFL: 5 international venues (Corinthians Arena, Croke Park,
    Olympic Stadium Berlin, Santiago Bernabéu, Tom Benson Hall of Fame)
  - MLS: 4 alternate venues (Miami Freedom Park, Citi Field,
    LA Memorial Coliseum, M&T Bank Stadium)
  - NWSL: 2 alternate venues (Northwestern Medicine Field, ONE Spokane)
- Add 15 stadium aliases for MLS/NWSL team-based lookups
- Fix CanonicalSyncService to sync timezone identifier to SwiftData
- Update debug logging to use stadium timezone for display

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 16:04:45 -06:00
Trey t
b339a53db3 fix(data): add correct timezone values to all stadiums in STADIUM_MAPPINGS
- Added explicit timezones for ~100 stadiums that were defaulting to America/New_York
- Coverage by timezone:
  - America/Chicago: TX, IL, MO, MN, WI, OK, TN, LA stadiums
  - America/Los_Angeles: CA, WA, OR, NV stadiums
  - America/Denver: CO, UT stadiums
  - America/Phoenix: AZ stadiums (no DST)
  - America/Toronto: ON, QC stadiums
  - America/Vancouver: BC stadiums
  - America/Edmonton: AB stadiums
  - America/Winnipeg: MB stadiums
- All 7 sports leagues now have correct timezone data for scrapers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 23:01:59 -06:00
Trey t
12ddca4d10 fix(data): populate stadium timezone in scrapers and CloudKit sync
Stadium timezones were always null because scrapers weren't passing
the timezone from STADIUM_MAPPINGS to the Stadium constructor. This
fix propagates timezone data through the entire pipeline: scrapers,
CloudKit uploader, and Swift CloudKit model.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 22:45:30 -06:00
Trey t
166ad5d6f9 fix(display): use stadium timezone for all game time displays
Game times were incorrectly using device timezone in several views.
Now all game time displays use the stadium's local timezone via
RichGame.localGameTime/localGameTimeShort properties.

Fixes:
- PDFGenerator: was using game.gameDate (midnight UTC) instead of actual time
- GameRowCompact: was formatting with device timezone
- TimelineGameRow: was using .formatted() with device timezone

Also adds Date+GameTime.swift extension for centralized timezone formatting.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 22:44:40 -06:00
Trey t
74fd21590b wip 2026-01-20 22:26:48 -06:00
Trey t
87079b434d fix(schedule): use start of day for date range queries
- Fix startDate to use Calendar.startOfDay instead of Date() to include
  games earlier in the current day
- Add SyncLogger for file-based sync logging viewable in Settings
- Add "View Sync Logs" button in Settings debug section
- Add diagnostics and NBA game logging to ScheduleViewModel
- Add dropped game logging to DataProvider.filterRichGames
- Use SyncLogger in SportsTimeApp and CloudKitService for sync operations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 22:25:44 -06:00
Trey t
8ea3e6112a feat(scripts): complete data pipeline remediation
Scripts changes:
- Add WNBA abbreviation aliases to team_resolver.py
- Fix NHL stadium coordinates in stadium_resolver.py
- Add validate_aliases.py script for orphan detection
- Update scrapers with improved error handling
- Add DATA_AUDIT.md and REMEDIATION_PLAN.md documentation
- Update alias JSON files with new mappings

iOS bundle updates:
- Update games_canonical.json with latest scraped data
- Update teams_canonical.json and stadiums_canonical.json
- Sync alias files with Scripts versions

All 5 remediation phases complete.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 18:58:47 -06:00
Trey t
51419fccf2 feat(debug): add per-entity CloudKit sync status in Settings
Add debug-only sync status monitoring to help diagnose CloudKit sync issues.
Shows last sync time, success/failure, and record counts for each entity type.
Includes manual sync trigger and re-enable button when sync is paused.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 13:12:56 -06:00
Trey t
c49206bb7c wip 2026-01-20 12:25:00 -06:00
Trey t
fbfdf136ae wip 2026-01-20 11:16:20 -06:00
Trey t
11adfc10dd wip 2026-01-19 23:53:37 -06:00
Trey t
19dd1791f1 wip 2026-01-19 23:21:33 -06:00
Trey t
6cddf601e3 wip 2026-01-19 22:52:42 -06:00
Trey t
a8b0491571 wip 2026-01-19 22:12:53 -06:00
Trey t
11c0ae70d2 docs(scripts): add comprehensive README for data scraping pipeline
Documents the complete sportstime_parser package including architecture,
multi-source scraping, name normalization with aliases, CloudKit uploads,
and workflows for manual review and adding new sports.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 13:22:33 -06:00
Trey t
1355c94236 feat(home): restore planning tips and add map buttons to itinerary rows
- Create shared TipsSection component for displaying planning tips
- Add TipsSection to all 22 home content variants
- Fix displayedTips population with onAppear in HomeView
- Add map buttons to GameRowCompact (opens stadium in Apple Maps)
- Add map buttons to TravelRowView (opens driving directions)
- Add map buttons to CustomItemRowView (opens location when GPS available)
- Add AppleMapsLauncher.openLocation() and openDirections() methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 13:02:17 -06:00
Trey t
0e7fcb65fc fix(pdf): include all trip days in PDF export
Fixed PDF export missing the last day when games occur on departure date.

Root cause: Trip.itineraryDays() calculated lastActivityDate as departure - 1,
assuming departure is always after the last activity. When games happen ON the
departure date, that day was skipped.

Fix: Check if the last stop has games. If so, include the departure date in
the itinerary loop.

Also includes:
- buildCompleteItineraryItems() to merge games, travel, and custom items
- Magazine-style PDF layout with sport-specific accent colors
- Proper iteration over all trip days in PDF generator

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 11:47:25 -06:00
Trey t
239d22a872 feat(trip): add Open in Apple Maps button to trip detail map
- Add floating action button (bottom-right) on trip map
- Create AppleMapsLauncher service to handle route opening
- Collect all routable stops (trip stops + custom items with coords)
- Handle >16 waypoints with alert offering to open in parts
- Silently skip stops without coordinates

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:59:53 -06:00
Trey t
1b0abe2cc1 feat(trip): redesign add custom item UI with polished visuals
Replace confusing dual-mode AddItemSheet with streamlined QuickAddItemSheet:
- Single flow with optional location (vs Search/Custom toggle)
- Card-based layout with shadows, borders, and theme colors
- Enhanced CategoryPicker with emoji circles and press animations
- Separate PlaceSearchSheet for focused location search
- Improved header button with capsule style and accessibility labels

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:49:13 -06:00
Trey t
e72da7c5a7 fix(itinerary): add city to game items for proper constraint validation
Travel constraint validation was not working because ItineraryConstraints
had no game items to validate against - games came from RichGame objects
but were never converted to ItineraryItem for constraint checking.

Changes:
- Add city parameter to ItemKind.game enum case
- Create game ItineraryItems from RichGame data in buildItineraryData()
- Update isValidTravelPosition to compare against actual game sortOrders
- Fix tests to use appropriate game sortOrder conventions

Now travel is properly constrained to appear before arrival city games
and after departure city games.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:46:40 -06:00
Trey t
72447c61fe refactor(itinerary): extract reordering logic into pure functions
Extract all itinerary reordering logic from ItineraryTableViewController into
ItineraryReorderingLogic.swift for testability. Key changes:

- Add flattenDays, dayNumber, travelRow, simulateMove pure functions
- Add calculateSortOrder with proper region classification (before/after games)
- Add computeValidDestinationRowsProposed with simulation+validation pattern
- Add coordinate space conversion helpers (proposedToOriginal, originalToProposed)
- Fix DragZones coordinate space mismatch (was mixing proposed/original indices)
- Add comprehensive documentation of coordinate space conventions

Test coverage includes:
- Row flattening order and semantic travel model
- Sort order calculation for before/after games regions
- Travel constraints validation
- DragZones coordinate space correctness
- Coordinate conversion helpers
- Edge cases (empty days, multi-day trips)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 20:04:52 -06:00
Trey t
143b364553 wip 2026-01-18 12:32:58 -06:00
Trey t
cd1666e7d1 not working, claude is ass 2026-01-17 23:23:22 -06:00
Trey t
64e54b3b11 fix: improve debounce task cancellation handling
- Add cancelPendingSync() method for explicit cleanup
- Use [weak self] capture to prevent potential retain issues
- Check Task.isCancelled before and after sleep
- Catch CancellationError from Task.sleep for immediate cancellation response
- Extract debounceInterval as constant

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 22:19:55 -06:00
Trey t
aa18ed13d7 test: remove legacy CustomItineraryItemTests
Test file for removed CustomItineraryItem model.
All 869 tests pass after itinerary refactor.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 22:14:46 -06:00
Trey t
e79f29d9c7 feat(export): respect custom itinerary order in PDF export
Update PDFGenerator to accept optional ItineraryItem array and render
items in user-specified sortOrder within each day. Adds support for:
- Custom items with icon, title, time, and address
- Travel segments from ItineraryItem (not just TravelSegment)
- Fallback to derived order when no itinerary items provided

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 22:07:06 -06:00
Trey t
9c40721af0 feat(itinerary): add constraint-aware drag and drop with visual feedback
- Add constraint validation during drag using ItineraryConstraints
- Calculate invalid zones and barrier games when drag starts
- Apply visual dimming (alpha 0.3) to invalid drop zones during drag
- Highlight barrier games with gold border when dragging travel segments
- Block invalid drops using ItineraryConstraints.isValidPosition validation
- Add haptic feedback for drag interactions:
  - Medium impact on pickup
  - Light impact when entering valid zone
  - Warning notification when entering invalid zone
  - Soft impact on drop

The drag state is tracked via draggingItem, invalidRowIndices, and
barrierGameIds properties. Visual feedback is applied and removed
via applyDragVisualFeedback/removeDragVisualFeedback methods.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:59:57 -06:00
Trey t
cd00384010 refactor(itinerary): replace CustomItineraryItem with ItineraryItem across codebase
- Update CKModels.swift to remove deleted type references
- Migrate LocalCustomItem to LocalItineraryItem in SavedTrip.swift
- Update AppDelegate to handle subscription removal
- Refactor AddItemSheet to create ItineraryItem with CustomInfo
- Update ItineraryTableViewController and Wrapper for new model
- Refactor TripDetailView state, methods and callbacks
- Fix TripMapView to display custom items with new model structure

This completes the migration from the legacy CustomItineraryItem/TravelDayOverride
model to the unified ItineraryItem model with ItemKind enum.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:51:32 -06:00
Trey t
b008af1c71 refactor(itinerary): consolidate duplicate optional unwrapping in CustomItemRow 2026-01-17 21:34:18 -06:00
Trey t
3a4b9f23e8 fix(itinerary): add empty state and single-line date format to DayHeaderRow
- Add isEmpty parameter to show "No items yet, tap + to add" text
- Change date format to single line: "Day 1 - Friday, January 17"
- Update preview to test both empty and non-empty states

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:32:18 -06:00
Trey t
7700104597 feat(itinerary): add row views for itinerary items
Add specialized row components for the new unified itinerary system:
- DayHeaderRow: Day number, date display, and add item button
- GameItemRow: Prominent card with sport color bar for games
- TravelItemRow: Gold-styled travel segments with drag handle
- CustomItemRow: Minimal custom items with icon, title, and optional time

All views follow existing Theme patterns and use SportColorBar for consistency.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:28:11 -06:00
Trey t
af2a5cd204 chore: remove legacy itinerary models and services
Removed:
- CustomItineraryItem
- TravelDayOverride
- CustomItemService
- CustomItemSubscriptionService
- TravelOverrideService
- CustomItemRow

These are replaced by unified ItineraryItem model and service.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:24:47 -06:00
Trey t
cae24efa90 feat: add ItineraryItemService with CloudKit sync
Debounced updates (1.5s), local-first with silent retry.
Supports game, travel, and custom item kinds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:23:01 -06:00
Trey t
12c2de8a1b feat: add ItineraryConstraints with full test coverage
Validates travel positions based on game locations:
- Travel must be after ALL departure city games
- Travel must be before ALL arrival city games
- Custom items have no constraints
- Games are fixed (cannot be moved)

12 tests covering all constraint scenarios including edge cases.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:14:02 -06:00
Trey t
d14976812a feat: add unified ItineraryItem model
Replaces CustomItineraryItem and TravelDayOverride with single model.
Supports game, travel, and custom item kinds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 20:57:56 -06:00
Trey t
49aaba0594 chore: add .worktrees to gitignore
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 20:31:33 -06:00
Trey t
05a3efd9c8 docs: comprehensive itinerary reorder refactor design
Complete design for TripDetailView refactor with constrained drag-and-drop:
- Games are fixed anchors (immovable, ordered by time)
- Travel is movable with hard constraints (after departure games, before arrival games)
- Custom items are freely movable anywhere

Key decisions from 100-question brainstorming session:
- Unified ItineraryItem model (replaces CustomItineraryItem + TravelDayOverride)
- Separate testable ItineraryConstraints type
- Full structure stored (not derived)
- Debounced sync, local-first, last-write-wins
- Invalid zones dim during drag, barrier games highlight
- Gap opens at drop position, haptic feedback throughout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 20:29:28 -06:00
Trey t
c82029abe7 docs: add itinerary reorder refactor design
Unified data model approach:
- Single ItineraryItem type (travel becomes a category)
- Constraint validation layer for travel rules
- Red zone visual feedback for invalid drops
- Simplified flattening logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 17:20:34 -06:00
Trey t
828059a12a docs: add flexible itinerary ordering implementation plan
13-task plan covering:
- TravelDayOverride model update with sortOrder
- CloudKit schema update
- Flattening logic to sort games/travel/custom together
- Drag constraint updates for flexible custom items
- Regression tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 11:07:58 -06:00
Trey t
6e9b9f728b docs: add flexible itinerary ordering design
Design for fully customizable item ordering in trip itineraries:
- Custom items can go anywhere (before/after games, any day)
- Travel constrained to valid day range but freely positioned within days
- Games get sortOrder for positioning but remain immovable
- TravelPosition stored in SwiftData, synced to CloudKit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 11:01:16 -06:00
Trey t
c658d5f9f4 refactor(itinerary): embed Add button in day header row
Merge Add button into DaySectionHeaderView to prevent items from being
dragged between the day header and Add button. The Add button now uses
a SwiftUI Button with its own tap handler instead of row selection.

Changes:
- Remove .addButton case from ItineraryRowItem enum
- Update DaySectionHeaderView to include Add button on the right
- Pass onAddTapped callback through configureDayHeaderCell
- Remove AddButtonRowView (no longer needed)
- Update documentation to reflect new row structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 10:13:03 -06:00
Trey t
f84addb39d feat(itinerary): reorder Add button after day header + comprehensive docs
- Move Add button to appear immediately after Day header (before games)
- Split games out of dayHeader into separate row for correct ordering
- Add 600+ lines of inline documentation to ItineraryTableViewController
- Document architecture decisions, data flow, constraints, and algorithms
- Add function-level comments explaining drag/drop, sortOrder calculation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 10:07:37 -06:00
Trey t
2a8bfeeff8 refactor(itinerary): replace anchor-based positioning with day/sortOrder
Replace complex anchor system (anchorType, anchorId, anchorDay) with
simple (day: Int, sortOrder: Double) positioning for custom items.

Changes:
- CustomItineraryItem: Remove anchor fields, add day and sortOrder
- CKModels: Add migration fallback from old CloudKit fields
- ItineraryTableViewController: Add calculateSortOrder() for midpoint insertion
- TripDetailView: Simplify callbacks, itinerarySections, and routeWaypoints
- AddItemSheet: Take simple day parameter instead of anchor
- SavedTrip: Update LocalCustomItem SwiftData model

Benefits:
- Items freely movable via drag-and-drop
- Route waypoints follow exact visual order
- Simpler mental model: position = (day, sortOrder)
- Midpoint insertion allows unlimited reordering

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 09:47:11 -06:00
Trey t
59ba2c6965 docs: add detailed itinerary refactor implementation plan
11 bite-sized TDD tasks to replace anchor-based positioning with
simple (day, sortOrder) model. Includes migration path for CloudKit.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 09:12:16 -06:00
Trey t
bd1e24181f docs: add itinerary refactor design
Replace anchor-based positioning with simple sort-order system:
- Custom items use (day, sortOrder: Double) instead of anchors
- Travel segments have hard guardrails based on city game schedules
- Route waypoints follow exact visual display order

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 09:08:42 -06:00
Trey t
8df33a5614 WIP: map route updates and custom item drag/drop fixes (broken)
- Fixed map header not updating in ItineraryTableViewWrapper using Coordinator pattern
- Added routeVersion UUID to force Map re-render when routes change
- Fixed determineAnchor to scan backwards for correct anchor context
- Added location support to CustomItineraryItem (lat/lng/address)
- Added MapKit place search to AddItemSheet
- Added extensive debug logging for route waypoint calculation

Known issues:
- Custom items still not routing correctly after drag/drop
- Anchor type determination may still have bugs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 00:00:57 -06:00