|
@@ -10,9 +10,9 @@ import { RouteProp, useNavigationState } from "@react-navigation/native";
|
|
import { booleanPointInPolygon, circle } from '@turf/turf';
|
|
import { booleanPointInPolygon, circle } from '@turf/turf';
|
|
import * as Notifications from 'expo-notifications';
|
|
import * as Notifications from 'expo-notifications';
|
|
import { observer } from "mobx-react";
|
|
import { observer } from "mobx-react";
|
|
-import React, { useEffect, useRef } from "react";
|
|
|
|
|
|
+import React, { useEffect, useRef, useState } from "react";
|
|
import { AppState, Image, Keyboard, Modal, Platform, TouchableOpacity, TouchableWithoutFeedback, Text, View, ActivityIndicator } from "react-native";
|
|
import { AppState, Image, Keyboard, Modal, Platform, TouchableOpacity, TouchableWithoutFeedback, Text, View, ActivityIndicator } from "react-native";
|
|
-import MapView, { LatLng, Marker, Polygon, Region } from "react-native-maps";
|
|
|
|
|
|
+import MapView, { LatLng, Marker, Polygon, Region, Polyline } from "react-native-maps";
|
|
import { PERMISSIONS } from "react-native-permissions";
|
|
import { PERMISSIONS } from "react-native-permissions";
|
|
import Spokestack from 'react-native-spokestack';
|
|
import Spokestack from 'react-native-spokestack';
|
|
import { Landmark } from '../../../data/landmarks';
|
|
import { Landmark } from '../../../data/landmarks';
|
|
@@ -27,6 +27,9 @@ import { VoicePanel } from "../Panels/VoicePanel";
|
|
import mapStyles from "./Map.styles";
|
|
import mapStyles from "./Map.styles";
|
|
import { useOutdoorMapState } from "./useMapState";
|
|
import { useOutdoorMapState } from "./useMapState";
|
|
|
|
|
|
|
|
+import MapViewDirections from 'react-native-maps-directions';
|
|
|
|
+
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* An interface representing the user location retrieved from [expo-location]{@link https://docs.expo.dev/versions/latest/sdk/location/}.
|
|
* An interface representing the user location retrieved from [expo-location]{@link https://docs.expo.dev/versions/latest/sdk/location/}.
|
|
* @category Map
|
|
* @category Map
|
|
@@ -48,8 +51,8 @@ export type AuthTabsMapRouteProp = RouteProp<MainTabsParamList, 'Map'>;
|
|
*/
|
|
*/
|
|
|
|
|
|
interface OutdoorMapProps {
|
|
interface OutdoorMapProps {
|
|
- mapNavigation: MapStackNavigationProp,
|
|
|
|
- authNavigation: MainTabsNavigationProp,
|
|
|
|
|
|
+ mapNavigation: MapStackNavigationProp,
|
|
|
|
+ authNavigation: MainTabsNavigationProp,
|
|
authNavIndex: number,
|
|
authNavIndex: number,
|
|
route: AuthTabsMapRouteProp,
|
|
route: AuthTabsMapRouteProp,
|
|
focusLandmark: (landmark: Landmark) => void,
|
|
focusLandmark: (landmark: Landmark) => void,
|
|
@@ -69,11 +72,16 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
|
|
|
|
const mapNavIndex = useNavigationState(state => state)
|
|
const mapNavIndex = useNavigationState(state => state)
|
|
|
|
|
|
|
|
+ const [coordinates] = useState([
|
|
|
|
+ { latitude: 53.527086340019856, longitude: -113.52358410971608, }, // Cameron library
|
|
|
|
+ { latitude: 53.52516024715472, longitude: -113.52154139033108, }, // University station
|
|
|
|
+ ]);
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* If the ReactNavigation route prop changes, check if it contains incoming selected landmarks, display them if there are. This will be triggered by incoming notifcations
|
|
* If the ReactNavigation route prop changes, check if it contains incoming selected landmarks, display them if there are. This will be triggered by incoming notifcations
|
|
* (See the AuthorizedNavigator page for the useEffect that will trigger this)
|
|
* (See the AuthorizedNavigator page for the useEffect that will trigger this)
|
|
*/
|
|
*/
|
|
- useEffect(() => {
|
|
|
|
|
|
+ useEffect(() => {
|
|
if (props.route?.params?.selectedLandmark) {
|
|
if (props.route?.params?.selectedLandmark) {
|
|
props.setSelectedLandmarkId(props.route?.params?.selectedLandmark)
|
|
props.setSelectedLandmarkId(props.route?.params?.selectedLandmark)
|
|
}
|
|
}
|
|
@@ -96,34 +104,34 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
/**
|
|
/**
|
|
* Toggle the lm details panel when a new selected landmark is detected (triggered by pressing on a map marker, or from the list of nearby landmarks)
|
|
* Toggle the lm details panel when a new selected landmark is detected (triggered by pressing on a map marker, or from the list of nearby landmarks)
|
|
*/
|
|
*/
|
|
- useEffect(() => {
|
|
|
|
|
|
+ useEffect(() => {
|
|
console.log("[LandmarkDetails]: Landmark selected - " + props.selectedLandmarkId)
|
|
console.log("[LandmarkDetails]: Landmark selected - " + props.selectedLandmarkId)
|
|
if (props.selectedLandmarkId) {
|
|
if (props.selectedLandmarkId) {
|
|
const landmark = props.landmarks.find(lm => lm.id == props.selectedLandmarkId)
|
|
const landmark = props.landmarks.find(lm => lm.id == props.selectedLandmarkId)
|
|
- mapState.mapRef.current.animateToRegion({latitude: landmark.latitude, longitude: landmark.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01})
|
|
|
|
|
|
+ mapState.mapRef.current.animateToRegion({ latitude: landmark.latitude, longitude: landmark.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01 })
|
|
props.toggleLmDetails(true)
|
|
props.toggleLmDetails(true)
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
}, [props.selectedLandmarkId])
|
|
}, [props.selectedLandmarkId])
|
|
|
|
|
|
/**
|
|
/**
|
|
* Move to pressed location when newlandmark changes
|
|
* Move to pressed location when newlandmark changes
|
|
*/
|
|
*/
|
|
- useEffect(() => {
|
|
|
|
|
|
+ useEffect(() => {
|
|
if (props.selectedLandmarkId) {
|
|
if (props.selectedLandmarkId) {
|
|
- mapState.mapRef.current.animateToRegion({latitude: props.newLandmark?.latitude, longitude: props.newLandmark?.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01})
|
|
|
|
|
|
+ mapState.mapRef.current.animateToRegion({ latitude: props.newLandmark?.latitude, longitude: props.newLandmark?.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01 })
|
|
}
|
|
}
|
|
}, [props.newLandmark])
|
|
}, [props.newLandmark])
|
|
|
|
|
|
/**
|
|
/**
|
|
* Gets speech permissions from user, runs every time app is brought to foreground
|
|
* Gets speech permissions from user, runs every time app is brought to foreground
|
|
*/
|
|
*/
|
|
- useEffect(() => {
|
|
|
|
|
|
+ useEffect(() => {
|
|
const getSpeechPermissions = async () => {
|
|
const getSpeechPermissions = async () => {
|
|
if (AppState.currentState == 'active') {
|
|
if (AppState.currentState == 'active') {
|
|
await getMapPermissions()
|
|
await getMapPermissions()
|
|
console.log('[Permissions]: Checking voice permissions...')
|
|
console.log('[Permissions]: Checking voice permissions...')
|
|
- if (Platform.OS == 'android') {
|
|
|
|
|
|
+ if (Platform.OS == 'android') {
|
|
const permitted = await checkVoicePermissions([PERMISSIONS.ANDROID.RECORD_AUDIO])
|
|
const permitted = await checkVoicePermissions([PERMISSIONS.ANDROID.RECORD_AUDIO])
|
|
mapState.toggleVoicePermission(permitted)
|
|
mapState.toggleVoicePermission(permitted)
|
|
if (permitted) console.log('[Permissions]: Voice permission granted')
|
|
if (permitted) console.log('[Permissions]: Voice permission granted')
|
|
@@ -135,86 +143,86 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
if (permitted) console.log('[Permissions]: Voice permission granted')
|
|
if (permitted) console.log('[Permissions]: Voice permission granted')
|
|
else console.log('[Permissions]: Voice permission denied')
|
|
else console.log('[Permissions]: Voice permission denied')
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|
|
getSpeechPermissions()
|
|
getSpeechPermissions()
|
|
- }, [AppState.currentState])
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Gets foreground location permissions from user, runs every time app is brought to foreground
|
|
|
|
- */
|
|
|
|
- useEffect(() => {
|
|
|
|
- const checkForegroundLocationPermissions = async () => {
|
|
|
|
- if (AppState.currentState == 'active') {
|
|
|
|
- console.log('[Permissions]: Checking location permissions...')
|
|
|
|
- if (Platform.OS == 'android') {
|
|
|
|
- const permitted = await checkVoicePermissions([PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION, PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION])
|
|
|
|
- mapState.toggleFgroundLocationPermission(permitted)
|
|
|
|
- if (permitted) console.log('[Permissions]: Location permission granted')
|
|
|
|
- else console.log('[Permissions]: Location permission denied')
|
|
|
|
- }
|
|
|
|
- else if (Platform.OS == 'ios') {
|
|
|
|
- const permitted = await checkVoicePermissions([PERMISSIONS.IOS.LOCATION_WHEN_IN_USE])
|
|
|
|
- mapState.toggleFgroundLocationPermission(permitted)
|
|
|
|
- if (permitted) console.log('[Permissions]: Location permission granted')
|
|
|
|
- else console.log('[Permissions]: Location permission denied')
|
|
|
|
- }
|
|
|
|
|
|
+ }, [AppState.currentState])
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets foreground location permissions from user, runs every time app is brought to foreground
|
|
|
|
+ */
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ const checkForegroundLocationPermissions = async () => {
|
|
|
|
+ if (AppState.currentState == 'active') {
|
|
|
|
+ console.log('[Permissions]: Checking location permissions...')
|
|
|
|
+ if (Platform.OS == 'android') {
|
|
|
|
+ const permitted = await checkVoicePermissions([PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION, PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION])
|
|
|
|
+ mapState.toggleFgroundLocationPermission(permitted)
|
|
|
|
+ if (permitted) console.log('[Permissions]: Location permission granted')
|
|
|
|
+ else console.log('[Permissions]: Location permission denied')
|
|
}
|
|
}
|
|
- }
|
|
|
|
- checkForegroundLocationPermissions();
|
|
|
|
- }, [AppState.currentState])
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Gets background location permissions from user, runs every time app is brought to foreground
|
|
|
|
- */
|
|
|
|
- useEffect(() => {
|
|
|
|
- const checkBackgroundLocationPermissions = async () => {
|
|
|
|
- if (AppState.currentState == 'active') {
|
|
|
|
- if (Platform.OS == 'android') {
|
|
|
|
- const permitted = await checkVoicePermissions([PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION])
|
|
|
|
- mapState.toggleBgroundLocationPermission(permitted)
|
|
|
|
- if (permitted) console.log('[Permissions]: Background location permission granted')
|
|
|
|
- else console.log('[Permissions]: Background location permission denied')
|
|
|
|
- }
|
|
|
|
- else if (Platform.OS == 'ios') {
|
|
|
|
- const permitted = await checkVoicePermissions([PERMISSIONS.IOS.LOCATION_ALWAYS])
|
|
|
|
- mapState.toggleBgroundLocationPermission(permitted)
|
|
|
|
- if (permitted) console.log('[Permissions]: Background location permission granted')
|
|
|
|
- else console.log('[Permissions]: Background location permission denied')
|
|
|
|
- }
|
|
|
|
|
|
+ else if (Platform.OS == 'ios') {
|
|
|
|
+ const permitted = await checkVoicePermissions([PERMISSIONS.IOS.LOCATION_WHEN_IN_USE])
|
|
|
|
+ mapState.toggleFgroundLocationPermission(permitted)
|
|
|
|
+ if (permitted) console.log('[Permissions]: Location permission granted')
|
|
|
|
+ else console.log('[Permissions]: Location permission denied')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- checkBackgroundLocationPermissions();
|
|
|
|
- }, [AppState.currentState])
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Gets net location permission the existing location permission states. It will check foreground and background permissions and AppState,
|
|
|
|
- * then from that it will decide if location-enabled features should be activated (through the mapState state values).
|
|
|
|
- */
|
|
|
|
- useEffect(() => {
|
|
|
|
- const updateLocationPermissionOnAppStateChange = async () => {
|
|
|
|
- const netLocationPermissions = mapState.bgroundLocationPermission || (mapState.fgroundLocationPermission && AppState.currentState == 'active')
|
|
|
|
- console.log('[Permissions]: Appstate, or location permissions changed, net location permissions found to be: ' + netLocationPermissions)
|
|
|
|
- mapState.toggleLocationPermitted(netLocationPermissions)
|
|
|
|
|
|
+ }
|
|
|
|
+ checkForegroundLocationPermissions();
|
|
|
|
+ }, [AppState.currentState])
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets background location permissions from user, runs every time app is brought to foreground
|
|
|
|
+ */
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ const checkBackgroundLocationPermissions = async () => {
|
|
|
|
+ if (AppState.currentState == 'active') {
|
|
|
|
+ if (Platform.OS == 'android') {
|
|
|
|
+ const permitted = await checkVoicePermissions([PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION])
|
|
|
|
+ mapState.toggleBgroundLocationPermission(permitted)
|
|
|
|
+ if (permitted) console.log('[Permissions]: Background location permission granted')
|
|
|
|
+ else console.log('[Permissions]: Background location permission denied')
|
|
|
|
+ }
|
|
|
|
+ else if (Platform.OS == 'ios') {
|
|
|
|
+ const permitted = await checkVoicePermissions([PERMISSIONS.IOS.LOCATION_ALWAYS])
|
|
|
|
+ mapState.toggleBgroundLocationPermission(permitted)
|
|
|
|
+ if (permitted) console.log('[Permissions]: Background location permission granted')
|
|
|
|
+ else console.log('[Permissions]: Background location permission denied')
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- updateLocationPermissionOnAppStateChange()
|
|
|
|
- }, [AppState.currentState, mapState.bgroundLocationPermission, mapState.fgroundLocationPermission])
|
|
|
|
|
|
+ }
|
|
|
|
+ checkBackgroundLocationPermissions();
|
|
|
|
+ }, [AppState.currentState])
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets net location permission the existing location permission states. It will check foreground and background permissions and AppState,
|
|
|
|
+ * then from that it will decide if location-enabled features should be activated (through the mapState state values).
|
|
|
|
+ */
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ const updateLocationPermissionOnAppStateChange = async () => {
|
|
|
|
+ const netLocationPermissions = mapState.bgroundLocationPermission || (mapState.fgroundLocationPermission && AppState.currentState == 'active')
|
|
|
|
+ console.log('[Permissions]: Appstate, or location permissions changed, net location permissions found to be: ' + netLocationPermissions)
|
|
|
|
+ mapState.toggleLocationPermitted(netLocationPermissions)
|
|
|
|
+ }
|
|
|
|
+ updateLocationPermissionOnAppStateChange()
|
|
|
|
+ }, [AppState.currentState, mapState.bgroundLocationPermission, mapState.fgroundLocationPermission])
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Animates the map to fly over to and focus on the user's location.
|
|
* Animates the map to fly over to and focus on the user's location.
|
|
*/
|
|
*/
|
|
- const flyToUser = () => {
|
|
|
|
|
|
+ const flyToUser = () => {
|
|
console.log('[Map]: Centering on user')
|
|
console.log('[Map]: Centering on user')
|
|
if (mapState.userLocation) {
|
|
if (mapState.userLocation) {
|
|
- mapState.mapRef.current?.animateToRegion({latitude: mapState.userLocation.latitude, longitude: mapState.userLocation.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01})
|
|
|
|
|
|
+ mapState.mapRef.current?.animateToRegion({ latitude: mapState.userLocation.latitude, longitude: mapState.userLocation.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01 })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* Activates speech recognition and opens the voice panel
|
|
* Activates speech recognition and opens the voice panel
|
|
*/
|
|
*/
|
|
- const startSpeech = () => {
|
|
|
|
|
|
+ const startSpeech = () => {
|
|
props.toggleLmDetails(false);
|
|
props.toggleLmDetails(false);
|
|
props.toggleLmAdd(false);
|
|
props.toggleLmAdd(false);
|
|
Spokestack.activate()
|
|
Spokestack.activate()
|
|
@@ -225,7 +233,7 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
*/
|
|
*/
|
|
const getInitialRegion = () => {
|
|
const getInitialRegion = () => {
|
|
if (mapState.userLocation) {
|
|
if (mapState.userLocation) {
|
|
- return {latitude: mapState.userLocation.latitude, longitude: mapState.userLocation.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01}
|
|
|
|
|
|
+ return { latitude: mapState.userLocation.latitude, longitude: mapState.userLocation.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01 }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -233,10 +241,10 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
* Method that runs every time user location changes, updates user location state in memory and checks if any landmarks are nearby
|
|
* Method that runs every time user location changes, updates user location state in memory and checks if any landmarks are nearby
|
|
*/
|
|
*/
|
|
const updateLocation = async (coord: LatLng) => {
|
|
const updateLocation = async (coord: LatLng) => {
|
|
-
|
|
|
|
|
|
+
|
|
mapState.setUserLocation(coord)
|
|
mapState.setUserLocation(coord)
|
|
// get 10m radius around user
|
|
// get 10m radius around user
|
|
- const userAlertRadius = circle([coord.longitude, coord.latitude], 10, {units: 'meters'})
|
|
|
|
|
|
+ const userAlertRadius = circle([coord.longitude, coord.latitude], 10, { units: 'meters' })
|
|
|
|
|
|
// check each landmark to see if its inside user radius. if it is, and it isn't already in the list of notified landmarks, add it
|
|
// check each landmark to see if its inside user radius. if it is, and it isn't already in the list of notified landmarks, add it
|
|
const newLandmarksNearUser = props.landmarks?.filter(lm => {
|
|
const newLandmarksNearUser = props.landmarks?.filter(lm => {
|
|
@@ -255,15 +263,15 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
if (newLandmarksNotPreviouslyNearUser?.length > 0) {
|
|
if (newLandmarksNotPreviouslyNearUser?.length > 0) {
|
|
const body = newLandmarksNotPreviouslyNearUser.length > 1 ? "There are new landmarks near by. Tap here to view" : "There is a new landmark close by. Tap here to view"
|
|
const body = newLandmarksNotPreviouslyNearUser.length > 1 ? "There are new landmarks near by. Tap here to view" : "There is a new landmark close by. Tap here to view"
|
|
const notifType: NotifType = newLandmarksNotPreviouslyNearUser.length > 1 ? 'near-landmarks' : 'near-landmark'
|
|
const notifType: NotifType = newLandmarksNotPreviouslyNearUser.length > 1 ? 'near-landmarks' : 'near-landmark'
|
|
- const data = {notif_type: notifType, landmarks: newLandmarksNotPreviouslyNearUser.length == 1 ? newLandmarksNearUser : null}
|
|
|
|
|
|
+ const data = { notif_type: notifType, landmarks: newLandmarksNotPreviouslyNearUser.length == 1 ? newLandmarksNearUser : null }
|
|
await Notifications.scheduleNotificationAsync({
|
|
await Notifications.scheduleNotificationAsync({
|
|
content: {
|
|
content: {
|
|
- title: "⚠ Landmarks close by ⚠",
|
|
|
|
- body: body,
|
|
|
|
- data: data
|
|
|
|
|
|
+ title: "⚠ Landmarks close by ⚠",
|
|
|
|
+ body: body,
|
|
|
|
+ data: data
|
|
},
|
|
},
|
|
trigger: { seconds: 2 },
|
|
trigger: { seconds: 2 },
|
|
- });
|
|
|
|
|
|
+ });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -271,7 +279,7 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
if (mapState.landmarksNearUser?.length > 1) {
|
|
if (mapState.landmarksNearUser?.length > 1) {
|
|
mapState.toggleNearbyLmPanel(true)
|
|
mapState.toggleNearbyLmPanel(true)
|
|
}
|
|
}
|
|
- else if (mapState.landmarksNearUser?.length === 1) {
|
|
|
|
|
|
+ else if (mapState.landmarksNearUser?.length === 1) {
|
|
props.setSelectedLandmarkId(mapState.landmarksNearUser[0].id)
|
|
props.setSelectedLandmarkId(mapState.landmarksNearUser[0].id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -279,91 +287,105 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
|
|
return (
|
|
return (
|
|
<TouchableWithoutFeedback>
|
|
<TouchableWithoutFeedback>
|
|
<>
|
|
<>
|
|
- {/*Main map component*/}
|
|
|
|
- <Modal transparent={true} animationType="fade" visible={mapState.loading}>
|
|
|
|
- <View style={{flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.3)'}}>
|
|
|
|
- <View style={{width: '60%', height: '30%', backgroundColor: colors.red, justifyContent: 'center', alignItems: 'center', borderRadius: 20}}>
|
|
|
|
- <ActivityIndicator size="large" color="white" style={{marginBottom: 20}}/>
|
|
|
|
- <Text style={{fontSize: 15, color: 'white'}}>Refreshing</Text>
|
|
|
|
|
|
+ {/*Main map component*/}
|
|
|
|
+ <Modal transparent={true} animationType="fade" visible={mapState.loading}>
|
|
|
|
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.3)' }}>
|
|
|
|
+ <View style={{ width: '60%', height: '30%', backgroundColor: colors.red, justifyContent: 'center', alignItems: 'center', borderRadius: 20 }}>
|
|
|
|
+ <ActivityIndicator size="large" color="white" style={{ marginBottom: 20 }} />
|
|
|
|
+ <Text style={{ fontSize: 15, color: 'white' }}>Refreshing</Text>
|
|
|
|
+ </View>
|
|
</View>
|
|
</View>
|
|
- </View>
|
|
|
|
- </Modal>
|
|
|
|
- <MapView
|
|
|
|
- key={mapState.refreshKey}
|
|
|
|
- toolbarEnabled={false}
|
|
|
|
- onPress={() => Keyboard.dismiss()}
|
|
|
|
- testID="mapView"
|
|
|
|
- ref={mapState.mapRef}
|
|
|
|
- style={{width: '100%', height: '100%'}}
|
|
|
|
- initialRegion={getInitialRegion()}
|
|
|
|
- onLongPress={async (e) => await props.promptAddLandmark(e.nativeEvent.coordinate.longitude, e.nativeEvent.coordinate.latitude)}
|
|
|
|
- showsUserLocation={mapState.locationPermitted}
|
|
|
|
- onUserLocationChange={e => updateLocation(e.nativeEvent.coordinate)}
|
|
|
|
- followsUserLocation={mapState.followUser}
|
|
|
|
- showsMyLocationButton={false}>
|
|
|
|
- <Polygon // polygon for cameron library
|
|
|
|
- coordinates={[
|
|
|
|
- {latitude: 53.527190, longitude: -113.524205 },
|
|
|
|
- {latitude: 53.526510, longitude: -113.524205 },
|
|
|
|
- {latitude: 53.526510, longitude: -113.523452 },
|
|
|
|
- {latitude: 53.527190, longitude: -113.523452 },
|
|
|
|
- // { name: "5", latitude: 60, longitude: -105 },
|
|
|
|
- ]}
|
|
|
|
- fillColor={`rgba(100,100,200,0.3)`}
|
|
|
|
- strokeWidth={2.5}
|
|
|
|
- tappable={true}
|
|
|
|
- onPress={() => props.mapNavigation.navigate("Indoor")}
|
|
|
|
- />
|
|
|
|
-
|
|
|
|
- {props.applyFilters(props.landmarks)?.map((landmark) => {
|
|
|
|
- if(landmark.floor == null){
|
|
|
|
- let trackChanges = false;
|
|
|
|
- if (landmark?.id == props.selectedLandmarkId) {
|
|
|
|
- trackChanges = true;
|
|
|
|
|
|
+ </Modal>
|
|
|
|
+ <MapView
|
|
|
|
+ key={mapState.refreshKey}
|
|
|
|
+ toolbarEnabled={false}
|
|
|
|
+ onPress={() => Keyboard.dismiss()}
|
|
|
|
+ testID="mapView"
|
|
|
|
+ ref={mapState.mapRef}
|
|
|
|
+ style={{ width: '100%', height: '100%' }}
|
|
|
|
+ initialRegion={getInitialRegion()}
|
|
|
|
+ onLongPress={async (e) => await props.promptAddLandmark(e.nativeEvent.coordinate.longitude, e.nativeEvent.coordinate.latitude)}
|
|
|
|
+ showsUserLocation={mapState.locationPermitted}
|
|
|
|
+ onUserLocationChange={e => updateLocation(e.nativeEvent.coordinate)}
|
|
|
|
+ followsUserLocation={mapState.followUser}
|
|
|
|
+ showsMyLocationButton={false}>
|
|
|
|
+ <Polygon // polygon for cameron library
|
|
|
|
+ coordinates={[
|
|
|
|
+ { latitude: 53.527190, longitude: -113.524205 },
|
|
|
|
+ { latitude: 53.526510, longitude: -113.524205 },
|
|
|
|
+ { latitude: 53.526510, longitude: -113.523452 },
|
|
|
|
+ { latitude: 53.527190, longitude: -113.523452 },
|
|
|
|
+ // { name: "5", latitude: 60, longitude: -105 },
|
|
|
|
+ ]}
|
|
|
|
+ fillColor={`rgba(100,100,200,0.3)`}
|
|
|
|
+ strokeWidth={2.5}
|
|
|
|
+ tappable={true}
|
|
|
|
+ onPress={() => props.mapNavigation.navigate("Indoor")}
|
|
|
|
+ />
|
|
|
|
+
|
|
|
|
+ {props.applyFilters(props.landmarks)?.map((landmark) => {
|
|
|
|
+ if (landmark.floor == null) {
|
|
|
|
+ let trackChanges = false;
|
|
|
|
+ if (landmark?.id == props.selectedLandmarkId) {
|
|
|
|
+ trackChanges = true;
|
|
|
|
+ }
|
|
|
|
+ return (
|
|
|
|
+ <Marker
|
|
|
|
+ tracksViewChanges={trackChanges}
|
|
|
|
+ onPress={() => props.focusLandmark(landmark)}
|
|
|
|
+ key={landmark.id}
|
|
|
|
+ coordinate={{ latitude: landmark.latitude as number, longitude: landmark.longitude as number }} >
|
|
|
|
+ {landmark.landmark_type ? <Image style={{ height: 35, width: 25 }} source={lmTypes[landmark.landmark_type].image} /> : null}
|
|
|
|
+ </Marker>)
|
|
}
|
|
}
|
|
- return (
|
|
|
|
- <Marker
|
|
|
|
- tracksViewChanges={trackChanges}
|
|
|
|
- onPress={() => props.focusLandmark(landmark)}
|
|
|
|
- key={landmark.id}
|
|
|
|
- coordinate={{latitude: landmark.latitude as number, longitude: landmark.longitude as number}} >
|
|
|
|
- { landmark.landmark_type ? <Image style={{height: 35, width: 25}} source={lmTypes[landmark.landmark_type].image} /> : null}
|
|
|
|
- </Marker>)}
|
|
|
|
}
|
|
}
|
|
- )}
|
|
|
|
-
|
|
|
|
- </MapView>
|
|
|
|
- {/*Map buttons*/}
|
|
|
|
- {mapState.landmarksNearUser?.length > 0 ?
|
|
|
|
- <TouchableOpacity style={[mapStyles.lowerMapButton, mapStyles.alertButton]} onPress={focusNearbyLandmarks}>
|
|
|
|
- <FontAwesome name='exclamation-triangle' size={20} color='white' />
|
|
|
|
- <Badge positioning={{bottom: 7, right: 4}} value={mapState.landmarksNearUser.length}/>
|
|
|
|
- </TouchableOpacity> : null}
|
|
|
|
- {mapState.locationPermitted && mapState.voicePermission ?
|
|
|
|
- <IconButton size={20} color='white' style={[mapStyles.lowerMapButton, mapStyles.voiceButton]} icon="microphone" onPress={startSpeech}/>: null}
|
|
|
|
- <IconButton size={20} color='white' style={[mapStyles.lowerMapButton, mapStyles.addLandmarkButton]} icon="plus" onPress={async () => await props.promptAddLandmark(mapState.userLocation.longitude, mapState.userLocation.latitude)}/>
|
|
|
|
- <IconButton size={20} color='white' style={[mapStyles.lowerMapButton, mapStyles.userLocationButton]} icon="location-arrow" onPress={flyToUser}/>
|
|
|
|
- <NearbyLandmarksPanel
|
|
|
|
- focusLandmark={props.focusLandmark}
|
|
|
|
- nearbyLmPanelVisible={mapState.nearbyLmPanelVisible}
|
|
|
|
- toggleAlertedLmPanel={mapState.toggleNearbyLmPanel}
|
|
|
|
- nearbyLandmarks={mapState.landmarksNearUser}/>
|
|
|
|
- {/*Map Panels*/}
|
|
|
|
- {mapState.voicePermission && mapState.locationPermitted ?
|
|
|
|
- <VoicePanel
|
|
|
|
- landmarksNearby={mapState.landmarksNearUser?.length > 0}
|
|
|
|
- toggleAlertedLandmarksVisible={mapState.toggleNearbyLmPanel}
|
|
|
|
- navigation={props.authNavigation}
|
|
|
|
- userCoords={{longitude: mapState.userLocation?.longitude, latitude: mapState.userLocation?.latitude}}
|
|
|
|
- toggleVoiceVisible={mapState.toggleVoiceVisible}
|
|
|
|
- toggleLmDetails={props.toggleLmDetails}
|
|
|
|
- setSelectedLandmarkId={props.setSelectedLandmarkId}
|
|
|
|
- voiceVisible={mapState.voiceVisible}
|
|
|
|
- newLandmark={props.newLandmark}
|
|
|
|
- setNewLandmark={props.setNewLandmark}
|
|
|
|
- /> : null }
|
|
|
|
|
|
+ )}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ <MapViewDirections
|
|
|
|
+ origin={coordinates[0]}
|
|
|
|
+ destination={coordinates[1]}
|
|
|
|
+ apikey={""} // insert your API Key here
|
|
|
|
+ strokeWidth={4}
|
|
|
|
+ strokeColor="#111111"
|
|
|
|
+ />
|
|
|
|
+ <Marker coordinate={coordinates[1]} />
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ </MapView>
|
|
|
|
+ {/*Map buttons*/}
|
|
|
|
+ {mapState.landmarksNearUser?.length > 0 ?
|
|
|
|
+ <TouchableOpacity style={[mapStyles.lowerMapButton, mapStyles.alertButton]} onPress={focusNearbyLandmarks}>
|
|
|
|
+ <FontAwesome name='exclamation-triangle' size={20} color='white' />
|
|
|
|
+ <Badge positioning={{ bottom: 7, right: 4 }} value={mapState.landmarksNearUser.length} />
|
|
|
|
+ </TouchableOpacity> : null}
|
|
|
|
+ {mapState.locationPermitted && mapState.voicePermission ?
|
|
|
|
+ <IconButton size={20} color='white' style={[mapStyles.lowerMapButton, mapStyles.voiceButton]} icon="microphone" onPress={startSpeech} /> : null}
|
|
|
|
+ <IconButton size={20} color='white' style={[mapStyles.lowerMapButton, mapStyles.addLandmarkButton]} icon="plus" onPress={async () => await props.promptAddLandmark(mapState.userLocation.longitude, mapState.userLocation.latitude)} />
|
|
|
|
+ <IconButton size={20} color='white' style={[mapStyles.lowerMapButton, mapStyles.userLocationButton]} icon="location-arrow" onPress={flyToUser} />
|
|
|
|
+ <NearbyLandmarksPanel
|
|
|
|
+ focusLandmark={props.focusLandmark}
|
|
|
|
+ nearbyLmPanelVisible={mapState.nearbyLmPanelVisible}
|
|
|
|
+ toggleAlertedLmPanel={mapState.toggleNearbyLmPanel}
|
|
|
|
+ nearbyLandmarks={mapState.landmarksNearUser} />
|
|
|
|
+ {/*Map Panels*/}
|
|
|
|
+ {mapState.voicePermission && mapState.locationPermitted ?
|
|
|
|
+ <VoicePanel
|
|
|
|
+ landmarksNearby={mapState.landmarksNearUser?.length > 0}
|
|
|
|
+ toggleAlertedLandmarksVisible={mapState.toggleNearbyLmPanel}
|
|
|
|
+ navigation={props.authNavigation}
|
|
|
|
+ userCoords={{ longitude: mapState.userLocation?.longitude, latitude: mapState.userLocation?.latitude }}
|
|
|
|
+ toggleVoiceVisible={mapState.toggleVoiceVisible}
|
|
|
|
+ toggleLmDetails={props.toggleLmDetails}
|
|
|
|
+ setSelectedLandmarkId={props.setSelectedLandmarkId}
|
|
|
|
+ voiceVisible={mapState.voiceVisible}
|
|
|
|
+ newLandmark={props.newLandmark}
|
|
|
|
+ setNewLandmark={props.setNewLandmark}
|
|
|
|
+ /> : null}
|
|
</>
|
|
</>
|
|
- </TouchableWithoutFeedback> )
|
|
|
|
|
|
+ </TouchableWithoutFeedback>)
|
|
}
|
|
}
|
|
|
|
|
|
export default observer(OutdoorMap);
|
|
export default observer(OutdoorMap);
|