Jelajahi Sumber

added dropdown support for iOS

Eric Li 2 tahun lalu
induk
melakukan
f3814c3bf9

+ 48 - 0
package-lock.json

@@ -70,6 +70,7 @@
         "react-native-picker-select": "^7.0.0",
         "react-native-popup-menu": "^0.15.12",
         "react-native-reanimated": "~2.2.0",
+        "react-native-root-toast": "^3.3.0",
         "react-native-safe-area-context": "3.3.2",
         "react-native-screens": "~3.8.0",
         "react-native-sectioned-multi-select": "^0.8.1",
@@ -78,6 +79,7 @@
         "react-native-spokestack": "^6.1.4",
         "react-native-svg": "^12.1.1",
         "react-native-svg-transformer": "^1.0.0",
+        "react-native-toast-message": "^2.1.3",
         "react-native-web": "^0.13",
         "react-native-windows": "0.64.2",
         "react-query": "^3.19.0",
@@ -25085,6 +25087,23 @@
         "ua-parser-js": "^0.7.18"
       }
     },
+    "node_modules/react-native-root-siblings": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/react-native-root-siblings/-/react-native-root-siblings-4.1.1.tgz",
+      "integrity": "sha512-sdmLElNs5PDWqmZmj4/aNH4anyxreaPm61c4ZkRiR8SO/GzLg6KjAbb0e17RmMdnBdD0AIQbS38h/l55YKN4ZA=="
+    },
+    "node_modules/react-native-root-toast": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/react-native-root-toast/-/react-native-root-toast-3.3.0.tgz",
+      "integrity": "sha512-C4Pqu+Ae7kXsYJwTvz8NshyJ9SL5YJd+/vCkvgDAxxR8AYlPFggEcTCMNARIWXuRwthLbuwcakh4z9k6qg95dg==",
+      "dependencies": {
+        "prop-types": "^15.5.10",
+        "react-native-root-siblings": "^4.0.0"
+      },
+      "peerDependencies": {
+        "react-native": ">=0.47.0"
+      }
+    },
     "node_modules/react-native-safe-area-context": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz",
@@ -25224,6 +25243,15 @@
         "boolbase": "~1.0.0"
       }
     },
+    "node_modules/react-native-toast-message": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/react-native-toast-message/-/react-native-toast-message-2.1.3.tgz",
+      "integrity": "sha512-K3hHSWezWixxOZUDbxPSarEG+tPv2WcaJG4L7dvRUC1TOKNVCEKzXjsx+6ZMxllDrJ0sFczuYGqZibGpFe/ubA==",
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
     "node_modules/react-native-vector-icons": {
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-8.1.0.tgz",
@@ -51123,6 +51151,20 @@
         }
       }
     },
+    "react-native-root-siblings": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/react-native-root-siblings/-/react-native-root-siblings-4.1.1.tgz",
+      "integrity": "sha512-sdmLElNs5PDWqmZmj4/aNH4anyxreaPm61c4ZkRiR8SO/GzLg6KjAbb0e17RmMdnBdD0AIQbS38h/l55YKN4ZA=="
+    },
+    "react-native-root-toast": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/react-native-root-toast/-/react-native-root-toast-3.3.0.tgz",
+      "integrity": "sha512-C4Pqu+Ae7kXsYJwTvz8NshyJ9SL5YJd+/vCkvgDAxxR8AYlPFggEcTCMNARIWXuRwthLbuwcakh4z9k6qg95dg==",
+      "requires": {
+        "prop-types": "^15.5.10",
+        "react-native-root-siblings": "^4.0.0"
+      }
+    },
     "react-native-safe-area-context": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz",
@@ -51236,6 +51278,12 @@
         "path-dirname": "^1.0.2"
       }
     },
