From a3bf6df41496ff5c65914dbcab493e6a588049c0 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Tue, 10 Oct 2023 17:50:37 -0600 Subject: [PATCH] Use Google Maps on iOS (#39) * frontend/maps: improve location following The MapView camera now pans to user location through native MapView APIs, which makes it signifigantly faster and easier to manage. * frontend/map: do not snap to location if panning Do not move the camera to the user's location unless the user has panned around earlier. * frontend/map: only disable location on gesture Do not disable automatic location following on android unless the camera panning is actually caused by a user. This does not work on iOS, but iOS also has native location following, so it's okay. * frontend/maps: back with google maps Apple Maps isn't cooperating. Use this instead to reduce compatibility requirements. I don't actually fully know if this works. * frontend: rename .env.sample to .env.template * frontend/map: cleanup * frontend: fix lint * frontend: rename .env.template to sample.env --- frontend/app.json | 7 ++++++- frontend/package-lock.json | 16 ++++++++-------- frontend/sample.env | 2 ++ frontend/src/components/Map.tsx | 32 ++++++++++++++------------------ 4 files changed, 30 insertions(+), 27 deletions(-) create mode 100644 frontend/sample.env diff --git a/frontend/app.json b/frontend/app.json index d1d58c21..9e320899 100644 --- a/frontend/app.json +++ b/frontend/app.json @@ -15,9 +15,14 @@ "**/*" ], "ios": { - "supportsTablet": true + "supportsTablet": true, + "bundleIdentifier": "org.orecart.app", + "config": { + "googleMapsApiKey": "${process.env.GOOGLE_MAPS_API_KEY_IOS}" + } }, "android": { + "package": "org.orecart.app", "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#ffffff" diff --git a/frontend/package-lock.json b/frontend/package-lock.json index aa986294..9840160a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2709,6 +2709,14 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/@expo/env/node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/@expo/env/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7941,14 +7949,6 @@ "node": ">=6.0.0" } }, - "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/dotenv-expand": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", diff --git a/frontend/sample.env b/frontend/sample.env new file mode 100644 index 00000000..7284ee43 --- /dev/null +++ b/frontend/sample.env @@ -0,0 +1,2 @@ +GOOGLE_MAPS_API_KEY_IOS=YOUR_API_KEY_HERE +GOOGLE_MAPS_API_KEY_ANDROID=YOUR_API_KEY_HERE \ No newline at end of file diff --git a/frontend/src/components/Map.tsx b/frontend/src/components/Map.tsx index 7057fd42..355ba04d 100644 --- a/frontend/src/components/Map.tsx +++ b/frontend/src/components/Map.tsx @@ -1,13 +1,14 @@ import MapView, { type Region } from 'react-native-maps' -import { StyleSheet, type ViewProps, Platform } from 'react-native' +import { StyleSheet, type ViewProps } from 'react-native' import { type Coordinate } from '../services/location' import { useRef, useState } from 'react' +import { PROVIDER_GOOGLE } from 'react-native-maps' const GOLDEN: Region = { latitude: 39.749675, longitude: -105.222606, - latitudeDelta: 0.05, - longitudeDelta: 0.05 + latitudeDelta: 0.005, + longitudeDelta: 0.005 } /** @@ -17,7 +18,7 @@ export function Map(props: ViewProps): React.ReactElement { const [userRegionChanged, setUserRegionChanged] = useState(false) const mapRef = useRef(null) - function followUserLocationAndroid(location: Coordinate | undefined): void { + function panToLocation(location: Coordinate | undefined): void { // We want to make sure we won't snap back to the user location if they decide to pan around, // so check if that's the case before panning. if (location !== undefined && mapRef.current != null && !userRegionChanged) { @@ -31,23 +32,18 @@ export function Map(props: ViewProps): React.ReactElement { return ( { followUserLocationAndroid(event.nativeEvent.coordinate) } - })} - onRegionChange={(_region, details) => { - // If the user is panning around, we don't want to snap back to their location. - // However, when we automatically pan to the location as part of the followsUserLocation - // reimplementation on android, this callback would be triggered and disable future pans. - // To prevent this, we check if the user is panning around by checking if the change was a - // gesture. This is not supported on iOS, but since we will only be panning the camera around - // on android, this is fine. + // followsUserLocation is only available on iOS maps, and isn't very cooperative anyway. + // Reimplement it ourselves. + onUserLocationChange={ event => { panToLocation(event.nativeEvent.coordinate) }} + onRegionChange={(_region, details) => { + // If the user is panning around, we don't want to snap back to their location. Note that we + // make sure to exclude camera pans from this to avoid disabling location following at soon + // as it changes. if (details.isGesture ?? true) { setUserRegionChanged(true) }