Viktoriia 6 місяців тому
батько
коміт
ab4f1781ea

+ 34 - 14
src/components/ScaleBar/index.tsx

@@ -1,15 +1,15 @@
-import React, { useEffect, useState } from 'react';
-import { StyleSheet, View, Text, Dimensions } from 'react-native';
+import React, { useEffect } from 'react';
+import { StyleSheet, Text, Dimensions } from 'react-native';
 import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';
 import { Colors } from 'src/theme';
 
 const FEET_PER_METER = 3.28084;
 const FEET_PER_MILES = 5280;
-const SCALE_SCREEN_RATIO = 0.3;
+const SCALE_SCREEN_RATIO = 0.25;
 const TILE_SIZE_METERS_AT_0_ZOOM = 156543.034;
 
 const SCALE_STEPS_IN_METERS = [
-  1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000,
+  2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000,
   1000000, 2000000, 3000000
 ];
 
@@ -39,22 +39,40 @@ const SCALE_STEPS_IN_FEET = [
 interface ScaleBarProps {
   zoom: number;
   latitude: number;
+  isVisible: boolean;
   bottom?: any;
 }
 
-const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) => {
+const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, isVisible, bottom = '21%' }) => {
   const metricWidth = useSharedValue(0);
   const imperialWidth = useSharedValue(0);
   const metricText = useSharedValue('');
   const imperialText = useSharedValue('');
   const screenWidth = Dimensions.get('window').width;
+  const opacity = useSharedValue(isVisible ? 1 : 0);
+
+  useEffect(() => {
+    if (isVisible) {
+      opacity.value = withTiming(1, { duration: 100 });
+    } else {
+      opacity.value = withTiming(0, { duration: 1500 });
+    }
+  }, [isVisible]);
+
+  const animatedStyle = useAnimatedStyle(() => ({
+    opacity: opacity.value
+  }));
 
   const getResolutionFromZoomAndLatitude = (zoom: number, latitude: number) =>
     (TILE_SIZE_METERS_AT_0_ZOOM * Math.cos((latitude * Math.PI) / 180)) / Math.pow(2, zoom);
 
-  const getBestStepFromResolution = (resolution: number, steps: number[]) => {
+  const getBestStepFromResolution = (
+    resolution: number,
+    steps: number[],
+    multiplier: number = 1
+  ) => {
     return steps.reduce((bestStep, currentStep) => {
-      const scaleSize = (2 * currentStep) / resolution;
+      const scaleSize = (2 * currentStep * multiplier) / resolution;
       return scaleSize / screenWidth < SCALE_SCREEN_RATIO ? currentStep : bestStep;
     });
   };
@@ -63,7 +81,7 @@ const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) =
     const resolution = getResolutionFromZoomAndLatitude(zoom, latitude);
 
     const metricStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_METERS);
-    const imperialStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_FEET);
+    const imperialStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_FEET, 0.4);
 
     const metricScaleSize = (2 * metricStep) / resolution;
     const imperialScaleSize = (2 * imperialStep) / resolution / FEET_PER_METER;
@@ -85,19 +103,21 @@ const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) =
   }, [zoom, latitude]);
 
   const animatedMetricLineStyle = useAnimatedStyle(() => ({
-    right: metricWidth.value
+    left: metricWidth.value
   }));
 
   const animatedImperialLineStyle = useAnimatedStyle(() => ({
-    right: imperialWidth.value
+    left: imperialWidth.value
   }));
 
   const animatedCombinedStyle = useAnimatedStyle(() => ({
     width: Math.max(metricWidth.value, imperialWidth.value)
   }));
 
+  if (!metricText.value || !imperialText.value) return null;
+
   return (
-    <View style={[styles.container, { bottom }]}>
+    <Animated.View style={[styles.container, { bottom }, animatedStyle]}>
       <Text style={[styles.text, { bottom: 0 }]}>{metricText.value}</Text>
 
       <Animated.View style={[styles.scaleBar, animatedCombinedStyle]}>
@@ -106,14 +126,14 @@ const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) =
       </Animated.View>
 
       <Text style={[styles.text, { top: 0 }]}>{imperialText.value}</Text>