+    "react-native-toast-message": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/react-native-toast-message/-/react-native-toast-message-2.1.3.tgz",
+      "integrity": "sha512-K3hHSWezWixxOZUDbxPSarEG+tPv2WcaJG4L7dvRUC1TOKNVCEKzXjsx+6ZMxllDrJ0sFczuYGqZibGpFe/ubA==",
+      "requires": {}
+    },
     "react-native-vector-icons": {
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-8.1.0.tgz",

+ 3 - 0
package.json

@@ -88,6 +88,7 @@
     "react-native-picker-select": "^7.0.0",
     "react-native-popup-menu": "^0.15.12",
     "react-native-reanimated": "~2.2.0",
+    "react-native-root-toast": "^3.3.0",
     "react-native-safe-area-context": "3.3.2",
     "react-native-screens": "~3.8.0",
     "react-native-sectioned-multi-select": "^0.8.1",
@@ -96,6 +97,8 @@
     "react-native-spokestack": "^6.1.4",
     "react-native-svg": "^12.1.1",
     "react-native-svg-transformer": "^1.0.0",
+    "react-native-toast-message": "^2.1.3",
+    "react-native-view-shot": "3.1.2",
     "react-native-web": "^0.13",
     "react-native-windows": "0.64.2",
     "react-query": "^3.19.0",

+ 42 - 0
src/components/Map/MainMapComponent/ArrowButton.tsx

@@ -0,0 +1,42 @@
+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";
+
+
+function ArrowButton(props) {
+    if (props.num != 0) {
+        return (
+          <View style={{ flex: 1.2, marginHorizontal: 7, backgroundColor: "#d4d4d4", height: 53.5, maxWidth: 60, borderRadius: 8 }}>
+            {/* <TouchableOpacity style={styles.arrowButton} onPress={() => { setFloor(prevState => prevState + props.num) }}></TouchableOpacity> */}
+            <TouchableOpacity style={styles.arrowButton} onPress={props.propEvent} >
+              <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
+                {/* <FontAwesomeIcon icon="fa-solid fa-left" /> */}
+                <FontAwesome style={{ marginLeft: (props.num == 1 ? 5 : -5) }} color={"white"} size={35} name={props.fontAweIcon} />
+              </View>
+            </TouchableOpacity>
+          </View>
+        )
+      }
+      else {
+        return (
+          <View style={{ flex: 1.2, marginHorizontal: 7, height: 53.5, maxWidth: 60, borderRadius: 10 }}>
+          </View>
+        )
+      }
+  }
+
+
+const styles = StyleSheet.create({
+    arrowButton: {
+        flex: 1,
+        backgroundColor: colors.red,
+        // backgroundColor: "blue",
+        height: 53.5,
+        borderRadius: 8,
+      },
+})
+
+
+
+export default ArrowButton

+ 18 - 0
src/components/Map/MainMapComponent/BottomButtons.tsx

@@ -0,0 +1,18 @@
+import { View, Text, TouchableOpacity, StyleSheet, Linking} from 'react-native'
+import React from 'react'
+import { colors, lmTypes } from "../../../utils/GlobalUtils";
+
+function BottomButtons(props) {
+  return (
+<View style={{ flexDirection: "row", justifyContent: "space-around", alignItems: "flex-end", borderColor: "green", borderWidth: 0 }}>
+        <TouchableOpacity style={{ backgroundColor: colors.red, height: 30, paddingHorizontal: 7, paddingTop: 3, borderRadius: 5 }} onPress={() => props.navigation.goBack()}>
+          <Text style={{ fontSize: 16, color: "white", textAlign: "right", textAlignVertical: "bottom" }}>{"Go back to map"}</Text>
+        </TouchableOpacity>
+        <TouchableOpacity style={{ backgroundColor: colors.red, height: 30, paddingHorizontal: 7, paddingTop: 3, borderRadius: 5 }} onPress={() => Linking.openURL('https://www.library.ualberta.ca/')}>
+          <Text style={{ fontSize: 16, color: "white", textAlign: "center", }}>{"Resources"}</Text>
+        </TouchableOpacity>
+      </View>  )
+}
+
+
+export default BottomButtons

+ 85 - 77
src/components/Map/MainMapComponent/IndoorMap.tsx

@@ -1,8 +1,8 @@
 import React, { useState, useEffect, Children } from 'react';
-import { View, Text, StatusBar, StyleSheet, Dimensions, Button, ActivityIndicator, Alert, Modal, PanResponderCallbacks, PanResponderGestureState, GestureResponderEvent, ImageSourcePropType, TouchableOpacity, Platform } from 'react-native';
+import { View, Text, StatusBar, StyleSheet, Dimensions, Button, ActivityIndicator, Alert, Modal, PanResponderCallbacks, PanResponderGestureState, GestureResponderEvent, ImageSourcePropType, TouchableOpacity, Platform, Linking, } from 'react-native';
 import { Svg, Defs, Rect, Mask, Circle, Marker, Path, Polyline, Image } from 'react-native-svg';
 import { RadioButton } from 'react-native-paper';
-import { Picker } from '@react-native-picker/picker';
+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";
@@ -15,6 +15,12 @@ import ReactDOMServer from 'react-dom/server'; //npm i --save-dev @types/react-d
 import { Landmark } from '../../../hooks/useLandmarks';
 import { ZoomableViewEvent } from '@openspacelabs/react-native-zoomable-view/src/typings';
 import IndoorFloor from '../IndoorFloor'
+// import Toast from 'react-native-toast-message';
+import Toast from 'react-native-root-toast';
+import ArrowButton from './ArrowButton'
+import BottomButtons from './BottomButtons'
+import Picker from 'react-native-picker-select';
+
 
 interface IndoorMapProps {
   navigation: MapStackNavigationProp
@@ -28,7 +34,7 @@ interface IndoorMapProps {
 
 
 const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddLandmark, focusLandmark, applyFilter }) => {
-  const [floor, setFloor] = useState(0);
+  const [floor, setFloor] = useState(1);
   const [showME, setShowME] = useState(false);
   const [showDots, setShowDots] = useState(false);
   const [showAddedDot, setShowAddedDot] = useState(false)
@@ -36,30 +42,12 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
 
   const [localLandmarks, setLocalLandmarks] = useState<Landmark[]>([])
 
-  const imageDim = 0.05 * Dimensions.get("window").width;
 
-  function arrowBut(num, fontAweIcon) {
-    if (num != 0) {
-      return (
-        <View style={{ flex: 1.2, marginHorizontal: 7, backgroundColor: "#d4d4d4", height: 53.5, maxWidth: 60 }}>
-          <TouchableOpacity style={styles.arrowButton} onPress={() => { setFloor(prevState => prevState + num) }}>
-            <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
-              {/* <FontAwesomeIcon icon="fa-solid fa-left" /> */}
-              <FontAwesome style={{ marginLeft: (num == 1 ? 5 : -5) }} color={"white"} size={35} name={fontAweIcon} />
-            </View>
-          </TouchableOpacity>
-        </View>
-      )
-    }
-    else {
-      return (
-        <View style={{ flex: 1.2, marginHorizontal: 7, height: 53.5, maxWidth: 60, borderRadius: 10 }}>
-        </View>
-      )
-    }
-  }
+  const [sport, setSport] = useState("football");
 
 
+  const imageDim = 0.05 * Dimensions.get("window").width;
+
   const loadCircles = applyFilter(landmarks)?.map((item) => {
     if (item.floor == floor && SVGdim[0] != 1 && SVGdim[1] != 1) {
       return (
@@ -78,20 +66,28 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
 
 
   function addLandmark(evt: GestureResponderEvent) {
-    if (evt) {
+    if (evt != null) {
       Alert.alert("Are you sure you want to add a landmark here?", undefined,
         [{ text: "Cancel", onPress: () => console.log("Cancelled") }
           ,
         {
-          text: "Confirm", onPress: () => {
-            promptAddLandmark((evt.nativeEvent.locationX - imageDim / 2) / SVGdim[0], (evt.nativeEvent.locationY - imageDim / 2) / SVGdim[1], floor)
+          text: "Confirm", onPress: async () => {
+            try {
+              await promptAddLandmark((evt.nativeEvent.locationX - imageDim / 2) / SVGdim[0], (evt.nativeEvent.locationY - imageDim / 2) / SVGdim[1], floor)
+            }
+            catch (err) {
+              console.log("error has been caught!")
+              Toast.show("An error has occured. Please ensure thumb 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
+            }
           }
-        }])
+        }]
+      )
     }
   }
 
-
-
   useEffect(() => {
     // Alert.alert("useEffect has been triggered")
     setShowAddedDot(false)
@@ -99,10 +95,6 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
     setTimeout(() => setShowME(true), 100);
   })
 
-
-
-
-
   const childToWeb = (child: any) => {
     const { type, props } = child;
     const name = type && type.displayName;
@@ -116,16 +108,16 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
   function renderSvg() {
     return (
       <Svg height="100%" width="100%" style={{ backgroundColor: '#33AAFF' }}>
-      <Rect
-        x="50"
-        y="50"
-        width="50"
-        height="50"
-        fill="#3399ff"
-        strokeWidth="3"
-        stroke="rgb(0,0,0)"
-      />
-    </Svg>
+        <Rect
+          x="50"
+          y="50"
+          width="50"
+          height="50"
+          fill="#3399ff"
+          strokeWidth="3"
+          stroke="rgb(0,0,0)"
+        />
+      </Svg>
     )
   }
 
@@ -138,8 +130,9 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
     return svgString
   }
 
-
-
+  function changer(num) {
+    setFloor(prevState => prevState + num)
+  }
 
   // TODO: wire up promptaddlandmark, applyfilters, and focuslandmark methods passed from MapNavigator
   return (
@@ -152,33 +145,54 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
 
       <View style={{ borderColor: "blue", borderWidth: 0, maxHeight: 50, flex: 1, flexDirection: "row", justifyContent: "center", }}>
 
-        {/* arrow-circle-o-right */}
-        {floor == 0 ? arrowBut(0, "") : arrowBut(-1, "chevron-left")}
+        {floor == 0 ? <ArrowButton num={0} fontAweIcon={""} /> : <ArrowButton num={-1} fontAweIcon={"chevron-left"} propEvent={() => changer(-1)} />}
+
+        <View style={{ backgroundColor: colors.red, flex: 5, height: 53.5, width: 200 }}>
+          <Picker
+            placeholder={{}}
+            value={floor}
+            style={{ inputAndroid: {color:"white"} , inputIOS: {color:"white"} }}
+            onValueChange={(value) => {
+              setFloor(value)
+              setShowME(false)
+            }
+            }
+            items={[
+              { label: 'Basement', value: 0 },
+              { label: 'First Floor', value: 1 },
+              { label: 'Second Floor', value: 2 },
+              { label: 'Third Floor', value: 3 },
+              { label: 'Fourth Floor', value: 4 },
+              { label: 'Fifth Floor', value: 5 },
+            ]}
+          />
+        </View>
 
 
-        <Picker
+        {/* <EricPicker
           style={{ backgroundColor: colors.red, width: 200, height: 50, flex: 5, color: 'white' }}
           selectedValue={floor} // the text of what gets displayed on the dropdown header
           onValueChange={(itemValue, itemIndex: number) => {
             setFloor(itemIndex)
             setShowME(false)
           }}>
-          {/* The value in Picker.Item refers to selectedValue in Picker, which refers to the state "floor" */}
-          <Picker.Item label="Basement" value={0} />
-          <Picker.Item label="First Floor" value={1} />
-          <Picker.Item label="Second Floor" value={2} />
-          <Picker.Item label="Third Floor" value={3} />
-          <Picker.Item label="Fourth Floor" value={4} />
-          <Picker.Item label="Fifth Floor" value={5} />
-        </Picker>
+          The value in EricPicker.Item refers to selectedValue in EricPicker, which refers to the state "floor"
+          <EricPicker.Item label="Basement" value={0} />
+          <EricPicker.Item label="First Floor" value={1} />
+          <EricPicker.Item label="Second Floor" value={2} />
+          <EricPicker.Item label="Third Floor" value={3} />
+          <EricPicker.Item label="Fourth Floor" value={4} />
+          <EricPicker.Item label="Fifth Floor" value={5} />
+        </EricPicker> */}
 
-        {floor == 5 ? arrowBut(0, "") : arrowBut(1, "chevron-right")}
 
-      </View>
+        {/* {floor == 5 ? arrowBut(0, "") : arrowBut(1, "chevron-right")} */}
+        {floor == 5 ? <ArrowButton num={0} fontAweIcon={""} /> : <ArrowButton num={1} fontAweIcon={"chevron-right"} propEvent={() => changer(1)} />}
 
 
+      </View>
 
-      <View style={{ flex: 1, alignItems: "center", height: '100%', width: '100%' }}>
+      <View style={{ flex: 1, alignItems: "center", height: '100%', width: '100%', borderColor: 'purple', borderWidth: 0 }}>
         <View style={styles.container}>
           {showME === false ?
             <View style={{ display: 'flex', flexDirection: 'row', justifyContent: "center", }}>
@@ -190,24 +204,20 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
               // bindToBorders={false}
               bindToBorders={true}
 
-
               zoomStep={2.8}
               // initialZoom={2.2}
               maxZoom={2.8}
               minZoom={1}
               initialOffsetY={5}
               onLongPress={(event) => {
-                console.log(event.nativeEvent)
+                console.log("native event is " + event.nativeEvent)
                 // serialize()
                 addLandmark(event)
               }}>
 
-
-
               <Svg onLayout={event => {
                 console.log("OFFICIAL: " + event.nativeEvent.layout.width + " , " + event.nativeEvent.layout.height)
                 setSVGdim([event.nativeEvent.layout.width, event.nativeEvent.layout.height])
-
                 const transformedLandmarks = localLandmarks.map(item => {
                   return { ...item, coordx: item.longitude * event.nativeEvent.layout.width, coordy: item.latitude * event.nativeEvent.layout.height }
                 })
@@ -217,17 +227,9 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
               >
                 {/* {firstTime == true ? undefined : loadCircles} */}
                 {loadCircles}
-                <IndoorFloor floorNum={floor}/>
-
-
+                <IndoorFloor floorNum={floor} />
               </Svg>
-
-
-
-
-
             </ReactNativeZoomableView>
-
           }
 
         </View>
@@ -238,10 +240,17 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
       }} /> */}
 
       {/* <Button title='Press me to svgString' color={colors.red} onPress={serialize}></Button> */}
+      {/* <View style={{ flex: 0.1, flexDirection: 'row', alignItems:'flex-end', justifyContent: 'space-around' , borderColor:'green' , borderWidth:0 ,}}>
       <Button title="Go back to map" color={colors.red} onPress={() => navigation.goBack()} />
+      <Button title="Resources" color={colors.red} onPress={() => Linking.openURL('https://www.library.ualberta.ca/')} />
+      </View> */}
       {/* <TouchableOpacity style={styles.arrowButton} onPress={() => setFloor(prevState => prevState+1)} ><Text>Increase floor by 1</Text></TouchableOpacity> */}
 
-    </View>
+
+      <BottomButtons navigation={navigation}/>
+      {/* <Text>{floor}</Text> */}
+
+    </View >
   );
 }
 
@@ -279,8 +288,7 @@ const styles = StyleSheet.create({
     // backgroundColor: "blue",
     height: 53.5,
     // borderRadius: 10,
-
-  }
+  },
 });
 
 

+ 198 - 163
src/components/Map/Panels/AddLandmarkPanel.tsx

@@ -8,8 +8,8 @@
 import { FontAwesome } from "@expo/vector-icons";
 import * as ImagePicker from 'expo-image-picker';
 import { ImageInfo } from "expo-image-picker/build/ImagePicker.types";
-import React, { memo, useEffect, useState } from "react";
-import { ActivityIndicator, Dimensions, Image, Platform, SafeAreaView, Text, TextInput, TouchableOpacity, View, ImageSourcePropType} from 'react-native';
+import React, { memo, useEffect, useState, useRef } from "react";
+import { ActivityIndicator, Dimensions, Image, Platform, SafeAreaView, Text, TextInput, TouchableOpacity, View, ImageSourcePropType, Share, } from 'react-native';
 import { ScrollView } from "react-native-gesture-handler";
 import Modal from 'react-native-modal';
 import { checkMultiple, PERMISSIONS, RESULTS } from "react-native-permissions";
@@ -19,10 +19,11 @@ import { colors, getMediaPermissions, lmTypes } from "../../../utils/GlobalUtils
 import { IconButton, SecondaryButton } from "../../Buttons";
 import { PhotoPicker } from "../../PhotoPicker";
 import TouchOpaq from "./LandmarkDetailsPanel/TouchOpaq";
-import {Svg , Rect, Image as ImageSVG} from 'react-native-svg'
+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 from "react-native-view-shot";
 
 /**
  * Props for the {@link AddLandmarkPanel} component.
@@ -31,7 +32,7 @@ export interface AddLandmarkProps {
     /**
      * Whether the landmark is being added at the current users location
      */
-     landmarkAtCurrentLocation?: boolean;
+    landmarkAtCurrentLocation?: boolean;
     /**
      * The {@link landmark} object to be added.
      */
@@ -52,18 +53,20 @@ export interface AddLandmarkProps {
  * @component
  * @category Map
  */
-const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({newLandmark, setNewLandmark, setVisible, visible}) => {
+const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({ newLandmark, setNewLandmark, setVisible, visible }) => {
     const [photos, setPhotos] = useState<LMPhoto[]>([])
     const [photoSourceMenuOpened, togglePhotoSourceMenu] = useState<boolean>(false)
 
+    const capture: any = useRef();
+
     const imgWidth = 346
     const imgHeight = 443
-    const imageDim = 5
+    const imageDim = 27
 
-    const { 
-        addLandmarkAsync, 
-        resetAddLm, 
-        addLandmarkStatus, 
+    const {
+        addLandmarkAsync,
+        resetAddLm,
+        addLandmarkStatus,
     } = useLandmarks();
 
     useEffect(() => {
@@ -86,78 +89,91 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({newLandmark, setNewLandma
 
 
 
-
     const renderIndoorLandmarkPin = (landmark: Landmark) => {
         return (
             <ImageSVG
-              x={landmark.longitude * imgWidth}
-              y={landmark.latitude * imgHeight}
-              width={imageDim}
-              height={imageDim}
-              href={lmTypes[landmark.landmark_type]['image'] as ImageSourcePropType} />
-          )
-    } 
-
-    // const renderLandmarkSvg = (floor: number) => {
-    //     return (
-    //         <Svg height={imgHeight} width={imgWidth}>
-    //             <IndoorFloor floorNum={floor} />
-    //             {renderIndoorLandmarkPin(newLandmark)}
-    //         </Svg>
-    //     )
+                x={landmark.longitude * imgWidth}
+                y={landmark.latitude * imgHeight}
+                width={imageDim}
+                height={imageDim}
+                href={lmTypes[landmark.landmark_type]['image'] as ImageSourcePropType} />
+        )
+    }
+
+    const renderLandmarkSvg = (floor: number) => {
+        return (
+            <Svg height="100%" width="100%">
+                {renderIndoorLandmarkPin(newLandmark)}
+                <IndoorFloor floorNum={floor} />
+            </Svg>
+        )
+    }
+
+
+    // function renderLandmarkSvg(floor) {
+    //   return (
+    //   // <svg height="100%" width="100%" style="background-color:#33AAFF" preserveAspectRatio="xMidYMid meet"><rect x="50" y="50" width="50" height="50" fill="#3399ff" stroke-width="3" stroke="rgb(0,0,0)"></rect></svg>
+    //   //                                 style={{backgroundColor:'#33AAFF'}}
+    //     <Svg height="100%" width="100%" style={{ backgroundColor: '#33AAFF' }}>
+    //     <Rect
+    //       x="50"
+    //       y="50"
+    //       width="50"
+    //       height="50"
+    //       fill="#3399ff"
+    //       strokeWidth="3"
+    //       stroke="rgb(0,0,0)"
+    //     />
+    //     <Circle cx="200" cy="75" r="20" fill="pink" />
+    //   </Svg>
+    //   )
     // }
 
+    // const childToWeb = (child: any) => {
+    //     const { type, props } = child;
+    //     const name = type && type.displayName;
+    //     const webName = name && name[0].toLowerCase() + name.slice(1);
+    //     const Tag = webName ? webName : type;
+    //     return <Tag {...props}>{toWeb(props.children)}</Tag>;
+    // };
 
+    // const toWeb = (children: any) => React.Children.map(children, childToWeb);
 
-    const childToWeb = (child: any) => {
-        const { type, props } = child;
-        const name = type && type.displayName;
-        const webName = name && name[0].toLowerCase() + name.slice(1);
-        const Tag = webName ? webName : type;
-        return <Tag {...props}>{toWeb(props.children)}</Tag>;
-      };
-    
-      const toWeb = (children: any) => React.Children.map(children, childToWeb);
-    
-      function renderLandmarkSvg(floor) {
-        return (
-        // <svg height="100%" width="100%" style="background-color:#33AAFF" preserveAspectRatio="xMidYMid meet"><rect x="50" y="50" width="50" height="50" fill="#3399ff" stroke-width="3" stroke="rgb(0,0,0)"></rect></svg>
-        //                                 style={{backgroundColor:'#33AAFF'}}
-          <Svg height="100%" width="100%" style={{ backgroundColor: '#33AAFF' }}>
-          <Rect
-            x="50"
-            y="50"
-            width="50"
-            height="50"
-            fill="#3399ff"
-            strokeWidth="3"
-            stroke="rgb(0,0,0)"
-          />
-        </Svg>
-        )
-      }
 
-    function serialize() {
-        const element = renderLandmarkSvg(newLandmark.floor);
-        const webJsx = toWeb(element);
-        const svgString = ReactDOMServer.renderToStaticMarkup(webJsx);
-        console.log(svgString)
-        return svgString
-      }
+    // function serialize() {
+    //     const element = renderLandmarkSvg(newLandmark.floor);
+    //     const webJsx = toWeb(element);
+    //     const svgString = ReactDOMServer.renderToStaticMarkup(webJsx);
+    //     console.log(svgString)
+    //     return svgString
+    // }
 
     /**
      * Calls {@link addLandmarkAsync} from {@link useLandmarks} to initate the process of adding a landmark, then closes the modal.
      */
     const submit = async () => {
-        // create svg content here, then pass it to addLandmarkAsync as the value of indoorLmLocImg
-        if(typeof newLandmark.floor === 'number'){
-            let rectangle = serialize()
-            await addLandmarkAsync({landmarkValue: newLandmark, photos: photos, indoorLmLocImg: rectangle }); // pass it in here
+
+        if (typeof newLandmark.floor === 'number') {
+            // let imageURI = await capture.current.capture()
+            let imageURI = "string"
+            console.log("*AddLandmarkPanel* imageURI is " + imageURI)
+            await addLandmarkAsync({ landmarkValue: newLandmark, photos: photos, indoorLmLocImg: imageURI }); // pass it in here
         }
-        else{
-            await addLandmarkAsync({landmarkValue: newLandmark, photos: photos }); 
+        else {
+            await addLandmarkAsync({ landmarkValue: newLandmark, photos: photos });
         }
-        
+
+
+
+        // create svg content here, then pass it to addLandmarkAsync as the value of indoorLmLocImg
+        // if (typeof newLandmark.floor === 'number') {
+        //     let rectangle = serialize()
+        //     await addLandmarkAsync({ landmarkValue: newLandmark, photos: photos, indoorLmLocImg: rectangle }); // pass it in here
+        // }
+        // else {
+        //     await addLandmarkAsync({ landmarkValue: newLandmark, photos: photos });
+        // }
+
         close()
     }
 
@@ -173,7 +189,7 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({newLandmark, setNewLandma
 
     const addPhoto = (result: ImageInfo) => {
         togglePhotoSourceMenu(false)
-        const photo: LMPhoto = {id: '', image_b64: 'data:image/png;base64,' + result.base64, height: result.height, width: result.width, landmark: ''}
+        const photo: LMPhoto = { id: '', image_b64: 'data:image/png;base64,' + result.base64, height: result.height, width: result.width, landmark: '' }
         setPhotos([...photos, photo])
     }
 
@@ -182,112 +198,131 @@ const AddLandmarkPanel: React.FC<AddLandmarkProps> = ({newLandmark, setNewLandma
     }
 
     return (
+
         <Modal
             useNativeDriver={true}
             useNativeDriverForBackdrop={true}
-            
+
             testID="addLMModal"
             avoidKeyboard={photos.length == 0}
             onBackdropPress={close}
-            style={{justifyContent: "flex-end", height: '100%', margin: 0}}
+            style={{ justifyContent: "flex-end", height: '100%', margin: 0 }}
             isVisible={visible} >
-            <SafeAreaView style={{backgroundColor: colors.red, height: photos.length>0 ? Dimensions.get('window').height * .8 : Dimensions.get('window').height * .6}}>
+            <SafeAreaView style={{ backgroundColor: colors.red, height: photos.length > 0 ? Dimensions.get('window').height * .8 : Dimensions.get('window').height * .6 }}>
                 {addLandmarkStatus == 'idle' ?
-                <>
-                    <View style={{
-                        justifyContent: 'space-between', 
-                        alignItems: 'center', 
-                        flexDirection: "row", 
-                        marginBottom: 15, 
-                        borderBottomWidth: 1, 
-                        borderBottomColor: 'white', 
-                        paddingHorizontal: 20, 
-                        paddingVertical: 10}}>
-                        <Text style={{color: 'white', fontSize: 15}}>Add landmark here?</Text>
-                        <TouchOpaq
-                            func={close}
-                            name={"close"}
-                            size={25}
-                            col={"white"}
-                        />
-
-                    </View>
-                    <ScrollView>
-                        <View style={{paddingHorizontal: 20, paddingBottom: 20 }}>
-                            <TextInput
-                                returnKeyType="done"
-                                blurOnSubmit={true}
-                                multiline={true} 
-                                style={{backgroundColor: 'white', textAlignVertical: 'top', paddingHorizontal: 10, paddingTop: 10, paddingBottom: 10, marginBottom: 20, height: 150}} 
-                                placeholder="Description"
-                                onChangeText={value => setNewLandmark({...newLandmark, description: value})}>
-                                {newLandmark?.description}
-                            </TextInput>
-                            <View style={{flexDirection: 'row'}}>
-                                <Picker
-                                    style={{
-                                        inputIOS: {color: 'white'}, 
-                                        inputAndroid: {color: 'white'},
-                                        viewContainer: {marginVertical: 5, flex: 1}, placeholder: {color: 'white'}}}
-                                    textInputProps={{placeholderTextColor: 'white', selectionColor: 'white'}}
-                                    Icon={() => <FontAwesome name="chevron-down" color='white' size={20} />}
-                                    placeholder={{label: "Select a landmark type...", value: 0}}
-                                    value={newLandmark?.landmark_type}
-                                    onValueChange={(value) => {
-                                        if (value) {
-                                            setNewLandmark({...newLandmark, landmark_type: value, title: lmTypes[value].label})
-                                        }
-                                        else {
-                                            setNewLandmark({...newLandmark, landmark_type: undefined, title: 'no title'})
-                                        }
-                                    }}
-                                    useNativeAndroidPickerStyle={true}
-                                    items={Object.keys(lmTypes)?.map(icon  => {
-                                        return (
-                                            {label: lmTypes[parseInt(icon)]?.label.toUpperCase(), value: icon, key: icon}
-                                        )})}
-                                />
-                                {newLandmark?.landmark_type ? <Image style={{marginLeft: 20}} source={lmTypes[newLandmark.landmark_type].image}/>
-                                : null}
-                            </View>
+                    <>
+                        <View style={{
+                            justifyContent: 'space-between',
+                            alignItems: 'center',
+                            flexDirection: "row",
+                            marginBottom: 15,
+                            borderBottomWidth: 1,
+                            borderBottomColor: 'white',
+                            paddingHorizontal: 20,
+                            paddingVertical: 10
+                        }}>
+                            <Text style={{ color: 'white', fontSize: 15 }}>Add landmark here?</Text>
+                            <TouchOpaq
+                                func={close}
+                                name={"close"}
+                                size={25}
+                                col={"white"}
+                            />
+
                         </View>
-                        {newLandmark?.landmark_type ?
-                        <View style={{justifyContent: 'flex-end', flexDirection: 'row', paddingHorizontal: 20, marginTop: 5}}>
-                            {newLandmark.description && newLandmark.title ?
-                            <View style={{flexDirection: 'row' }}>
-                                <TouchableOpacity onPress={async () => await submit()}><Text style={{color: 'white', marginRight: 25}}>Add</Text></TouchableOpacity>
-                                <TouchableOpacity onPress={close}><Text style={{color: 'white',  marginRight: 25}}>Cancel</Text></TouchableOpacity>
-                                {photos.length == 0 ? <TouchableOpacity onPress={() => togglePhotoSourceMenu(true)}><Text style={{color: 'white'}}>Include photos</Text></TouchableOpacity> : null }
-                            </View> : null}
-                        </View> : null}
-                        {photos?.length ? 
-                        <View>
-                            <ScrollView style={{borderTopWidth: 1, borderColor: 'lightgray', paddingTop: 20, marginHorizontal: 20, flexDirection: 'row', marginBottom: 5, marginTop: 30}} horizontal={true}>
-                                {photos.map((photo, i) => {
-                                    return (
-                                        <View key={i} style={{marginHorizontal: 1, padding: 15}}>
-                                            <IconButton style={{position: 'absolute', top: 0, right: 0, zIndex: 10, }} icon="times-circle" color="lightgray" size={20} onPress={() => deletePhoto(i)} />
-                                            <Image style={{borderWidth: 1, alignSelf: 'center', height: 200, width: 200 * photo.width / photo.height}} source={{uri: photo.image_b64}} /> 
-                                        </View>
-                                    )
-                                })}
-                                {photos.length < 5 ? <IconButton style={{alignSelf: 'center', padding: 10, opacity: .5, marginLeft: 10}} color='white' size={30} icon="plus" onPress={() => togglePhotoSourceMenu(true)} /> : null}
-                            </ScrollView>
-                        </View> : null}
-                    </ScrollView>
-                </> :
-                <View style={{height: '100%', justifyContent: "space-evenly", alignItems: "center"}}>
-                    <Text style={{color: 'white', fontSize: 20}}>{
-                        addLandmarkStatus == "loading" ? 'Uploading landmark...' :
-                        addLandmarkStatus == "error" ? 'Something went wrong when trying to upload the landmark.' : null }
-                    </Text>
-                    {
-                        addLandmarkStatus == "loading" ? <ActivityIndicator color='white' size="large"/> :
-                        addLandmarkStatus == "error" ? <SecondaryButton text="Okay" onPress={close}/> : null
-                    }
-                </View> }
+                        <ScrollView>
+                            <View style={{ paddingHorizontal: 20, paddingBottom: 20 }}>
+                                <TextInput
+                                    returnKeyType="done"
+                                    blurOnSubmit={true}
+                                    multiline={true}
+                                    style={{ backgroundColor: 'white', textAlignVertical: 'top', paddingHorizontal: 10, paddingTop: 10, paddingBottom: 10, marginBottom: 20, height: 150 }}
+                                    placeholder="Description"
+                                    onChangeText={value => setNewLandmark({ ...newLandmark, description: value })}>
+                                    {newLandmark?.description}
+                                </TextInput>
+                                <View style={{ flexDirection: 'row' }}>
+                                    <Picker
+                                        style={{
+                                            inputIOS: { color: 'white' },
+                                            inputAndroid: { color: 'white' },
+                                            viewContainer: { marginVertical: 5, flex: 1 }, placeholder: { color: 'white' }
+                                        }}
+                                        textInputProps={{ placeholderTextColor: 'white', selectionColor: 'white' }}
+                                        Icon={() => <FontAwesome name="chevron-down" color='white' size={20} />}
+                                        placeholder={{ label: "Select a landmark type...", value: 0 }}
+                                        value={newLandmark?.landmark_type}
+                                        onValueChange={(value) => {
+                                            if (value) {
+                                                setNewLandmark({ ...newLandmark, landmark_type: value, title: lmTypes[value].label })
+                                            }
+                                            else {
+                                                setNewLandmark({ ...newLandmark, landmark_type: undefined, title: 'no title' })
+                                            }
+                                        }}
+                                        useNativeAndroidPickerStyle={true}
+                                        items={Object.keys(lmTypes)?.map(icon => {
+                                            return (
+                                                { label: lmTypes[parseInt(icon)]?.label.toUpperCase(), value: icon, key: icon }
+                                            )
+                                        })}
+                                    />
+                                    {newLandmark?.landmark_type ? <Image style={{ marginLeft: 20 }} source={lmTypes[newLandmark.landmark_type].image} />
+                                        : null}
+                                </View>
+                            </View>
+                            {newLandmark?.landmark_type ?
+                                <View style={{ justifyContent: 'flex-end', flexDirection: 'row', paddingHorizontal: 20, marginTop: 5 }}>
+                                    {newLandmark.description && newLandmark.title ?
+                                        <View style={{ flexDirection: 'row' }}>
+                                            <TouchableOpacity onPress={async () => await submit()}><Text style={{ color: 'white', marginRight: 25 }}>Add</Text></TouchableOpacity>
+                                            <TouchableOpacity onPress={close}><Text style={{ color: 'white', marginRight: 25 }}>Cancel</Text></TouchableOpacity>
+                                            {photos.length == 0 ? <TouchableOpacity onPress={() => togglePhotoSourceMenu(true)}><Text style={{ color: 'white' }}>Include photos</Text></TouchableOpacity> : null}
+                                        </View> : null}
+                                </View> : null}
+                            {photos?.length ?
+                                <View>
+                                    <ScrollView style={{ borderTopWidth: 1, borderColor: 'lightgray', paddingTop: 20, marginHorizontal: 20, flexDirection: 'row', marginBottom: 5, marginTop: 30 }} horizontal={true}>
+                                        {photos.map((photo, i) => {
+                                            return (
+                                                <View key={i} style={{ marginHorizontal: 1, padding: 15 }}>
+                                                    <IconButton style={{ position: 'absolute', top: 0, right: 0, zIndex: 10, }} icon="times-circle" color="lightgray" size={20} onPress={() => deletePhoto(i)} />
+                                                    <Image style={{ borderWidth: 1, alignSelf: 'center', height: 200, width: 200 * photo.width / photo.height }} source={{ uri: photo.image_b64 }} />
+                                                </View>
+                                            )
+                                        })}
+                                        {photos.length < 5 ? <IconButton style={{ alignSelf: 'center', padding: 10, opacity: .5, marginLeft: 10 }} color='white' size={30} icon="plus" onPress={() => togglePhotoSourceMenu(true)} /> : null}
+                                    </ScrollView>
+                                </View> : null}
+                        </ScrollView>
+                    </> :
+                    <View style={{ height: '100%', justifyContent: "space-evenly", alignItems: "center" }}>
+                        <Text style={{ color: 'white', fontSize: 20 }}>{
+                            addLandmarkStatus == "loading" ? 'Uploading landmark...' :
+                                addLandmarkStatus == "error" ? 'Something went wrong when trying to upload the landmark.' : null}
+                        </Text>
+                        {
+                            addLandmarkStatus == "loading" ? <ActivityIndicator color='white' size="large" /> :
+                                addLandmarkStatus == "error" ? <SecondaryButton text="Okay" onPress={close} /> : null
+                        }
+                    </View>}
             </SafeAreaView>
             <PhotoPicker multiple={true} menuType='alert' photoSourceMenuOpened={photoSourceMenuOpened} onReceivedPhotoResult={result => addPhoto(result)} cancel={() => togglePhotoSourceMenu(false)} />
+
+            {/* <View style={{position:'absolute', zIndex:-1}}>
+            <ViewShot ref={capture} options={{format:'jpg'}}>
+                <Svg>
+                    {renderIndoorLandmarkPin(newLandmark)}
+                    <IndoorFloor floorNum={newLandmark.floor} />
+                    Issue rn is that upon initial rendering, RN doesnt know what "newLandmark" is
+
+                    <ImageSVG x={100} y={100} width={imageDim} height={imageDim} href={lmTypes[2]['image'] as ImageSourcePropType} />
+                    <IndoorFloor floorNum={2} />
+                </Svg> 
+            </ViewShot>
+            </View> */}
+
+
         </Modal>
     )
 }

+ 2 - 3
src/navigation/MapNavigator.tsx

@@ -47,6 +47,7 @@ const MapNavigator: React.FC<MapNavigatorProps> = ({ route }) => {
 
     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]
@@ -158,7 +159,7 @@ const MapNavigator: React.FC<MapNavigatorProps> = ({ route }) => {
 
             {/* Filter chips and button*/}
             {!mapState.filterVisible && currentRoute == 'Indoor' ?
-                <View style={{width:Dimensions.get("window").width*0.8 ,marginLeft:Dimensions.get("window").width*0.1, borderColor:"red" , borderWidth:0, bottom: 50, position: 'absolute', flexDirection: "row-reverse", justifyContent: 'flex-end' }}>
+                <View style={{width:Dimensions.get("window").width*0.8 ,marginLeft:Dimensions.get("window").width*0.1, borderColor:"red" , borderWidth:0, bottom: 55, 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}
@@ -183,8 +184,6 @@ const MapNavigator: React.FC<MapNavigatorProps> = ({ route }) => {
                         {mapState.minLmRating > 0 ? <Chip avatar={(<FontAwesome name="star" size={20} color='gray' style={{ textAlign: 'center', textAlignVertical: 'center' }} />)} style={{ borderWidth: 1, borderColor: 'lightgray', marginLeft: 5, marginRight: 10 }} onClose={() => mapState.setMinLmRating(0)}>Minimum rating: {mapState.minLmRating}</Chip> : null}
                     </ScrollView>
                 </View>
-                
-                
                 }
   
 

File diff ditekan karena terlalu besar
+ 338 - 345
yarn.lock


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini