Viktoriia 7 miesięcy temu
rodzic
commit
ce38a7f1ad

+ 117 - 99
src/screens/InAppScreens/TravelsScreen/EarthScreen/index.tsx

@@ -1,37 +1,72 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
 import { View, Platform, Text, StatusBar } from 'react-native';
 import { SafeAreaView } from 'react-native-safe-area-context';
-import MapView, { Geojson, UrlTile } from 'react-native-maps';
 
 import kye from '../../../../../assets/geojson/kye.json';
 import { Header } from 'src/components';
 import { useGetKyeQuery, usePostSetKye } from '@api/travels';
 import { StoreType, storage } from 'src/storage';
 
-import { FeatureCollection } from '@turf/turf';
-import { FASTEST_MAP_HOST } from 'src/constants';
+import { VECTOR_MAP_HOST } from 'src/constants';
 import { styles } from './styles';
-import InfoIcon from 'assets/icons/info-solid.svg';
-import { NAVIGATION_PAGES } from 'src/types';
-import { useNavigation } from '@react-navigation/native';
-
-interface PropertiesData {
-  id: number;
-  tt: string;
-  mega: string;
-  name: string;
-  fill?: string;
-}
+import MapLibreGL, { MapViewRef } from '@maplibre/maplibre-react-native';
+
+MapLibreGL.setAccessToken(null);
+
+let kye_fill = {
+  id: 'kye_fill',
+  style: {
+    fillColor: 'rgba(21, 99, 123, 0.4)'
+  },
+
+  maxzoom: 12
+};
+
+let kye_fill_visited = {
+  id: 'kye_fill_visited',
+  style: {
+    fillColor: 'rgba(132, 138, 68, 0.6)'
+  },
+  maxzoom: 12
+};
+
+let kye_line = {
+  id: 'kye_line',
+  filter: ['all'],
+  style: {
+    lineColor: 'rgba(14, 80, 109, 1)',
+    lineWidth: ['interpolate', ['linear'], ['zoom'], 0, 0.8, 4, 1, 5, 1.5, 12, 3],
+    lineWidthTransition: { duration: 300, delay: 0 }
+  },
+  maxzoom: 16
+};
 
 const EarthScreen = () => {
-  const token = storage.get('token', StoreType.STRING) as string || '';
-  const [geojson, setGeojson] = useState<FeatureCollection>(kye as FeatureCollection);
-  const { data } = useGetKyeQuery(token, true);
+  const token = (storage.get('token', StoreType.STRING) as string) || '';
+  const { data } = useGetKyeQuery(token, !!token);
   const { mutateAsync } = usePostSetKye();
   const [visited, setVisited] = useState<number[]>([]);
   const [score, setScore] = useState({ base: 0, percentage: 0 });
   const [quadrantsAll, setQuadrantsAll] = useState<number>(1);
-  const navigation = useNavigation();
+
+  const generateFilter = (ids: number[]) => {
+    if (!ids || !ids.length) return ['==', 'id', -1];
+
+    return [
+      'any',
+      ...ids.map((id) => {
+        if (id > 612) {
+          return ['>=', 'id', 613];
+        } else {
+          return ['==', 'id', id];
+        }
+      })
+    ];
+  };
+
+  const [filter, setFilter] = useState<any[]>(generateFilter([]));
+
+  const mapRef = useRef<MapViewRef>(null);
 
   useEffect(() => {
     if (!data || !data.regions) return;
@@ -40,46 +75,10 @@ const EarthScreen = () => {
   }, [data]);
 
   useEffect(() => {
-    const updatedGeojson = updateGeojsonStyles(geojson);
-    setGeojson(updatedGeojson);
+    setFilter(generateFilter(visited));
     showScore();
   }, [visited]);
 
-  const getFeatureStyle = (properties: PropertiesData) => {
-    const style = {
-      fill: 'transparent'
-    };
-
-    if (properties.tt == '1') {
-      if (properties.id > 612) {
-        if (Math.max(...visited) > 612) {
-          style.fill = 'rgba(132, 138, 68, 0.5)';
-        } else {
-          style.fill = 'rgba(21, 99, 123, 0.5)';
-        }
-      } else {
-        if (visited.includes(properties.id)) {
-          style.fill = 'rgba(132, 138, 68, 0.5)';
-        } else {
-          style.fill = 'rgba(21, 99, 123, 0.5)';
-        }
-      }
-    } else {
-      style.fill = 'rgba(230, 230, 230, 0.5)';
-    }
-
-    return style;
-  };
-
-  const updateGeojsonStyles = (geojson: FeatureCollection) => {
-    const updatedFeatures = geojson.features.map((feature) => {
-      const style = getFeatureStyle(feature.properties as PropertiesData);
-      return { ...feature, properties: { ...feature.properties, ...style } };
-    });
-
-    return { ...geojson, features: updatedFeatures };
-  };
-
   const markQuadrant = async (qid: number) => {
     if (!token) return;
 
@@ -151,20 +150,34 @@ const EarthScreen = () => {
     setScore({ base: score, percentage: calc });
   };
 
+  const onMapPress = async (event: any) => {
+    if (!mapRef.current) return;
+
+    try {
+      const { screenPointX, screenPointY } = event.properties;
+
+      const { features } = await mapRef.current.queryRenderedFeaturesAtPoint(
+        [screenPointX, screenPointY],
+        undefined,
+        ['kye_fill']
+      );
+
+      if (features?.length) {
+        const selectedKye = features[0];
+
+        if (selectedKye.properties && selectedKye.properties.tt == '1') {
+          markQuadrant(selectedKye.properties.id);
+        }
+      }
+    } catch (error) {
+      console.error('Failed to get coordinates on EarthScreen', error);
+    }
+  };
+
   return (
-    <SafeAreaView style={{ height: '100%' }}>
+    <SafeAreaView style={{ height: '100%' }} edges={['top']}>
       <View style={styles.wrapper}>
-        <Header
-          label={'My Earth'}
-          // rightElement={
-          //   <TouchableOpacity
-          //     onPress={() => navigation.navigate(NAVIGATION_PAGES.EARTH_INFO as never)}
-          //     style={{ width: 30 }}
-          //   >
-          //     <InfoIcon />
-          //   </TouchableOpacity>
-          // }
-        />
+        <Header label={'My Earth'} />
         {token && (
           <View style={styles.score}>
             <Text style={[styles.scoreText, { fontWeight: 'bold' }]}>Your score: {score.base}</Text>
@@ -173,39 +186,44 @@ const EarthScreen = () => {
         )}
       </View>
 
-      <View style={[styles.container, { paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0 }]}>
-        <MapView
+      <View
+        style={[
+          styles.container,
+          { paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0 }
+        ]}
+      >
+        <MapLibreGL.MapView
+          ref={mapRef}
           style={styles.map}
-          showsMyLocationButton={false}
-          showsCompass={false}
-          zoomControlEnabled={false}
-          mapType={Platform.OS == 'android' ? 'none' : 'standard'}
-          maxZoomLevel={15}
-          minZoomLevel={0}
-          initialRegion={{
-            latitude: 0,
-            longitude: 0,
-            latitudeDelta: 180,
-            longitudeDelta: 180
-          }}
+          styleJSON={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
+          rotateEnabled={false}
+          attributionEnabled={false}
+          onPress={onMapPress}
         >
-          <UrlTile
-            urlTemplate={`${FASTEST_MAP_HOST}/tiles_osm/{z}/{x}/{y}`}
-            maximumZ={15}
-            maximumNativeZ={13}
-            shouldReplaceMapContent
-            minimumZ={0}
-          />
-          <Geojson
-            geojson={geojson as any}
-            zIndex={1}
-            tappable={true}
-            onPress={(event) => {
-              markQuadrant(event.feature.properties?.id);
-            }}
-            tracksViewChanges={false}
-          />
-        </MapView>
+          <MapLibreGL.ShapeSource id="kye" shape={kye as any}>
+            <MapLibreGL.LineLayer
+              id={kye_line.id}
+              filter={kye_line.filter as any}
+              maxZoomLevel={kye_line.maxzoom}
+              style={kye_line.style as any}
+              belowLayerID="waterway-name"
+            />
+            <MapLibreGL.FillLayer
+              id={kye_fill.id}
+              filter={['==', 'tt', '1']}
+              style={kye_fill.style}
+              maxZoomLevel={kye_fill.maxzoom}
+              belowLayerID={kye_fill_visited.id}
+            />
+            <MapLibreGL.FillLayer
+              id={kye_fill_visited.id}
+              filter={filter as any}
+              style={kye_fill_visited.style}
+              maxZoomLevel={kye_fill_visited.maxzoom}
+              belowLayerID={kye_line.id}
+            />
+          </MapLibreGL.ShapeSource>
+        </MapLibreGL.MapView>
       </View>
     </SafeAreaView>
   );