-    </View>
+    </Animated.View>
   );
 };
 
 const styles = StyleSheet.create({
   container: {
     position: 'absolute',
-    right: 10,
+    left: 16,
     alignItems: 'center'
   },
   scaleBar: {
@@ -135,7 +155,7 @@ const styles = StyleSheet.create({
     color: Colors.TEXT_GRAY,
     marginVertical: 4,
     position: 'absolute',
-    right: 0
+    left: 0
   }
 });
 

+ 10 - 2
src/screens/InAppScreens/MapScreen/index.tsx

@@ -394,6 +394,8 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
   const [selectedUser, setSelectedUser] = useState<any>(null);
   const [zoom, setZoom] = useState(0);
   const [center, setCenter] = useState<number[] | null>(null);
+  const [isZooming, setIsZooming] = useState(true);
+  const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
 
   const isSmallScreen = Dimensions.get('window').width < 383;
   const processedImages = useRef(new Set<string>());
@@ -732,6 +734,9 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
 
   const handleMapChange = async () => {
     if (!mapRef.current) return;
+    if (hideTimer.current) clearTimeout(hideTimer.current);
+
+    setIsZooming(true);
 
     const currentZoom = await mapRef.current.getZoom();
     const currentCenter = await mapRef.current.getCenter();
@@ -854,7 +859,10 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
   };
 
   const handleRegionDidChange = async (feature: GeoJSON.Feature<GeoJSON.Point, any>) => {
-    handleMapChange();
+    hideTimer.current = setTimeout(() => {
+      setIsZooming(false);
+    }, 2000);
+    
     if (!feature) return;
     const { zoomLevel } = feature.properties;
     const { coordinates } = feature.geometry;
@@ -1474,7 +1482,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
       </MapLibreGL.MapView>
 
       {center ? (
-        <ScaleBar zoom={zoom} latitude={center[1]} />
+        <ScaleBar zoom={zoom} latitude={center[1]} isVisible={isZooming} />
       ) : null}
 
       {regionPopupVisible && regionData ? (

+ 13 - 2
src/screens/InAppScreens/ProfileScreen/UsersMap/index.tsx

@@ -179,6 +179,8 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
 
   const [zoom, setZoom] = useState(0);
   const [center, setCenter] = useState<number[] | null>(null);
+  const [isZooming, setIsZooming] = useState(true);
+  const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
 
   const { data: visitedRegionIds } = usePostGetVisitedRegionsIdsQuery(
     token,
@@ -226,6 +228,9 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
 
   const handleMapChange = async () => {
     if (!mapRef.current) return;
+    if (hideTimer.current) clearTimeout(hideTimer.current);
+
+    setIsZooming(true);
 
     const currentZoom = await mapRef.current.getZoom();
     const currentCenter = await mapRef.current.getCenter();
@@ -342,7 +347,11 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
         styleJSON={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
         rotateEnabled={false}
         attributionEnabled={false}
-        onRegionDidChange={handleMapChange}
+        onRegionDidChange={() =>
+          (hideTimer.current = setTimeout(() => {
+            setIsZooming(false);
+          }, 2000))
+        }
         onRegionIsChanging={handleMapChange}
         onRegionWillChange={_.debounce(handleMapChange, 200)}
       >
@@ -446,7 +455,9 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
         )}
       </MapLibreGL.MapView>
 
-      {center ? <ScaleBar zoom={zoom} latitude={center[1]} bottom={'15%'} /> : null}
+      {center ? (
+        <ScaleBar zoom={zoom} latitude={center[1]} bottom={'12%'} isVisible={isZooming} />
+      ) : null}
 
       {!isExpanded ? (
         <TouchableOpacity