f97d5f52ec4a4d46a4ee5f3823c94dcb5dd777cf
20 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
a33a56176d |
History v3: search, sort, filters, interactive lifetime map
Pulls the History tab toward Flighty's Passport in three ways: Search + sort + filters on the list - .searchable text field across flight #, route, IATA codes - 6-way sort menu (newest/oldest, longest/shortest, by airline, by flight number); list either groups by year (date sorts) or goes flat (everything else) - New HistoryFilters value type: year set + airline set + airport set + aircraft-type set + query. .matches(flight) predicate - New HistoryFilterSheet with multi-select chips and live counts per option (we only show years/airlines/airports/types you've actually flown) - Active-filter chip row above the list, tap to remove individual filters; "Clear" wipes all - Totals strip retitles to FILTERED TOTALS when filters are on and recomputes against the visible subset Interactive route map - Tap an arc style preserved, but most-recent flight now highlighted brighter so it stands out at a glance - Tap an airport dot → AirportFlightsView for that airport - Filter sync: dots tied to currently-filtered airports light up - Replay button in the toolbar restarts the reveal animation - Map respects History tab's filters (visible arcs match) but draws airport dots from the FULL log so geography stays stable Airport drilldown (new) - AirportFlightsView shows summary (departed/arrived/total), top 10 destinations from that airport, and the full list of flights through it - "Filter list" toolbar action sets the History filter to just that airport and pops back Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
d639cdef15 |
History: import flights from CSV (Southwest PNR format)
Adds a "Import CSV…" entry to the History tab's + menu, opening a
file picker → preview → save flow.
- CSVFlightImporter: RFC-4180-ish quote-aware parser + format
detection. Today only recognizes the Southwest PNR export schema
(columns Flt No / ORG / DST / Dep Date / OPNG Flt). Returns
ParsedFlight values with carrier, flight number, route, and
scheduled departure.
- ImportCSVView: SwiftUI .fileImporter picks a CSV from Files (iCloud
Drive / On My iPhone / etc.), parses on a Task, dedupes against
the existing log via FlightHistoryStore.exists(...), shows a
preview with "N new · M dupes" counts, imports on confirm.
- LoggedFlights created from import store the PNR in notes
("PNR: ABC123") and source "csv-import".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
9e1dbfbf90 |
Re-enable flights:// URL scheme (with UISceneConfigurations)
Switching the app target's Info.plist back to a manual file at Flights/Info.plist so we can register CFBundleURLTypes for the flights:// scheme. The Info.plist now includes UISceneConfigurations inside UIApplicationSceneManifest — missing that key was the likely cause of the device-launch crash on the previous attempt. Verified launch + xcrun simctl openurl flights://import?... on the iPhone 17 Pro simulator. App stays running after URL handoff. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
f40b02f68d |
Fix launch crash: drop CloudKit init, lazy Wallet, revert plist
Three changes that together stop the crash-on-launch the previous build hit on device: 1. FlightsApp: stop attempting `cloudKitDatabase: .private(...)` when the iCloud entitlement isn't set — SwiftData's ModelContainer init can fatalError validating the cap (not just throw), so try? doesn't save us. Go straight to local config, with an in-memory fallback if the disk store is incompatible with the current schema. 2. WalletPassObserver: don't touch PKPassLibrary in init(). `@StateObject` accesses .shared at view body time, which on first launch can race against PassKit subsystem init. Move the library bring-up into an explicit start() called from RootView's .task. 3. Flights app target Info.plist: revert from manual INFOPLIST_FILE back to GENERATE_INFOPLIST_FILE = YES (with the INFOPLIST_KEY_* entries restored). The manual plist I wrote was missing some auto-generated keys the device launch path needs. Loses the custom URL scheme — `.onOpenURL` handler stays in code but won't fire until we re-add the scheme via a manual plist that's been verified end-to-end. Verified launch on iPhone 17 Pro simulator — scene becomes key window, no fatalError. The earlier on-device crash was almost certainly the CloudKit init. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
d444a5caac |
Share Extension: back out target, keep URL scheme
The signed export needs a provisioning profile for the extension's bundle id (com.flights.app.share) which the dev portal hasn't provisioned for this team. Reverted the pbxproj surgery that added the FlightsShareExtension target. Kept: - Flights/Info.plist with CFBundleURLTypes registering flights:// - `.onOpenURL` handler in RootView that consumes `flights://import?carrier=...&num=...&dep=...&arr=...&date=...` - FlightsShareExtension/ source files (ShareViewController.swift + Info.plist) in the repo for later — when the extension bundle id is provisioned, the target can be re-added in Xcode UI in a few minutes (no need to redo the Swift work) Until the extension is built, users can still get Mail integration by installing a one-time Apple Shortcut that takes selected text and opens `flights://import?...`. The host app handles the rest. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
16b874a7ad |
Detail sheet: hero aircraft photo via planespotters
Adds a 200pt-tall hero image at the top of the detail sheet showing
the actual airframe (registration-keyed), surfacing special liveries
naturally — photographers chase one-off paint jobs first, so the
most recent photo is usually the most recent livery scheme.
AircraftPhotoService wraps planespotters.net's public API:
- Lookup by registration (FR24 enrichment) first
- Falls back to ICAO24 hex when no registration
- In-memory cache (hits and misses) so we never re-query the same
airframe twice in a session
- User-Agent includes contact URL per planespotters' TOS
- Photographer attribution rendered in the AIRCRAFT section,
tap to open the planespotters page
Sheet hides the banner entirely when no photo exists.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
92bc6ed52e |
Live feed: FR24 primary, OpenSky fallback
OpenSky's free anonymous tier has sparse ground coverage — at DAL it
returned a single airborne aircraft when there were 3+ SWA jets
visibly parked on the apron. FR24's feed.js aggregates ASDE-X, MLAT,
and multiple community ADS-B feeds and reliably surfaces ground
aircraft at major airports. We now query FR24 first and fall back to
OpenSky only when FR24 errors.
FR24's payload also carries departure + arrival IATA + flight number
+ aircraft type + tail number inline, so we shortcut the
route-explorer schedule lookup in the detail sheet: a new
`LiveAircraft.Enrichment` struct holds those fields, and the
ResolvedRoute cascade gains a `.fromFR24` first-tier case that uses
them directly. The `typeCode` and `airlineICAO` computed properties
prefer enrichment values over the AircraftDatabase / callsign-prefix
heuristics — this also fixes the case where FR24 callsigns use the
IATA carrier ("AA0013") which our 3-letter-prefix derivation would
have rejected.
OpenSky still owns trail polylines and recent-flights history; only
the live position fetch swapped sources.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
dee6df1ac6 |
Live map: center on user, persist region, zoom-based aircraft cap
- Initial region cascade: restore last viewed region → on location grant, animate to a city-level view centered on user; otherwise fall back to the saved/continental default. User pans are detected via a center-delta threshold so a late location grant doesn't yank the camera away from where the user is looking. - LocationService: thin one-shot CLLocationManager wrapper with CheckedContinuation. Added NSLocationWhenInUseUsageDescription via INFOPLIST_KEY_ build setting. - Visible-aircraft cap scales with zoom (<2°: uncapped, <8°: 100, <25°: 150, else 200). Active filters bypass the cap entirely so every match always renders. When capped, we keep the N closest to the map center. - Footer shows "Showing N of M" when the cap clips, "N aircraft" otherwise. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
390a158487 |
Live tab: restore type filter via bundled aircraft DB + sheet pickers
Two issues:
1) Menu list stutters. SwiftUI's Menu renders all rows in a
non-virtualized popover. With 30+ airlines and Buttons containing
Labels, scrolling jank starts immediately. Switched the airline +
type filters to a sheet-based picker (LiveFilterPicker) backed by
a real List — virtualized scrolling, plus a search bar that
filters as you type.
2) Type filter was non-functional because OpenSky's anonymous tier
returns ADS-B emitter category as null for most aircraft.
Replaced with a real type-code lookup: bundled aircraftDB.json
(1.5MB slimmed copy of OpenSky's aircraft metadata, 100k
commercial-class airframes, filtered to skip GA / gliders /
ultralights). AircraftDatabase.shared.typeCode(forICAO24:)
returns the ICAO type designator (B738, A21N, etc.).
AircraftDatabase.displayName(forTypeCode:) maps the top ~130
common codes to friendly names ("B738" → "Boeing 737-800").
LiveAircraft now exposes a `typeCode` computed property that
indexes into the DB. The type filter chip → sheet flow uses the
same LiveFilterPicker as airlines, with multi-select + counts +
search.
Both pickers keep the "Selected (N)" group pinned at the top so
the user always sees what they have active without scrolling.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
6b33a104c8 |
Live tab: bundled airline DB, OpenSky login, in-flight trails
Three follow-ups to the live tab landed together:
1) Bundled airline registry
- airlines.json (208KB, 2,695 entries sourced from FR24's
/mobile/airlines feed and slimmed to {icao,iata,name,logo}).
- AircraftRegistry rewritten as an instance singleton that loads
the bundle at startup, indexes by both ICAO and IATA, and falls
back to a small hardcoded subset if the bundle is unavailable.
- Detail sheet now shows the airline's logo (loaded from FR24's
CDN via AsyncImage) alongside the callsign. Filter chips use
the real names everywhere.
2) OpenSky account login
- OpenSkyCredentials: Keychain wrapper that stores username +
password using SecItem APIs. Posts a notification on change so
the OpenSkyClient can refresh its in-memory copy.
- OpenSkyClient now sends HTTP Basic auth when credentials are
present. Anonymous fallback unchanged.
- OpenSkySettingsView: tap the gear in the footer to sign in.
Credentials are verified against /states/all before being
stored; sign-out clears Keychain. Raises the quota from ~100
to ~4000 requests/day.
3) Flight trails
- AircraftTrack model decodes OpenSky's /tracks/all heterogeneous
path array into typed TrackPoint entries.
- OpenSkyClient.track(icao24:) fetches the current/most-recent
track for an aircraft.
- LiveFlightsView renders a MapPolyline trail along the path of
whichever aircraft is currently selected. Cleared on
deselection; race-guarded against rapid selection changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
888943deb4 |
Add Live Flights tab: real-time aircraft map with filters + tap detail
New top-level TabView (RootView) splits the app into: Tab 1 (Search): existing RoutePlannerView home Tab 2 (Live): live flight tracker Live tab features: - MapKit map showing every aircraft in the visible viewport, rotated to true heading. Color-coded by vertical state: climbing/level/ descending/on-ground. - Auto-refresh every 15s + on map pan/zoom (debounced); manual refresh button. Rate-limit aware (60s backoff on HTTP 429). - Tap any aircraft → modal sheet with live state grid (altitude, speed, heading, vertical rate, squawk, last-contact), current route (lazily fetched per-aircraft from OpenSky's /flights/ aircraft endpoint, mapped from ICAO to IATA airport codes), and recent flight history (up to 8 prior legs). - Filters: airline (multi-select from currently visible callsigns, with counts), aircraft type (ADS-B emitter category), airborne- only toggle. All filters render as horizontal chips and clear with a single tap. - Search bar: callsign/flight number — submitting centers the map on the match and opens its detail sheet. Data source: OpenSky Network REST API. Free, anonymous (~100 req/ day cap), JSON. Same ADS-B data FR24 starts with — without satellite ADS-B coverage but more than enough for the in-flight tracker use case. Reviewed FR24's APK and confirmed they migrated their live feed to gRPC+protobuf with anti-bot device-id headers; OpenSky's plain JSON is the right tradeoff for our build. Implementation: - LiveAircraft model: decodes OpenSky's mixed-type position arrays into a typed struct; computed properties for ft/knots/heading and airline ICAO extracted from callsign. - OpenSkyClient: actor with /states/all + /flights/aircraft. Bbox query, throttle-aware errors. - AircraftRegistry: ~80 ICAO → (IATA, name) entries for the major carriers; everything else falls through to the raw ICAO code. - LiveFlightsView: the main map + filter UI. - LiveFlightDetailSheet: tap modal with live state + route history. - RootView: TabView wrapping RoutePlannerView (Search) and the new LiveFlightsView (Live). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
62729213d7 |
Add FlightsTests target + fix AA load fetcher (Android UA version bump)
AA was silently returning nil because the server now rejects User-Agent
"Android/2025.31" with HTTP 403 ("Please update your version of the
American Airlines app"). Bumped to "2026.14" (matches the APK in
airlines/) and centralized to a constant so the next bump is one line.
Added comprehensive logging to fetchAmericanLoad (was zero) so the next
breakage won't be silent — including an explicit ⚠️ when the server
returns the "update your version" payload.
New FlightsTests target with AirlineLoadIntegrationTests — hits live
airline APIs to verify each fetcher still returns data. Per-airline
strategy:
- Try route-explorer /departures from carrier hubs for a flight in the
next 24h (works for AA/UA/AS/B6).
- Fall back to a known-good daily flight when route-explorer doesn't
have the carrier in its data (NK/EK/KE — ULCC + some intl carriers).
- B6/EK/NK are status-only by design (no standby data without a PNR);
asserted as non-nil only.
- XE (JSX) skipped: needs WKWebView host.
Retries on route-explorer 429 by parsing the `retryAfter` field and
sleeping the indicated number of seconds. Static-shared client+services
across tests so the token cache survives.
Results 2026-05-26 (xcodebuild test -scheme Flights):
✅ AA, AS, B6, EK, KE, UA ❌ NK ⏭️ XE
NK (Spirit) is now broken: GetFlightInfoBI returns HTTP 403 with
{"getFlightInfoBIResult":null}. APIM key still accepted (401 without
it), but the call itself is rejected. Documented in
AIRLINE_INTEGRATION_GUIDE.md as a known regression to fix; likely
needs reverse-engineering against the current Spirit APK in airlines/.
Also: enable shared schemes in .gitignore so `xcodebuild test` works
out of the box for anyone cloning the repo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
0c4777216e |
Make RoutePlannerView the home; merge "Where can I go?" into it
Single unified search at the app root. TO is optional: filled goes through
/route (connections); blank flips to /departures with a time-window picker
("Where can I go?"). Same per-leg load card detail screen for any tap, so
direct flights and multi-stop connections share the same UX.
- Drop ContentView entirely (favorites + browse + entry cards). FlightsApp
instantiates RoutePlannerView directly.
- Delete WhereToGoView; DepartureLegRow is inlined into RoutePlannerView
as the where-can-I-go result row.
- SearchRoute enum trimmed to just the cases DestinationsListView still
references and moved to its own file (Models/SearchRoute.swift).
Sort bar moved out of the controls cards into a dedicated row between the
Search button and the results — only visible once results exist. Switched
from segmented to dropdown menu picker. Options narrowed to the four
the user asked for: Departure Earliest / Departure Latest / Fewest Stops
/ Most Stops in connection mode, just the two time-based options for
where-can-I-go (single-leg, stop-count is meaningless). All sorts apply
client-side; upstream still gets `departure_time` for a stable base order.
Two real bugs fixed in connection search:
- Past flights weren't filtered. Same-day searches return mostly already-
departed itineraries because the API sorts earliest-first. Added a
`firstDeparture > now` filter applied before sort. Header surfaces the
dropped count ("12 itineraries · 38 already departed"). When every
result is past, the error message says so explicitly instead of going
blank.
- 100-result limit was way too low for hub→hub with maxStops:2 — the
combinatorial explosion of valid permutations filled the cap with
morning flights and never reached afternoon. Bumped to 500.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
df4a74726c |
Route Explorer: unified per-leg load card + multi-leg fan-out
Single ConnectionLoadDetailView is now the universal detail screen for
both Find Connections (1+ legs) and Where Can I Go (single-leg). For
multi-stop connections it fetches each leg's load in parallel via
withTaskGroup so the slowest carrier doesn't block the rest. Each leg
card shows airline + flight + IATAs + airport names + aircraft + an
open/standby summary, with a "Full details" drill-down to
FlightLoadDetailView for waitlists/passenger lists.
Bug fixes along the way:
- Empty origin/destination in carrier API URLs (HTTP 400 from AA): the
4 separate @State vars feeding .sheet(item:) raced — sheet captured
empty strings before the other writes settled. Bundled into one
Identifiable RouteLoadDetailRequest / ConnectionLoadRequest so updates
are atomic.
- Flight numbers rendered with locale separators ("AA 6,380", "3,189").
Text("\(int)") resolves to the LocalizedStringKey initializer; switched
to Text(verbatim:).
- "Load data not available for {airline}" was misleading when the
airline IS supported but a specific flight has no data. Reworded to
flight-scoped copy.
- AA fetcher had no logging — added URL/status/body/keys diagnostics
matching the UA pattern.
UI cleanup:
- DepartureLegRow: big IATAs on their own row, full airport names on a
middle-truncated subtitle, aircraft pill single-line tail-truncated.
- LegSummary (ConnectionRow): airport-name subtitle line below
times+IATAs row.
- airportName priority: bundled airports.json first ("Dallas-Fort
Worth") over the route-explorer appendix ("Dallas Dallas/Fort Worth
Intl") which truncated to garbage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
b403bfd970 |
Add route-explorer.com integration: connection finder + departures board
- RouteExplorerClient: anonymous HMAC token (route-explorer.com/api/token,
IP rate-limited 10/min), POST /api/flight-search with X-API-Token; auto
retry on 401/403 token rotation. Wraps the SuperJSON {json:{...}} envelope
for the upstream tRPC endpoints.
- RouteExplorerModels: Codable types for /route, /departures responses
(RouteConnection, RouteFlight, cabins, appendix). Custom ISO-8601
decoder for the dateTime-with-offset timestamps. Bridge helper
RouteFlight.toFlightSchedule(...) so route-explorer legs reuse the
existing FlightLoadDetailView and AirlineLoadService flow for
supported carriers (UA/AA/NK/KE/B6/AS/EK/XE).
- RoutePlannerView: feature (a) — direct + multi-stop A→B routing via
/route with maxStops 0/1/2, sortBy departure_time/duration, optional
interline-only filter. Renders one ConnectionRow per itinerary with
chained legs and layover indicators.
- WhereToGoView: feature (b) — "where can I go" departures board for an
airport over a 2/4/6/12/24h window. Capacity pills (F/J/W/Y), color-
coded countdown, cross-midnight rollover. Tap any leg → load detail.
- IATAAirportPicker: lightweight local-only picker against
AirportDatabase (no flightconnections roundtrip needed since
route-explorer keys on IATA, not FC IDs).
- ContentView: two new entry-point cards (Find Connections, Where can I
go?) above the favorites list.
- api_docs/route_explorer_api.md + captures: full endpoint reference and
representative response samples (DFW→LAS direct, DFW→KOA 1-stop,
LBB→KOA 2-stop, AA2178 schedule, DFW departures).
No tests yet — project has no test target and adding TDD would require
scaffolding XCTest first. Worth backfilling tests for the date decoder,
layover math, and toFlightSchedule bridge using the saved fixtures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
847000d059 |
Land local WIP on top of JSX rewrite + wire JSXWebViewFetcher into target
Resolves the working tree that was sitting uncommitted on this machine when the JSX rewrite ( |
||
|
|
3790792040 |
Initial commit: Flights iOS app
Flight search app built on FlightConnections.com API data. Features: airport search with autocomplete, browse by country/state/map, flight schedules by route and date, multi-airline support with per-airline schedule loading. Includes 4,561-airport GPS database for map browsing. Adaptive light/dark mode UI inspired by Flighty. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |