Read the CurrentSlot policy: when the meter's current time-of-day window is Free
or No Parking, show that status instead of a purchase flow (matches the official
app). Confirmed via API: DSB3 9AM-5PM is RateType "Hour" $4/hr with no free grace;
the "2 hours free" is a city grace period outside the ParkSmarter payment system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New StartSession screen off MeterDetail: pick vehicle -> duration (from the live
multi-estimate ladder, exact cost per option) -> card; detects a free prefix and
shows "Free until X, then charged"; explicit Pay $X confirmation before charging
via postStartParkingSession; schedules the local expiry reminder on success
- About screen themed (was black-on-dark in dark mode)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New Notifications screen (Account > Notifications): enable/disable expiry
reminders + a 5-minute-increment stepper (5–60 min), default 15 min
- localReminders.scheduleExpiryReminder now reads the persisted lead time + enabled
flag, so it's ready to fire once the start-session flow is wired
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Camera recenter-on-search confirmed fixed (view-lock). Strip the temporary trace
logs; keep viewport tracking (needed for the fix). HTTP request logging now defaults
off — still toggleable in Account > Log requests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The native MapLibre camera re-applies its last setCamera() stop on the search
re-render (confirmed via trace: revert to prior target with userInteraction=false).
Track the live viewport and, before searching the current area, setCamera() to the
current center (0ms) so the re-applied stop is a no-op instead of a jump-back.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ROOT CAUSE: MapLibre Camera re-applies its last setCamera() stop on every
re-render, so a search (setZones) snapped the map back to the last programmatic
target. Memoize the Camera + UserLocation elements so search re-renders never
touch them; only the marker ShapeSource updates. (Confirmed via [CAM] trace.)
- Login: brain-car logo + full theming so text is readable in light/dark
- Meter policies: negative Rate is a sentinel (RateType No Parking=-1 / Free=-3),
not a price; show DisplayString + colored type dot, real $/hr only when positive.
Fix zone rate "$ 4.00" formatting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- MeterDetail now themed (fixes unreadable black headings in dark mode)
- Rate no longer double-'$'; MaxTime 0 -> "Unlimited"; policies show a clean
title + time window and hide sentinel (<=0) rates
- Temporary [CAM] logging on the map to trace the persistent recenter-on-search
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MarkerView (React overlays repositioned per frame) caused the pins to float and
the camera to snap back to the user on pan/zoom/tap. Meters are now a ShapeSource
+ CircleLayer (GPU-drawn, coordinate-anchored); tapping a circle opens its parking
flow via the source's native onPress. No React overlays = no floating, no camera thrash.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Markers are now compact colored pins (no long label bubbles); tapping one opens
the meter/parking flow for that zone
- UserLocation renderMode "native" -> "normal": the native location component was
tracking the camera back to the user on re-render / marker tap. Normal mode draws
the dot in the JS layer with no camera coupling.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Client: server returns 200 + Status:"Error" on bad credentials; loginWith* now
throw LoginError with the server message instead of faking a signed-in state
- Map: uncontrolled camera positioned once on load + explicit actions only, so
Search/marker-tap/re-renders no longer snap back to the user's location
- Markers: always-dark high-contrast bubble + zone-colored dot (some zones report
a white BackgroundColor -> was white-on-white)
- Dark mode now switches map tiles to CARTO dark-matter
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Client: onUnauthorized hook; 401 clears the token and (in-app) bounces to sign-in
- Map: "My location" uses the native UserLocation fix + flyTo; safe-area insets on
the floating status bar / controls
- Enable edgeToEdgeEnabled (Android 15 forces it) so headers/back-arrow sit correctly
- App icon: brain-car launcher + adaptive icon
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- "Search this area" now searches the map's current center (getCenter), so it
works with no GPS fix — pan anywhere and search. Fixes "search here does nothing".
- "My location" recenters the camera on the GPS fix and searches there.
- Status bar shows real feedback (N meters / none found / errors) instead of silent.
- Add bottom tab icons via @expo/vector-icons (map/qr/star/time).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The '@/' import alias needs this plugin; debug builds hid the gap because
they bundle lazily via Metro. Release (standalone) bundling now succeeds.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- About screen surfaces getAbout() content; tapping the title 7x reveals
assets/joelangel.png (placeholder committed; replace with the real image)
- Correct UnifiedPush package to react-native-unifiedpush-connector (lazy-required)
- Fix expo-notifications NotificationBehavior (shouldShowAlert)
- Reachable via an ⓘ header button on the main tabs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reverse-engineered ParkSmarter API client (TypeScript, live-verified) plus a
de-Googled Expo/React Native app for GrapheneOS: MapLibre meter map with GPS,
VisionCamera QR kiosk scanning with save/share, local session-expiry reminders,
UnifiedPush wiring, and Gitea CI to publish signed APKs for Obtainium.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>