chase пре 2 година
родитељ
комит
e4278dc98f

BIN
assets/childfriendly.png


BIN
assets/garbage.png


BIN
assets/loudnoise.png


BIN
assets/tripping.png


+ 1 - 0
package.json

@@ -84,6 +84,7 @@
     "react-native-gesture-handler": "~1.10.2",
     "react-native-get-random-values": "~1.7.0",
     "react-native-maps": "0.29.3",
+    "react-native-maps-directions": "^1.8.0",
     "react-native-material-menu": "^2.0.0",
     "react-native-modal": "^12.0.3",
     "react-native-multi-selectbox": "^1.5.0",

+ 1 - 0
src/components/Map/IndoorFloor.tsx

@@ -17,6 +17,7 @@ function IndoorFloor(props) {
     <Image height={"100%"} width={"100%"} href={require('./MainMapComponent/images/thirdfloor.png')} />,
     <Image height={"100%"} width={"100%"} href={require('./MainMapComponent/images/fourthfloor.png')} />,
     <Image height={"100%"} width={"100%"} href={require('./MainMapComponent/images/fifthfloor.png')} />,
+    // <FifthFloorC viewBox='257 153 270 290' style={{ opacity: 0.7 }} height={"100%"} width={"100%"} />,
   ]
 
   return compArray[props.floorNum]

+ 1 - 1
src/components/Map/MainMapComponent/ArrowButton.tsx

@@ -1,7 +1,7 @@
 import { View, Text, TouchableOpacity, StyleSheet, ToastAndroid} from 'react-native'
 import React from 'react'
 import { FontAwesome } from "@expo/vector-icons";
