Commit Graph

3 Commits

Author SHA1 Message Date
Trey T 86582cea4a History tab: passport redesign
Replaces the History tab end-to-end with a passport-styled experience
modeled on Flighty's Passport but with its own identity:

- New HistoryStyle palette: runway orange (#FF5722) + midnight navy
  + warm cream paper. Adaptive light/dark surfaces, mono-digit
  display numbers, card chrome modifier. Scoped to History so the
  rest of the app's FlightTheme stays untouched.
- New PassportComponents library: HeroStatCard (orange / navy / gold /
  green / photo variants), YearTabStrip, OCRPassportFooter (the OCR
  passport-bottom flex text), StatColumn, HistorySectionLabel.

Screens rewritten:
- HistoryView — ScrollView feed with title header, year tab strip,
  stacked hero cards (this-year passport, most-flown aircraft, quick
  links to map/aircraft/year-in-review), and passport-styled flight
  rows in cards. Search, sort, filter, and add affordances live in
  the toolbar.
- PassportView (was LifetimeStatsView) — stacked colored hero cards
  for flights, distance, time aloft, top route, top airline, longest
  flight, plus repeated-airframes list. Year tabs at top scope
  everything. OCR-passport flex footer at the bottom.
- AircraftStatsView (new) — Total / Newest / Oldest header tiles,
  ranked list of types with the airframe photo as the row background,
  "Repeat Offender" hero card with the most-flown tail's photo
  full-bleed.
- HistoryRouteMapView — satellite map style (.imagery), brighter
  arcs in runway orange with the most-recent leg in fluorescent
  yellow, persistent bottom navy drawer showing the passport summary
  + active filter chips + replay button.
- YearInReviewView — horizontal TabView paged card deck, each card a
  full-bleed hero composition optimized for screenshot share. Cover
  card with year number set in 140pt monospaced bold.
- HistoryDetailView — restyled with passport palette. Aircraft card
  uses a labeled grid (Type/Tail #/First Flight/Age/Repeats/ICAO24)
  with em-dashes for missing data. New Detailed Timetable card with
  Scheduled vs Actual columns, late times in red.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 11:13:24 -05:00
Trey T 803c812f86 History v2: everything — Wallet auto-prompt, age, track replay, share
Adds the deferred pieces from the v1 ship, plus a Mail Share
Extension target so the iOS share sheet picks up flight emails.

Track replay
- `LoggedFlight.icao24` field — populated from FR24 enrichment on
  live-tap adds.
- HistoryDetailView's track query now fires for any flight younger
  than 7 days that has an icao24, pulling the actual flown path
  from OpenSky's /tracks/all endpoint. Falls back to a clean
  great-circle arc otherwise.

Wallet auto-prompt
- RootView subscribes to WalletPassObserver.shared. When the user
  adds a boarding pass to Apple Wallet, the observer's published
  `pendingPass` flips and we present AddFlightView pre-filled with
  the parsed origin / destination / flight # / date.

Airframe age + first-flight date
- `AirframeMetadataService` queries OpenSky's
  /api/metadata/aircraft/icao/{icao24} endpoint. Caches results in
  the existing `AirframeMetadata` SwiftData model so we never
  re-fetch the same airframe twice. (jetphotos and planespotters
  pages are both Cloudflare-gated; OpenSky's metadata API is the
  cleanest free source.)
- HistoryDetailView fires the lookup on appear and persists the
  result; the aircraft card already renders "Age" when a date is
  cached.

Mail Share Extension
- New `FlightsShareExtension` Xcode target (app-extension product
  type) built into the app bundle via an Embed Foundation
  Extensions copy phase.
- `ShareViewController` (SLComposeServiceViewController) parses
  shared text + URLs for flight-shaped codes ("AA 2178"), route
  hints ("DFW → ORD"), and date strings.
- On Save, the extension builds a `flights://import?carrier=…&num=
  …&dep=…&arr=…&date=…` URL and opens it via the responder-chain
  openURL trick (Share Extensions can't access UIApplication
  directly).
- Host app handles the URL via `.onOpenURL` in RootView, switches
  to the History tab and presents AddFlightView prefilled.
- App now has an actual Info.plist (CFBundleURLTypes registered
  for `flights://`); switched from GENERATE_INFOPLIST_FILE to
  INFOPLIST_FILE for the app target.

If the dev portal hasn't registered bundle id
`com.flights.app.share` for the team, the signed archive will
fail. In that case the simpler URL-scheme path still works —
users can hit `flights://import?...` from a Shortcut.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 09:51:30 -05:00
Trey T 847e5c6035 Flight History (v1): logbook, stats, animated route map, year-in-review
Adds a new History tab implementing the core of Flighty's Passport
feature set, free + iCloud-synced.

Data layer
- `LoggedFlight` and `AirframeMetadata` @Model classes (SwiftData)
- ModelContainer with CloudKit private DB; falls back to local-only
  when CloudKit cap isn't provisioned so the app stays functional.
- `FlightHistoryStore` wraps the ModelContext for save/delete +
  dedupe + great-circle distance / duration helpers + tail-repeat
  counting.

History UI
- `HistoryView` — list grouped by year, totals strip at top, swipe
  to delete, empty state with instructions.
- `HistoryRowView` — airframe photo thumbnail (planespotters),
  flight#, route, type, date.
- `HistoryDetailView` — title → route → photo → flown-path / great-
  circle map → aircraft card (type, tail, age, "Nth time on this
  airframe") → editable notes → delete.

Add paths
- "+ Add to my flights" button on the live aircraft sheet —
  pre-fills the form from FR24 enrichment (carrier, flight#,
  route, aircraft type, tail).
- Manual entry form (`AddFlightView`) with route-explorer autofill
  via `searchSchedule(carrierCode:flightNumber:startDate:endDate:)`.
- Calendar scan (`CalendarFlightImporter` + `CalendarImportView`) —
  EventKit access prompt → regex-detect flight-shaped events
  across last 5 years → dedupe → batch-confirm with route-explorer
  enrichment.
- `WalletPassObserver` (PassKit) — observes the library for new
  boarding passes and parses origin/destination/flight#/seat.
  Service is wired; explicit UI prompt deferred to follow-up.

Stats + visualization
- `StatsEngine` — totals (flights / miles / hours / airports /
  airlines / aircraft / countries) + narrative stats (top airline,
  top route, top airport, longest, shortest, repeated tails).
- `LifetimeStatsView` — big-number tile grid + highlights cards +
  repeated airframes list.
- `HistoryRouteMapView` — every great-circle arc the user has
  flown, animating in oldest → newest on first appear. Airport
  dots sized log-scale by visit count.
- `YearInReviewView` — Spotify-Wrapped-style horizontal card deck
  for the current year: total miles, airports + countries, hours
  airborne, top airline, top route, longest flight.

Entitlements
- New `Flights.entitlements` with `iCloud.com.flights.app` CloudKit
  container.

Risk note: the build falls back to local-only SwiftData if the
CloudKit container isn't provisioned for team V3PF3M6B6U / bundle
id com.flights.app. The History feature works fully either way;
sync requires the cap to land.

Deferred to follow-ups
- Wallet auto-prompt UI binding (service exists, view hook TBD)
- Mail Share Extension (separate app-extension target)
- Jetphotos first-flight-date scraping
- OpenSky historical track replay (great-circle fallback ships)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 09:34:38 -05:00