Skip to content

Commit

Permalink
integrate to use websocket on backend server
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickdemers6 committed May 9, 2023
1 parent d7805d6 commit 5584fb5
Show file tree
Hide file tree
Showing 27 changed files with 1,257 additions and 814 deletions.
1 change: 1 addition & 0 deletions app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ module.exports = {
},
package: 'com.demerstech.amesride',
},
jsEngine: 'hermes',
web: {
favicon: './assets/favicon.png',
},
Expand Down
Binary file modified assets/arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
737 changes: 451 additions & 286 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@react-native-async-storage/async-storage": "~1.17.3",
"@react-navigation/native": "^6.0.13",
"@react-navigation/native-stack": "^6.9.1",
"date-fns": "^2.29.3",
"expo": "~47.0.8",
"expo-clipboard": "~4.0.1",
"expo-constants": "~14.0.2",
Expand All @@ -37,7 +38,8 @@
"react-native-svg": "13.4.0",
"react-native-swipe-gestures": "^1.0.5",
"react-native-vector-icons": "^9.2.0",
"recoil": "^0.7.5"
"recoil": "^0.7.5",
"socket.io-client": "^4.5.4"
},
"devDependencies": {
"@babel/core": "^7.12.9",
Expand Down
4 changes: 2 additions & 2 deletions src/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ export default function Main() {
const getLocationPermission = async () => {
try {
await Location.requestForegroundPermissionsAsync();
} catch (e) {
} catch {
console.log('requestForegroundPermissionsAsync failed');
}

try {
const location = await Location.getCurrentPositionAsync();
dispatcherRef.current.setUserLocation(location);
} catch (e) {
} catch {
console.log('No location permissions granted.');
}
};
Expand Down
48 changes: 38 additions & 10 deletions src/components/Home.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { driverWithoutSerialization } from '@aveq-research/localforage-asyncstorage-driver';
import localforage from 'localforage';
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Portal } from 'react-native-paper';
import { useRecoilValue } from 'recoil';

import { dispatcherState } from '../state/atoms';
import Map from './Map/Map';
import RouteSelect from './RouteSelect';
import SettingsFAB from './Settings/FAB';
import StopInfo from './StopInfo/StopInfo';
import Websocket from './Websocket';

const styles = StyleSheet.create({
page: {
Expand All @@ -22,21 +27,44 @@ const styles = StyleSheet.create({
},
});

const setup = async () => {
const driver = driverWithoutSerialization();
await localforage.defineDriver(driver);
await localforage.setDriver(driver._driver);
};

const Home = () => {
const dispatcher = useRecoilValue(dispatcherState);
const [updatedOnce, setUpdatedOnce] = React.useState(false);

React.useEffect(() => {
(async () => {
if (!dispatcher || updatedOnce) return;
setUpdatedOnce(true);
await setup();
dispatcher?.fetchData();
dispatcher?.fetchFavoriteStops();
dispatcher?.fetchFavorites();
dispatcher?.fetchUserSettings();
})();
}, []);

return (
<>
<Portal.Host>
<View style={styles.page}>
<RouteSelect />
<View style={styles.container}>
<Map />
<StopInfo />
<Websocket>
<Portal.Host>
<View style={styles.page}>
<RouteSelect />
<View style={styles.container}>
<Map />
<StopInfo />
</View>
</View>
</View>
<SettingsFAB />
</Portal.Host>
<SettingsFAB />
</Portal.Host>
</Websocket>
</>
);
};

export default Home;
export default React.memo(Home);
32 changes: 2 additions & 30 deletions src/components/Map/Map.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as Location from 'expo-location';
import React, { useRef } from 'react';
import { View, Dimensions, AppState } from 'react-native';
import { View, Dimensions } from 'react-native';
import MapView from 'react-native-maps';
import { useRecoilValue } from 'recoil';

Expand All @@ -11,8 +10,6 @@ import RouteLine from './components/RouteLine';
import Stops from './components/Stops';
import Vehicles from './components/Vehicles';

const FETCH_BUS_SECONDS_INTERVAL = 5000;

const isuCampusRegion = {
latitude: 42.02663,
longitude: -93.6466,
Expand All @@ -38,22 +35,6 @@ const Map = () => {
if (currentStop) dispatcher?.clearCurrentStop();
};

const updateVehiclesOnForeground = () => {
const fetchVehiclesInterval = fetchVehiclesOnInterval(route, dispatcher);

// fetch bus arrivals when app comes back into foreground
const appToForegroundSubscription = AppState.addEventListener('change', (nextAppState) => {
if (nextAppState === 'active') {
fetchVehicle(route, dispatcher);
}
});

return () => {
clearInterval(fetchVehiclesInterval);
appToForegroundSubscription.remove();
};
};

const moveMapToUser = () => {
if (!location) return;

Expand All @@ -69,7 +50,6 @@ const Map = () => {
}
};

React.useEffect(updateVehiclesOnForeground, [route]);
React.useEffect(moveMapToUser, [location]);

return (
Expand All @@ -88,19 +68,11 @@ const Map = () => {
showsIndoors={false}
showsTraffic={false}>
<RouteLine route={route} />
<Stops stops={route.stops} />
<Stops />
<Vehicles />
</MapView>
</View>
);
};

const fetchVehicle = (route, dispatcher) => dispatcher?.updateVehicleLocations(route.ID);

const fetchVehiclesOnInterval = (route, dispatcher) => {
fetchVehicle(route, dispatcher);

return setInterval(() => fetchVehicle(route, dispatcher), FETCH_BUS_SECONDS_INTERVAL);
};

export default Map;
4 changes: 2 additions & 2 deletions src/components/Map/components/ImagePin.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class ImagePin extends PureComponent {
tracksViewChanges={Platform.OS === 'ios'}
onPress={this.onPress}
coordinate={{
latitude: this.props.details.Latitude,
longitude: this.props.details.Longitude,
latitude: this.props.details.latitude,
longitude: this.props.details.longitude,
}}
style={{ width: 45, height: 45 }}
anchor={{ x: 0.5, y: 0.5 }}>
Expand Down
54 changes: 35 additions & 19 deletions src/components/Map/components/RouteLine.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,51 @@ import React from 'react';
import { Polyline } from 'react-native-maps';
import { useRecoilValue } from 'recoil';

import { routesState } from '../../../state/atoms';
import { dataState } from '../../../state/atoms';
import { ALL_ROUTES, FAVORITE_ROUTES } from '../../../state/constants';
import { currentPatternSelector } from '../../../state/selectors';
import { currentRouteShapeSelector } from '../../../state/selectors';

const RouteLine = ({ route }) => {
let stops = [];
const routes = useRecoilValue(routesState);
const currPattern = useRecoilValue(currentPatternSelector);
let routes = [];
const data = useRecoilValue(dataState);
const currentRouteShape = useRecoilValue(currentRouteShapeSelector);

if (route.ID === FAVORITE_ROUTES) return null;
if (!data || !data.routes || !data.shapes || !data.trips) return;

if (route.ID === ALL_ROUTES) {
stops = Object.values(routes);
if (route.route_id === FAVORITE_ROUTES) return null;

if (route.route_id === ALL_ROUTES) {
const seenRouteWaypoints = new Set();
Object.values(data.trips).forEach((trip) => {
const key = data.routes[trip.route_id].route_id;
if (seenRouteWaypoints.has(key)) return;
seenRouteWaypoints.add(key);
routes.push({
waypoints: data.shapes[trip.shape_id]?.map((a) => ({
latitude: a.latitude,
longitude: a.longitude,
})),
route: data.routes[trip.route_id],
});
});
} else {
stops = [route];
if (!currentRouteShape) return null;
routes = [
{
waypoints: data.shapes[currentRouteShape]?.map((a) => ({
latitude: a.latitude,
longitude: a.longitude,
})),
route,
},
];
}

return stops.map((route, i) => {
return routes.map((route, i) => {
return (
<Polyline
key={i}
coordinates={
route && route.waypoints && currPattern && route.waypoints[currPattern]
? route.waypoints[currPattern]
: route && route.waypoints
? Object.values(route.waypoints)[0]
: []
}
strokeColor={route.Color || '#000000'}
coordinates={route.waypoints}
strokeColor={`#${route.route.route_color}` || '#000000'}
strokeWidth={5}
/>
);
Expand Down
29 changes: 16 additions & 13 deletions src/components/Map/components/Stops.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,33 @@ import React from 'react';
import { useRecoilValue } from 'recoil';

import { dispatcherState, favoriteStopsState } from '../../../state/atoms';
import { currentRouteStopDetailsState, favoriteStopDetailsState } from '../../../state/selectors';
import { stopsInCurrentTripSelector, favoriteStopDetailsState } from '../../../state/selectors';
import FavoriteStopImage from '../../icons/FavoriteStopImage';
import RegularStopImage from '../../icons/RegularStopImage';
import ImagePin from './ImagePin';

/**
* Renders all stops on the map for the given trip.
*/
const Stops = () => {
const favoriteStopIDs = useRecoilValue(favoriteStopsState);
const favoriteStopDetails = useRecoilValue(favoriteStopDetailsState);
const stops = useRecoilValue(currentRouteStopDetailsState);
const dispatcher = useRecoilValue(dispatcherState);
const stops = useRecoilValue(stopsInCurrentTripSelector);
const favoriteStops = useRecoilValue(favoriteStopDetailsState);
const favoriteStopIds = useRecoilValue(favoriteStopsState);

const dispatcher = useRecoilValue(dispatcherState);
const setActiveStop = (stop) => {
dispatcher.setCurrentStop(stop);
};

if (stops && stops.length > 0) {
if (stops) {
return stops.map((s, i) => {
const isFavorite = favoriteStopIDs.has(s.RtpiNumber);
// the seprate rendering of ImagePin is required to ensure a rerender of the element
const isFavorite = favoriteStopIds.has(s.stop_id);
// the seprate rendering of ImagePin is required to ensure a re-render of the element
// otherwise performance will be 0 fps
if (isFavorite)
return (
<ImagePin
key={s.ID + 'f' + i}
key={s.stop_id + 'f' + i}
details={s}
sizeMultiplier={1}
onPress={setActiveStop}
Expand All @@ -35,7 +38,7 @@ const Stops = () => {
);
return (
<ImagePin
key={s.ID + ' ' + i}
key={s.stop_id + ' ' + i}
details={s}
sizeMultiplier={1}
onPress={setActiveStop}
Expand All @@ -46,9 +49,9 @@ const Stops = () => {
});
}

if (favoriteStopDetails && favoriteStopDetails.length > 0) {
return favoriteStopDetails.map((s, i) => (
<ImagePin key={s.ID + ' ' + i} details={s} onPress={setActiveStop} favorite>
if (favoriteStops) {
return favoriteStops.map((s, i) => (
<ImagePin key={s.stop_id + ' ' + i} details={s} onPress={setActiveStop} favorite>
<FavoriteStopImage width={25} height={25} />
</ImagePin>
));
Expand Down
Loading

0 comments on commit 5584fb5

Please sign in to comment.