-import { colors, lmTypes } from "../../../utils/GlobalUtils";
+import { colors} from "../../../utils/GlobalUtils";
 
 
 function ArrowButton(props) {

+ 1 - 1
src/components/Map/MainMapComponent/BottomButtons.tsx

@@ -1,6 +1,6 @@
 import { View, Text, TouchableOpacity, StyleSheet, Linking } from 'react-native'
 import React from 'react'
-import { colors, lmTypes } from "../../../utils/GlobalUtils";
+import { colors } from "../../../utils/GlobalUtils";
 
 function BottomButtons(props) {
   return (

+ 8 - 5
src/components/Map/MainMapComponent/IndoorMap.tsx

@@ -5,7 +5,7 @@ import { RadioButton } from 'react-native-paper';
 import { Picker as EricPicker } from '@react-native-picker/picker';
 import ReactNativeZoomableView from '@openspacelabs/react-native-zoomable-view/src/ReactNativeZoomableView';
 import Spinner from 'react-native-spinkit'
-import { colors, lmTypes } from "../../../utils/GlobalUtils";
+import { colors, lmTypesIndoor } from "../../../utils/GlobalUtils";
 import { MapStackNavigationProp } from "../../../navigation/MapNavigator"
 import CustomModal from './modal';
 import { FontAwesome } from "@expo/vector-icons";
@@ -20,6 +20,7 @@ import Picker from 'react-native-picker-select';
 import { Landmark } from '../../../data/landmarks';
 
 
+
 interface IndoorMapProps {
   navigation: MapStackNavigationProp
   landmarks: Landmark[]
@@ -52,7 +53,7 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
           y={item.latitude * SVGdim[1]}
           width={imageDim}
           height={imageDim}
-          href={lmTypes[item.landmark_type]['image'] as ImageSourcePropType} />
+          href={lmTypesIndoor[item.landmark_type]['image'] as ImageSourcePropType} />
       )
     }
   }
@@ -70,7 +71,7 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
               await promptAddLandmark((evt.nativeEvent.locationX - imageDim / 2) / SVGdim[0], (evt.nativeEvent.locationY - imageDim / 2) / SVGdim[1], floor)
             }
             catch (err) {
-              Toast.show("An error has occured. Please ensure finger is not moving when holding down on screen.", { duration: Toast.durations.LONG, })
+              Toast.show("Please ensure finger is not moving when holding down on screen.", { duration: Toast.durations.LONG, })
 
               // Alert.alert("An error has occured." , "Please ensure thumb is not moving when holding down on screen.")
               // consider toast
@@ -192,7 +193,6 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
               panBoundaryPadding={100}
               // bindToBorders={false}
               bindToBorders={true}
-
               zoomStep={2.8}
               // initialZoom={2.2}
               maxZoom={2.8}
@@ -201,7 +201,10 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
               onLongPress={(event) => {
                 // serialize()
                 addLandmark(event)
-              }}>
+              }}
+              movementSensibility={3}
+              longPressDuration={200}
+              >
 
               <Svg onLayout={event => {
                 console.log("OFFICIAL: " + event.nativeEvent.layout.width + " , " + event.nativeEvent.layout.height)

+ 185 - 163
src/components/Map/MainMapComponent/OutdoorMap.tsx

@@ -10,9 +10,9 @@ import { RouteProp, useNavigationState } from "@react-navigation/native";
 import { booleanPointInPolygon, circle } from '@turf/turf';
 import * as Notifications from 'expo-notifications';
 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 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 Spokestack from 'react-native-spokestack';
 import { Landmark } from '../../../data/landmarks';
@@ -27,6 +27,9 @@ import { VoicePanel } from "../Panels/VoicePanel";
 import mapStyles from "./Map.styles";
 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/}.
  * @category Map
@@ -48,8 +51,8 @@ export type AuthTabsMapRouteProp = RouteProp<MainTabsParamList, 'Map'>;
  */
 
 interface OutdoorMapProps {
-    mapNavigation: MapStackNavigationProp, 
-    authNavigation: MainTabsNavigationProp, 
+    mapNavigation: MapStackNavigationProp,
+    authNavigation: MainTabsNavigationProp,
     authNavIndex: number,
     route: AuthTabsMapRouteProp,
     focusLandmark: (landmark: Landmark) => void,
@@ -69,11 +72,16 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
 
     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 
      * (See the AuthorizedNavigator page for the useEffect that will trigger this)
      */
-     useEffect(() => {
+    useEffect(() => {
         if (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)
      */
-     useEffect(() => {
+    useEffect(() => {
         console.log("[LandmarkDetails]: Landmark selected - " + props.selectedLandmarkId)
         if (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.selectedLandmarkId])
 
     /**
      * Move to pressed location when newlandmark changes
      */
-     useEffect(() => {
+    useEffect(() => {
         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])
 
     /**
      * Gets speech permissions from user, runs every time app is brought to foreground
      */
-     useEffect(() => {
+    useEffect(() => {
         const getSpeechPermissions = async () => {
             if (AppState.currentState == 'active') {
                 await getMapPermissions()
                 console.log('[Permissions]: Checking voice permissions...')
-                if (Platform.OS == 'android') {        
+                if (Platform.OS == 'android') {
                     const permitted = await checkVoicePermissions([PERMISSIONS.ANDROID.RECORD_AUDIO])
                     mapState.toggleVoicePermission(permitted)
                     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')
                     else console.log('[Permissions]: Voice permission denied')
                 }
-            }   
+            }
         }
         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.
      */
-     const flyToUser = () => {
+    const flyToUser = () => {
         console.log('[Map]: Centering on user')
         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
      */
-     const startSpeech = () => {
+    const startSpeech = () => {
         props.toggleLmDetails(false);
         props.toggleLmAdd(false);
         Spokestack.activate()
@@ -225,7 +233,7 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
      */
     const getInitialRegion = () => {
         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
      */
     const updateLocation = async (coord: LatLng) => {
-        
+
         mapState.setUserLocation(coord)
         // 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
         const newLandmarksNearUser = props.landmarks?.filter(lm => {
@@ -255,15 +263,15 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
         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 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({
                 content: {
-                  title: "⚠ Landmarks close by ⚠",
-                  body: body,
-                  data: data
+                    title: "⚠ Landmarks close by ⚠",
+                    body: body,
+                    data: data
                 },
                 trigger: { seconds: 2 },
-              });
+            });
         }
     }
 
@@ -271,7 +279,7 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
         if (mapState.landmarksNearUser?.length > 1) {
             mapState.toggleNearbyLmPanel(true)
         }
-        else if (mapState.landmarksNearUser?.length === 1) { 
+        else if (mapState.landmarksNearUser?.length === 1) {
             props.setSelectedLandmarkId(mapState.landmarksNearUser[0].id)
         }
     }
@@ -279,91 +287,105 @@ const OutdoorMap: React.FC<OutdoorMapProps> = (props) => {
     return (
         <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>
-            </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={"AIzaSyBpckHhiuieLglacinLqewC_HfWkLehwWI"} // insert your API Key here
+                        strokeWidth={4}
+                        strokeColor="#111111"
+                    />
+                    <Marker coordinate={coordinates[1]} pinColor={colors.red} /> */}
+
+
+
+
+                </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);

+ 26 - 4
src/components/Map/Panels/AddLandmarkPanel.tsx

@@ -13,16 +13,20 @@ import { ScrollView } from "react-native-gesture-handler";
 import Modal from 'react-native-modal';
 import Picker from 'react-native-picker-select';
 import { Landmark, LMPhoto, useAddLandmark } from "../../../data/landmarks";
-import { colors, lmTypes } from "../../../utils/GlobalUtils";
+import { colors, lmTypes as allLmTypes, lmTypesIndoor } from "../../../utils/GlobalUtils";
 import { IconButton, SecondaryButton } from "../../Buttons";
 import { PhotoPicker } from "../../PhotoPicker";
 import TouchOpaq from "./LandmarkDetailsPanel/TouchOpaq";
 import { Svg, Rect, Image as ImageSVG, Circle } from 'react-native-svg'
 import ReactDOMServer from 'react-dom/server'; //npm i --save-dev @types/react-dom
 
+
 import IndoorFloor from "../IndoorFloor";
 import ViewShot, { captureRef, captureScreen } from "react-native-view-shot";
 
+import { useNavigationState } from "@react-navigation/native"
+
+
 /**
  * Props for the {@link AddLandmarkPanel} component.
  */
@@ -58,6 +62,15 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandm
 
     const addLandmarkMutation = useAddLandmark()
 
+    const navigationState = useNavigationState(state => state)
+    const [currentRoute, setCurrentRoute] = useState<string>()
+    useEffect(() => {
+        const currentRouteIndex = navigationState?.routes[0]?.state?.index
+        const currentRouteName = navigationState?.routes[0]?.state?.routeNames[currentRouteIndex]
+        setCurrentRoute(currentRouteName)
+    }, [navigationState])
+
+    
     useEffect(() => {
         let eventString = Platform.OS == "android" ? 'keyboardDidShow' : Platform.OS == "ios" ? 'keyboardWillShow' : null;
         if (eventString) {
@@ -100,6 +113,11 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandm
     const imgWidth = 346
     const imgHeight = 448
     const imageDim = 25
+    
+    let lmTypes = allLmTypes
+    if(currentRoute=="Indoor") {
+        lmTypes = lmTypesIndoor
+    }
 
     useEffect(() => {
         /**
@@ -144,7 +162,6 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandm
         }
 
 
-
         // create svg content here, then pass it to addLandmarkAsync as the value of indoorLmLocImg
         // if (typeof newLandmark.floor === 'number') {
         //     let rectangle = serialize()
@@ -182,7 +199,7 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandm
             useNativeDriver={true}
             useNativeDriverForBackdrop={true}
             testID="addLMModal"
-            avoidKeyboard={false}
+            avoidKeyboard={photos?.length > 0}
             onBackdropPress={close}
             style={{ flex: 0, justifyContent: "flex-end", height: '100%', margin: 0 }}
             isVisible={visible} >
@@ -192,6 +209,9 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandm
                 enabled={photos?.length > 0}
             >
                 {console.log("state of keyboard is " + keyboardOpened)}
+                {/* {console.log("*THIS IS IN PANEL* navigationState is " + navigationState.index)}
+                {console.log("*THIS IS IN PANEL* currentRoute is " + currentRoute)} */}
+
                 <SafeAreaView style={{ backgroundColor: colors.red, height: determineModalHeight(), }}>
                     {addLandmarkMutation.isIdle ?
                         <>
@@ -253,8 +273,10 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandm
                                                 )
                                             })}
                                         />
+
                                         {newLandmark?.landmark_type ? <Image style={{ marginLeft: 20 }} source={lmTypes[newLandmark.landmark_type].image} />
                                             : null}
+                                            <Text>{currentRoute=="Indoor" ? "INDOOR" : "OUTDOOR"}</Text>
                                     </View>
                                 </View>
                                 {newLandmark?.landmark_type ?
@@ -302,8 +324,8 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandm
                         <View style={styles.container}>
                             <Svg>
                                 {console.log("x coord is " + newLandmark.longitude + " and y coord is " + newLandmark.latitude)}
-                                <ImageSVG x={newLandmark.longitude * imgWidth - 3} y={newLandmark.latitude * imgHeight - 3} width={imageDim} height={imageDim} href={lmTypes[newLandmark.landmark_type]['image'] as ImageSourcePropType} />
                                 <IndoorFloor floorNum={newLandmark.floor} />
+                                <ImageSVG x={newLandmark.longitude * imgWidth - 3} y={newLandmark.latitude * imgHeight - 3} width={imageDim} height={imageDim} href={lmTypes[newLandmark.landmark_type]['image'] as ImageSourcePropType} />
                             </Svg>
                         </View>
                     }

+ 52 - 26
src/components/Map/Panels/FilterPanel/FilterLmTypes.tsx

@@ -5,43 +5,69 @@
  * <dev@clicknpush.ca>, January 2022
  */
 
-import React from "react"
-import { View, Text } from "react-native"
+import React, { useEffect, useState } from "react";
+import { View, Text, ScrollView } from "react-native"
 import Select from "react-native-multiple-select"
-import { lmTypes } from "../../../../utils/GlobalUtils"
+import { lmTypes as lmTypess, lmTypesIndoor } from "../../../../utils/GlobalUtils"
+import { useNavigation, useNavigationState, useRoute } from "@react-navigation/native"
+
 
 interface FilterLmTypesProps {
     localFilterTypes: number[],
     setLocalFilterTypes: (types: number[]) => void
 }
 
+
+
+
 /**
  * Component that offers a selector for landmark types to be filtered
  */
-export const FilterLmTypes: React.FC<FilterLmTypesProps> = ({setLocalFilterTypes, localFilterTypes}) => {
+export const FilterLmTypes: React.FC<FilterLmTypesProps> = ({ setLocalFilterTypes, localFilterTypes }) => {
+
+    const navigationState = useNavigationState(state => state)
+    const [currentRoute, setCurrentRoute] = useState<string>()
+    useEffect(() => {
+        const currentRouteIndex = navigationState?.routes[0]?.state?.index
+        const currentRouteName = navigationState?.routes[0]?.state?.routeNames[currentRouteIndex]
+        setCurrentRoute(currentRouteName)
+    }, [navigationState])
+
+    let lmTypes = lmTypess
+
+    if (currentRoute == "Indoor") {
+        lmTypes = lmTypesIndoor
+    }
+
     return (
-        <View style={{marginBottom: 10, justifyContent: 'flex-start'}}>
-            <Text style={{marginRight: 10, marginBottom: 5}}>Landmark type:</Text>
-            <View style={{borderColor:"blue" , borderWidth:0, width: '100%', justifyContent: 'center'}}>
-                <Select
-                    styleRowList={{borderColor:"red" , borderWidth:0}}
-                    textColor='black'  
-                    itemTextColor='black'
-                    displayKey="label"
-                    uniqueKey="value"
-                    submitButtonText="Confirm"
-                    submitButtonColor='black'
-                    onSelectedItemsChange={(types) => {
-                        setLocalFilterTypes(types)
-                    }}
-
-                    selectedItems={localFilterTypes}
-                    items={Object.keys(lmTypes)?.map(icon => {
-                        return (
-                            {label: lmTypes[parseInt(icon)].label.toUpperCase(), value: parseInt(icon), key: icon}
-                        )})}>
-                </Select>
+        <View style={{ justifyContent: 'flex-start' }}>
+            <Text style={{ marginRight: 10, marginBottom: 5 }}>Landmark type:</Text>
+            <View style={{ borderColor: "blue", borderWidth: 0, width: '100%', justifyContent: 'center' }}>
+
+                {/* <ScrollView style={{height:"60%"}}> */}
+                    <Select
+                        styleRowList={{ borderColor: "red", borderWidth: 0 }}
+                        textColor='black'
+                        itemTextColor='black'
+                        displayKey="label"
+                        uniqueKey="value"
+                        submitButtonText="Confirm"
+                        submitButtonColor='black'
+                        onSelectedItemsChange={(types) => {
+                            setLocalFilterTypes(types)
+                        }}
+
+                        selectedItems={localFilterTypes}
+                        items={Object.keys(lmTypes)?.map(icon => {
+                            return (
+                                    {label: lmTypes[parseInt(icon)].label.toUpperCase(), value: parseInt(icon), key: icon }
+                            )
+                        })}>
+                    </Select>
+                {/* </ScrollView> */}
+
+                {/* {console.log("*FILTER PANEL* currentRoute is " + currentRoute)} */}
             </View>
-        </View> 
+        </View>
     )
 }

+ 20 - 1
src/components/Map/Panels/LandmarkDetailsPanel/DetailsBody.tsx

@@ -14,13 +14,16 @@ import { QueryStatus } from "react-query";
 import { LMComment } from "../../../../data/comments";
 import { Landmark, LMPhoto } from "../../../../data/landmarks";
 import { MainTabsNavigationProp } from "../../../../navigation/MainTabsNavigator";
-import { lmTypes } from "../../../../utils/GlobalUtils";
+import { lmTypes as lmTypess , lmTypesIndoor } from "../../../../utils/GlobalUtils";
 import { IconButton, PrimaryButton } from "../../../Buttons";
 import { PhotoPicker } from "../../../PhotoPicker";
 import { Separator } from "../../../Separator";
 import { CommentsContainer } from "./CommentsContainer";
 import { LandmarkPhotos } from "./LandmarkPhotos";
 
+import { useNavigationState } from "@react-navigation/native"
+
+
 interface DetailsBodyProps {
     editingEnabled: boolean,
     updatedLandmark?: Landmark,
@@ -58,6 +61,21 @@ interface DetailsBodyProps {
 */
 export const DetailsBody: React.FC<DetailsBodyProps> = (props) => {
 
+    const navigationState = useNavigationState(state => state)
+    const [currentRoute, setCurrentRoute] = useState<string>()
+    useEffect(() => {
+        const currentRouteIndex = navigationState?.routes[0]?.state?.index
+        const currentRouteName = navigationState?.routes[0]?.state?.routeNames[currentRouteIndex]
+        setCurrentRoute(currentRouteName)
+    }, [navigationState])
+
+
+    let lmTypes = lmTypess
+    if(currentRoute=="Indoor") {
+        lmTypes = lmTypesIndoor
+    }
+
+
     useEffect(() => {
         if (props.editingEnabled) {
             console.log("[LandmarkDetails]: Editing is enabled")
@@ -126,6 +144,7 @@ export const DetailsBody: React.FC<DetailsBodyProps> = (props) => {
                 <LandmarkTypePicker />
                 <Separator style={{marginBottom: 20, opacity: .5}} color="lightgray" />
                 <Text style={{color: 'white', marginBottom: 10}}>Description</Text>
+                {/* {console.log("*DETAILS BODY: currentRotue is " + currentRoute)} */}
                 <ScrollView nestedScrollEnabled={true} style={{backgroundColor: 'white', marginBottom: 20}}>
                     <TextInput 
                         multiline={true} 

+ 13 - 6
src/navigation/MapNavigator.tsx

@@ -35,7 +35,7 @@ export type MapStackParamList = {
 export type MapStackNavigationProp = StackNavigationProp<MapStackParamList>
 
 const MapNavigator: React.FC = ({ }) => {
-    const {userId, anonUserId} = useAuth()
+    const { userId, anonUserId } = useAuth()
     const mapState = useMapState()
     const authNavigation = useNavigation() as MainTabsNavigationProp
     const authRoute = useRoute() as AuthTabsMapRouteProp
@@ -112,7 +112,7 @@ const MapNavigator: React.FC = ({ }) => {
  */
     const promptAddLandmark = async (longitude?: number, latitude?: number, floor?: number) => {
         console.log('[Map]: Opening add landmark panel...')
-        mapState.setNewLandmark({ latitude: latitude, longitude: longitude, floor: floor});
+        mapState.setNewLandmark({ latitude: latitude, longitude: longitude, floor: floor });
         mapState.toggleLmAdd(true)
         mapState.toggleLmDetails(false)
     }
@@ -158,7 +158,7 @@ const MapNavigator: React.FC = ({ }) => {
 
             {/* Filter chips and button*/}
             {!mapState.filterVisible && currentRoute == 'Indoor' ?
-                <View style={{ top: 60, right: 7.5 , position: 'absolute', flexDirection: "row-reverse", justifyContent: 'flex-end' }}>
+                <View style={{ top: 60, right: 7.5, position: 'absolute', flexDirection: "row-reverse", justifyContent: 'flex-end' }}>
                     <IconButton size={16} color={colors.red} style={[mapStyles.filterButtonIndoor]} icon="filter" onPress={() => mapState.toggleFilter(true)} />
                     <ScrollView horizontal={true} contentContainerStyle={{ alignItems: 'center' }} style={{ marginHorizontal: 10, flexDirection: 'row' }}>
                         {mapState.onlyOwned ? <Chip avatar={(<FontAwesome name="user" size={20} color='gray' style={{ textAlign: 'center', textAlignVertical: 'center' }} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginRight: 5, marginLeft: 10 }} onClose={() => mapState.toggleOnlyOwned(false)}>My landmarks</Chip> : null}
@@ -187,7 +187,7 @@ const MapNavigator: React.FC = ({ }) => {
 
             {/* Create Hamburger icon */}
             {currentRoute == 'Indoor' ?
-                <View style={{ top: 100, right: 7.5 , position: 'absolute', }}>
+                <View style={{ top: 100, right: 7.5, position: 'absolute', }}>
                     <Menu
                         visible={visible}
                         anchor={<IconButton size={16} color={colors.red} style={[mapStyles.filterButtonIndoor]} icon="bars" onPress={() => setVisible(true)} />}
@@ -197,12 +197,18 @@ const MapNavigator: React.FC = ({ }) => {
                             setVisible(false)
                             navigate("Outdoor")
                             // Alert.alert("Cameron Library")
-                        }}>Go back outdoors</MenuItem>
+                        }}>Go Back Outdoors</MenuItem>
 
                         <MenuItem onPress={() => {
                             setVisible(false)
                             Linking.openURL('https://www.ualberta.ca/facilities-operations/portfolio/emergency-management-office/emergency-procedures/alarms-evacuation.html')
                             // Alert.alert("Cameron Library")
+                        }}>Emergency Procedures</MenuItem>
+
+                        <MenuItem onPress={() => {
+                            setVisible(false)
+                            Linking.openURL('https://www.library.ualberta.ca/')
+                            // Alert.alert("Cameron Library")
                         }}>Resources</MenuItem>
 
                     </Menu>
@@ -214,9 +220,10 @@ const MapNavigator: React.FC = ({ }) => {
                         anchor={<IconButton size={20} color={colors.red} style={[mapStyles.filterButtonOutdoor]} icon="bars" onPress={() => setVisible(true)} />}
                         onRequestClose={() => setVisible(false)}
                     >
-                        <MenuItem disabled={true} disabledTextColor='black' style={{alignItems: 'center', borderColor: 'black', borderBottomWidth: 1, marginHorizontal: 10, opacity: .7}}>
+                        <MenuItem disabled={true} disabledTextColor='black' style={{ alignItems: 'center', borderColor: 'black', borderBottomWidth: 1, marginHorizontal: 10, opacity: .7 }}>
                             <Text>Indoor buildings</Text>
                         </MenuItem>
+                        
                         <MenuItem onPress={() => {
                             setVisible(false)
                             navigate("Indoor")

+ 32 - 2
src/utils/GlobalUtils.ts

@@ -28,13 +28,43 @@ export const lmTypes: {[key: number]: {image: ImageRequireSource, label: string}
     7: {image: require('../../assets/power.png'), label: "power issue"},
     8: {image: require('../../assets/crosswalk.png'), label: "crosswalk issue"},
     9: {image: require('../../assets/ice.png'), label: "ice"},
+    14: {image: require('../../assets/ramp.png'), label: "ramp"},
+    16: {image: require('../../assets/childfriendly.png'), label: "child friendly area"},
+}
+
+export const lmTypesIndoor: {[key: number]: {image: ImageRequireSource, label: string}} = {
+    2: {image: require('../../assets/stairs.png'), label: "stairs"},
+    5: {image: require('../../assets/information.png'), label: "information"},
+    6: {image: require('../../assets/washroom.png'), label: "accessible washroom"},
     10: {image: require('../../assets/desk.png'), label: "desk"},
     11: {image: require('../../assets/elevator.png'), label: "elevator"},
     12: {image: require('../../assets/kiosk.png'), label: "kiosk"},
     13: {image: require('../../assets/monitor.png'), label: "monitor"},
     14: {image: require('../../assets/ramp.png'), label: "ramp"},
-    15: {image: require('../../assets/water.png'), label: "water"},
-} 
+    15: {image: require('../../assets/water.png'), label: "water fountain"},
+    16: {image: require('../../assets/childfriendly.png'), label: "child friendly area"},
+    17: {image: require('../../assets/garbage.png'), label: "Garbage cans"},
+    18: {image: require('../../assets/loudnoise.png'), label: "Loud area"},
+    19: {image: require('../../assets/tripping.png'), label: "Tripping hazard"},
+
+}
+
+// 2: {image: require('../../assets/stairs.png'), label: "stairs"},
+// 3: {image: require('../../assets/barrier.png'), label: "barrier"},
+// 4: {image: require('../../assets/uneven.png'), label: "rough terrain"},
+// 5: {image: require('../../assets/information.png'), label: "information"},
+// 6: {image: require('../../assets/washroom.png'), label: "accessible washroom"},
+// 7: {image: require('../../assets/power.png'), label: "power issue"},
+// 8: {image: require('../../assets/crosswalk.png'), label: "crosswalk issue"},
+// 9: {image: require('../../assets/ice.png'), label: "ice"},
+// 10: {image: require('../../assets/desk.png'), label: "desk"},
+// 11: {image: require('../../assets/elevator.png'), label: "elevator"},
+// 12: {image: require('../../assets/kiosk.png'), label: "kiosk"},
+// 13: {image: require('../../assets/monitor.png'), label: "monitor"},
+// 14: {image: require('../../assets/ramp.png'), label: "ramp"},
+// 15: {image: require('../../assets/water.png'), label: "water fountain"},
+// 16: {image: require('../../assets/childfriendly.png'), label: "child friendly area"},
+
 
 export const GlobalStyles = StyleSheet.create({
     itemRowContainer: {

Разлика између датотеке није приказан због своје велике величине
+ 338 - 345
yarn.lock


Неке датотеке нису приказане због велике количине промена