Conversation
… present; fallback to Leaflet
… and log helpful warning; update README troubleshooting
… generator for smoother maps
…s; fix template syntax and brace imbalance
…nd route updates - Add comprehensive Mapbox error handling with try-catch, map event listeners, and WebView error callbacks - Implement global unit preferences in ThemeProvider (speed units, temperature units) - Add functional 3D rendering toggle in settings - Add gradient fade to 3D car viewer for smooth visual transition - Replace Colorado ski trip with Madison ehall_trip route data (308 positions) - Remove Australia route files and update routeLoader to use ehall_trip only - Restructure navigation: rename Systems tab to Signal Search, create new Systems page with dropdown - Add Sparky logo to Battery screen header - Remove StarsOverlay from Battery/Strategy screens when embedded - Separate weather temperature units from battery temperature units (weather uses local toggle, battery uses global setting) - Add WebView compatibility props (allowsInlineMediaPlayback, mixedContentMode) - Create conversion script for route data (ehall_trip.csv → dataset1_positions.json)
There was a problem hiding this comment.
Pull request overview
This pull request introduces a comprehensive navigation system overhaul by migrating from React Navigation to Expo Router, implementing Mapbox integration, and adding race strategy features with route visualization. The changes include new tab-based navigation, persistent navigation state management, unit preferences (speed and temperature), 3D rendering toggles, and CSV-based route loading with dynamic visualization on maps.
Changes:
- Migrated from React Navigation to Expo Router with native tab bars and file-based routing
- Added Mapbox GL JS integration with flexible token configuration via .env, app.config.js, or app.json
- Implemented navigation features with CSV route loading, waypoint visualization, and persistent navigation state via NavigationContext
- Added user preferences for speed units, temperature units, and 3D rendering to ThemeProvider
- Restructured Systems screen with dropdown selector routing to Battery, Strategy, and placeholder subsystems
- Created new StrategyScreen with race strategy recommendations, sparkline charts, and route preview
Reviewed changes
Copilot reviewed 34 out of 49 changed files in this pull request and generated 25 comments.
Show a summary per file
| File | Description |
|---|---|
| app/(tabs)/_layout.js | New Expo Router tab layout with native tabs for iOS and Android |
| app/_layout.js | Root layout with providers (Theme, Navigation, fonts) |
| index.js | Updated to use Expo Router entry point |
| src/context/NavigationContext.js | Global navigation state for route selection and nav mode |
| src/data/routeLoader.js | CSV route loading with Asset API and waypoint parsing |
| src/data/routes/ehall_trip.csv | Sample route data for navigation testing |
| src/data/dataset1_positions.json | Position replay data for telemetry simulation |
| src/screens/SystemsScreen.js | Refactored to dropdown-based system selector |
| src/screens/StrategyScreen.js | New screen with race strategy metrics and map preview |
| src/screens/SignalSearchScreen.js | Extracted from old SystemsScreen |
| src/screens/ProfileScreen.js | Added speed/temp unit preferences UI |
| src/screens/Home2Screen.js | Added battery temperature with global tempUnit preference |
| src/screens/BatteryScreen.js | Added Sparky logo header image |
| src/components/MapView.js | Added Mapbox GL JS support, navigation controls, route visualization |
| src/components/LocationWeatherDisplay.js | Restructured location display with state/country |
| src/components/Battery3DViewer.js | Added cell selection grid placeholder |
| src/theme/ThemeProvider.js | Added speedUnit, tempUnit, render3D preferences |
| app.config.js | Dynamic config loader for Mapbox token from .env |
| .env.example | Template for environment variables |
| package.json | Added expo-router, dotenv dependencies |
| metro.config.js | Added CSV to asset extensions |
| babel.config.js | Standard Expo preset for Expo Router support |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| useEffect(() => { | ||
| if (selectedRoute) { | ||
| loadRoute(selectedRoute) | ||
| .then(routeData => { | ||
| setLoadedRouteData(routeData); | ||
| // Draw route on map (both inline and fullscreen) | ||
| if (mapLoaded && webViewRef.current) { | ||
| drawRouteOnMap(routeData); | ||
| } | ||
| }) | ||
| .catch(err => { | ||
| console.error('Failed to load route:', err); | ||
| if (!inline) { | ||
| Alert.alert('Error', 'Failed to load route'); | ||
| } | ||
| }); | ||
| } | ||
| }, [selectedRoute, mapLoaded, inline]); |
There was a problem hiding this comment.
The useEffect that loads route data (lines 166-183) is missing drawRouteOnMap in its dependency array. If drawRouteOnMap is not wrapped in useCallback, this could lead to stale closures or missed updates. Either add drawRouteOnMap to the dependency array or wrap it in useCallback.
| const [useImperialUnits, setUseImperialUnits] = useState(true); // For weather only | ||
| const [locationName, setLocationName] = useState('Madison, WI'); | ||
| const { theme } = useTheme(); | ||
| const { theme, render3D, tempUnit } = useTheme(); | ||
|
|
||
| // Temperature helpers (same logic as HomeScreen) | ||
| const convertTemperature = (celsius) => { | ||
| // Temperature helpers - for weather (uses local useImperialUnits) | ||
| const convertWeatherTemperature = (celsius) => { | ||
| return useImperialUnits ? Math.round(celsius * 9/5 + 32) : Math.round(celsius || 0); | ||
| }; | ||
| const getTempUnit = () => useImperialUnits ? '°F' : '°C'; | ||
| const getWeatherTempUnit = () => useImperialUnits ? '°F' : '°C'; | ||
|
|
||
| // Battery temperature helper - uses global tempUnit setting | ||
| const convertBatteryTemperature = (celsius) => { | ||
| return tempUnit === 'imperial' ? Math.round(celsius * 9/5 + 32) : Math.round(celsius || 0); | ||
| }; | ||
| const getBatteryTempUnit = () => tempUnit === 'imperial' ? '°F' : '°C'; |
There was a problem hiding this comment.
The Home2Screen has two separate unit systems: useImperialUnits for weather (local state) and tempUnit from theme context for battery temperature. This creates confusing UX where users might set temperature units in the profile/settings but only see it apply to battery temperature, not weather. Consider consolidating to use a single temperature unit preference from the theme context for both weather and battery, or clearly document why they need to be different.
|
|
||
| // Selected cell for UI interactions (placeholder for real 3D selection) | ||
| const [selectedCell, setSelectedCell] = useState(null); | ||
| const CELL_COUNT = 12; // placeholder cell count; replace with actual count when model integration is added |
There was a problem hiding this comment.
The cell grid UI (added in Battery3DViewer) shows 12 cells but the actual battery system has 29 modules as seen in BatteryScreen.js (line 301). This hardcoded CELL_COUNT of 12 doesn't match the actual system architecture and could confuse users. Either update CELL_COUNT to match the actual module count (29) or clarify in the UI that this is a placeholder visualization.
| const hasLatHeader = headers.includes('lat') || headers.includes('latitude'); | ||
| const hasLngHeader = headers.includes('lng') || headers.includes('longitude'); | ||
| const hasNameHeader = headers.includes('name'); | ||
|
|
||
| // Determine column indices | ||
| const latIndex = headers.indexOf('latitude') !== -1 ? headers.indexOf('latitude') : headers.indexOf('lat'); | ||
| const lngIndex = headers.indexOf('longitude') !== -1 ? headers.indexOf('longitude') : headers.indexOf('lng'); | ||
| const nameIndex = headers.indexOf('name'); |
There was a problem hiding this comment.
The variables hasLatHeader and hasLngHeader are computed but never used. These checks should be removed or used to validate the CSV format before attempting to parse it. Currently, if a CSV file doesn't have the expected headers, latIndex or lngIndex will be -1, and the code will silently fail to parse waypoints correctly.
| // Unit preferences | ||
| const [speedUnit, setSpeedUnit] = useState('imperial'); // 'imperial' | 'metric' | ||
| const [tempUnit, setTempUnit] = useState('imperial'); // 'imperial' | 'metric' | ||
|
|
||
| // 3D rendering preference | ||
| const [render3D, setRender3D] = useState(true); |
There was a problem hiding this comment.
The unit preferences (speedUnit, tempUnit) and render3D setting are stored only in React state, which means they will reset to default values every time the app restarts. These user preferences should be persisted using AsyncStorage or similar persistent storage mechanism so users don't have to reconfigure them on every app launch.
| @@ -0,0 +1,236 @@ | |||
| import React, { useState, useEffect } from 'react'; | |||
| import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Pressable, Dimensions } from 'react-native'; | |||
There was a problem hiding this comment.
Unused import Dimensions.
| import { SafeAreaView } from 'react-native-safe-area-context'; | ||
| import { useTheme } from '../theme/ThemeProvider'; | ||
| import { Ionicons } from '@expo/vector-icons'; | ||
| import { BlurView } from 'expo-blur'; |
There was a problem hiding this comment.
Unused import BlurView.
| import { useNavigation } from '../context/NavigationContext'; | ||
|
|
||
| export default function StrategyScreen() { | ||
| const { theme, isDark } = useTheme(); |
There was a problem hiding this comment.
Unused variable isDark.
| const { theme, isDark } = useTheme(); | ||
| const { navigationEnabled, setNavigationEnabled, selectedRoute, setSelectedRoute } = useNavigation(); | ||
| const [telemetryData, setTelemetryData] = useState(null); | ||
| const [lastUpdate, setLastUpdate] = useState(new Date()); |
There was a problem hiding this comment.
Unused variable lastUpdate.
| </BlurView> | ||
|
|
||
| {/* Navigation Controls */} | ||
| {!inline && ( |
There was a problem hiding this comment.
This negation always evaluates to true.
- Add overrides field to package.json to enforce tar >= 7.5.4 for all dependencies - Fixes CVE: Race Condition in node-tar Path Reservations via Unicode collisions on macOS APFS - Fixes CVE: Arbitrary File Overwrite and Symlink Poisoning via Insufficient Path Sanitization - Current tar version: 7.5.6 (satisfies both security patches)
…rsions - Update @react-navigation/bottom-tabs from ^6.6.1 to ^7.4.0 (installed: 7.10.1) - Update @react-navigation/native from ^6.1.18 to ^7.1.8 (installed: 7.1.28) - Fixes expo-doctor compatibility warnings
- Add expo.install.exclude config to ignore @react-navigation/bottom-tabs and @react-navigation/native - Installed versions (7.10.1 and 7.1.28) are newer than minimum required (7.4.0 and 7.1.8) - Fixes expo-doctor failing on minor/patch version differences - All 17 expo-doctor checks now pass
- expo-doctor has a bug where it exits with code 1 without --verbose even when all checks pass - With --verbose flag, all 17 checks pass correctly and exit with code 0 - Fixes CI pipeline failures on doctor check
- Remove --platform all and specify --platform ios --platform android explicitly - Avoids requiring react-native-web since this is a mobile-only app - Export now completes successfully with 1402 modules bundled
- expo-doctor has a bug where it exits with code 1 even when all checks pass - Update CI to check for 'No issues detected' in verbose output instead of relying on exit code - Script now correctly identifies when all 17 checks pass successfully
This pull request introduces a significant navigation system overhaul and migration to the Expo Router architecture, along with several supporting improvements. The most notable changes include enabling tab-based navigation with Expo Router, implementing a global navigation context and route visualization feature, updating configuration and environment management (notably for Mapbox integration), and improving documentation and developer tooling.
Navigation System & Expo Router Migration:
Migrated the app structure to use Expo Router for navigation, replacing the previous navigation setup. This includes new tab layouts in
app/(tabs)/_layout.jsand corresponding route files for each tab, enabling more modular and scalable navigation. (app/(tabs)/_layout.js,app/(tabs)/index.js,app/(tabs)/systems.js,app/(tabs)/signal-search.js,app/(tabs)/environmental.js,app/(tabs)/profile.js,app/_layout.js,index.js,package.json, [1] [2] [3] [4] [5] [6] [7] [8] [9]Added a global
NavigationContextto manage navigation state and route selection, supporting persistent navigation features across screens. (app/_layout.js,src/context/NavigationContext.js, app/_layout.jsR1-R48)Navigation Features & Route Visualization:
docs/NAVIGATION_FEATURES.md,metro.config.js, [1] [2]Configuration, Environment, and Mapbox Integration:
Added support for loading a Mapbox access token from
.env, environment variables, orapp.jsonusing a newapp.config.js. This improves developer experience and makes Mapbox configuration more flexible and secure. (.env.example,app.config.js,README.md, [1] [2] [3]Updated
app.jsonand related files to set dark mode as default, add iOS/Android bundle/package identifiers, and register new Expo plugins. (app.json, app.jsonL8-R34)Developer Experience & Tooling:
Added Babel and dotenv configuration for compatibility with Expo Router and environment variable loading. (
babel.config.js,package.json, [1] [2] [3]Updated Metro bundler config to support
.csvfiles as assets, enabling dynamic route loading. (metro.config.js, metro.config.jsL29-R29)Documentation and Scripts:
Expanded the
README.mdwith detailed Mapbox setup instructions and updated screenshots to reflect the new navigation and tab structure. (README.md, [1] [2]Added a conversion script for datasets, supporting easier data import and sampling. (
scripts/convert_dataset.js, scripts/convert_dataset.jsR1-R26)Summary of Key Changes:
Navigation & Routing:
NavigationContext.Navigation Features:
Configuration & Environment:
.env, environment variables, orapp.json, with a new config loader and example file. [1] [2] [3]Developer Tooling:
Documentation:
These changes lay the foundation for advanced navigation features and a more maintainable, modular app architecture.