Pārlūkot izejas kodu

android map fix for all screens

Viktoriia 2 mēneši atpakaļ
vecāks
revīzija
cacc9c409b

+ 5 - 7
src/screens/InAppScreens/MessagesScreen/Components/MessageLocation.tsx

@@ -1,5 +1,5 @@
 import React, { useRef } from 'react';
-import { View, TouchableOpacity, StyleSheet, Platform } from 'react-native';
+import { View, TouchableOpacity, StyleSheet } from 'react-native';
 import * as MapLibreRN from '@maplibre/maplibre-react-native';
 import { useNavigation } from '@react-navigation/native';
 import { Colors } from 'src/theme';
@@ -39,12 +39,10 @@ const MessageLocation = ({
         zoomEnabled={false}
         pitchEnabled={false}
       >
-        {Platform.OS === 'ios' && (
-          <MapLibreRN.Camera
-            ref={cameraRef}
-            defaultSettings={{ centerCoordinate: [lng, lat], zoomLevel: 10 }}
-          />
-        )}
+        <MapLibreRN.Camera
+          ref={cameraRef}
+          defaultSettings={{ centerCoordinate: [lng, lat], zoomLevel: 10 }}
+        />
         <MapLibreRN.MarkerView coordinate={[lng, lat]}>
           <View
             style={{

+ 52 - 3
src/screens/InAppScreens/MessagesScreen/Components/RouteB.tsx

@@ -31,6 +31,43 @@ const RouteB = () => {
   const cameraRef = useRef<MapLibreRN.CameraRef | null>(null);
   const [mapDimensions, setMapDimensions] = useState({ width: 0, height: 0, x: 0, y: 0 });
 
+  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
+  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
+  const isAnimatingRef = useRef(false);
+
+  const cameraController = {
+    setCamera: (config: any) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.setCamera(config);
+        });
+
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+            setRenderCamera(false);
+          },
+          (config.animationDuration || 1000) + 200
+        );
+      } else {
+        cameraRef.current?.setCamera(config);
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+          },
+          (config.animationDuration || 1000) + 100
+        );
+      }
+    }
+  };
+
   useEffect(() => {
     const getLocation = async () => {
       try {
@@ -39,7 +76,9 @@ const RouteB = () => {
           return;
         }
 
-        const location = await Location.getCurrentPositionAsync({});
+        const location = await Location.getCurrentPositionAsync({
+          accuracy: Location.Accuracy.Balanced
+        });
         const coords = {
           latitude: location.coords.latitude,
           longitude: location.coords.longitude
@@ -58,7 +97,7 @@ const RouteB = () => {
     if (currentLocation) {
       const timeoutId = setTimeout(() => {
         if (cameraRef.current) {
-          cameraRef.current.setCamera({
+          cameraController.setCamera({
             centerCoordinate: [currentLocation.longitude, currentLocation.latitude],
             zoomLevel: 14,
             animationDuration: 500
@@ -66,6 +105,7 @@ const RouteB = () => {
           setLoading(false);
         } else {
           console.warn('Camera ref is not available.');
+          setLoading(false);
         }
       }, 500);
 
@@ -73,6 +113,14 @@ const RouteB = () => {
     }
   }, [currentLocation]);
 
+  useEffect(() => {
+    return () => {
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+    };
+  }, []);
+
   const confirmLocation = () => {
     if (selectedLocation) {
       onSendLocation(selectedLocation);
@@ -114,7 +162,8 @@ const RouteB = () => {
           attributionEnabled={false}
           onRegionDidChange={handleRegionChange}
         >
-          {Platform.OS === 'ios' && <MapLibreRN.Camera ref={cameraRef} />}
+          {(Platform.OS === 'ios' || renderCamera) && <MapLibreRN.Camera ref={cameraRef} />}
+
           {currentLocation && (
             <MapLibreRN.PointAnnotation
               id="currentLocation"

+ 76 - 4
src/screens/InAppScreens/MessagesScreen/FullMapScreen/index.tsx

@@ -32,6 +32,9 @@ const FullMapScreen = ({ route }: { route: any }) => {
   const navigation = useNavigation();
   const mapRef = useRef<MapLibreRN.MapViewRef>(null);
   const cameraRef = useRef<MapLibreRN.CameraRef>(null);
+  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
+  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
+  const isAnimatingRef = useRef(false);
 
   const [isLocationLoading, setIsLocationLoading] = useState(false);
   const [location, setLocation] = useState<any | null>(null);
@@ -45,6 +48,67 @@ const FullMapScreen = ({ route }: { route: any }) => {
 
   const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
 
+  const cameraController = {
+    setCamera: (config: any) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.setCamera(config);
+        });
+
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+            setRenderCamera(false);
+          },
+          (config.animationDuration || 1000) + 200
+        );
+      } else {
+        cameraRef.current?.setCamera(config);
+
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+          },
+          (config.animationDuration || 1000) + 100
+        );
+      }
+    },
+
+    flyTo: (coordinates: number[], duration: number = 1000) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.flyTo(coordinates, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.flyTo(coordinates, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }
+  };
+
   useEffect(() => {
     (async () => {
       let { status } = await Location.getForegroundPermissionsAsync();
@@ -65,6 +129,14 @@ const FullMapScreen = ({ route }: { route: any }) => {
     })();
   }, []);
 
+  useEffect(() => {
+    return () => {
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+    };
+  }, []);
+
   const handleMapChange = async () => {
     if (!mapRef.current) return;
     if (hideTimer.current) clearTimeout(hideTimer.current);
@@ -106,7 +178,7 @@ const FullMapScreen = ({ route }: { route: any }) => {
       setLocation(currentLocation.coords);
 
       if (currentLocation.coords) {
-        cameraRef.current?.flyTo(
+        cameraController?.flyTo(
           [currentLocation.coords.longitude, currentLocation.coords.latitude],
           1000
         );
@@ -154,10 +226,10 @@ const FullMapScreen = ({ route }: { route: any }) => {
             setIsZooming(false);
           }, 2000);
         }}
-        onRegionIsChanging={handleMapChange}
+        // onRegionIsChanging={handleMapChange}
         onRegionWillChange={_.debounce(handleMapChange, 200)}
       >
-        {Platform.OS === 'ios' && (
+        {(Platform.OS === 'ios' || renderCamera) && (
           <MapLibreRN.Camera
             ref={cameraRef}
             defaultSettings={{ centerCoordinate: [lng, lat], zoomLevel: 12 }}
@@ -175,7 +247,7 @@ const FullMapScreen = ({ route }: { route: any }) => {
               const currentZoom = await mapRef.current?.getZoom();
               const newZoom = (currentZoom || 0) + 2;
 
-              cameraRef.current?.setCamera({
+              cameraController.setCamera({
                 centerCoordinate: [location.longitude, location.latitude],
                 zoomLevel: newZoom,
                 animationDuration: 500,

+ 68 - 5
src/screens/InAppScreens/ProfileScreen/UsersMap/index.tsx

@@ -10,7 +10,7 @@ import {
   ScrollView,
   View
 } from 'react-native';
-import React, { FC, useEffect, useRef, useState } from 'react';
+import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
 import * as Location from 'expo-location';
 import Animated, {
   Easing,
@@ -155,6 +155,10 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
 
   const mapRef = useRef<MapLibreRN.MapViewRef>(null);
   const cameraRef = useRef<MapLibreRN.CameraRef>(null);
+  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
+  const isAnimatingRef = useRef(false);
+  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
+
   const [isFilterVisible, setIsFilterVisible] = useState<string | null>(null);
   const [tilesType, setTilesType] = useState({ label: 'NM regions', value: 0 });
   const tilesTypes = [
@@ -201,6 +205,57 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
     type === 'dare' && !!userId
   );
 
+  const cameraController = {
+    flyTo: useCallback((coordinates: number[], duration: number = 1000) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.flyTo(coordinates, duration);
+        });
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.flyTo(coordinates, duration);
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, []),
+    setCamera: useCallback((config: any) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.setCamera(config);
+        });
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+            setRenderCamera(false);
+          },
+          (config.animationDuration ?? 1000) + 200
+        );
+      } else {
+        cameraRef.current?.setCamera(config);
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+          },
+          (config.animationDuration ?? 1000) + 100
+        );
+      }
+    }, [])
+  };
+
   useEffect(() => {
     if (visitedRegionIds) {
       setRegionsVisitedFilter(generateFilter(visitedRegionIds.ids));
@@ -232,13 +287,21 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
       data.location_last_seen_location?.lat &&
       cameraRef.current
     ) {
-      cameraRef.current.flyTo(
+      cameraController.flyTo(
         [data.location_last_seen_location.lng, data.location_last_seen_location.lat],
         1000
       );
     }
   }, [data, cameraRef.current]);
 
+  useEffect(() => {
+    return () => {
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+    };
+  }, []);
+
   const handleMapChange = async () => {
     if (!mapRef.current) return;
     if (hideTimer.current) clearTimeout(hideTimer.current);
@@ -279,7 +342,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
     setLocation(currentLocation.coords);
 
     if (currentLocation.coords) {
-      cameraRef.current?.flyTo(
+      cameraController.flyTo(
         [currentLocation.coords.longitude, currentLocation.coords.latitude],
         1000
       );
@@ -376,7 +439,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
             setIsZooming(false);
           }, 2000);
         }}
-        onRegionIsChanging={handleMapChange}
+        // onRegionIsChanging={handleMapChange}
         onRegionWillChange={_.debounce(handleMapChange, 200)}
       >
         {type === 'regions' && (
@@ -501,7 +564,7 @@ const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
           </MapLibreRN.ShapeSource>
         )}
 
-        {Platform.OS === 'ios' && <MapLibreRN.Camera ref={cameraRef} />}
+        {(Platform.OS === 'ios' || renderCamera) && <MapLibreRN.Camera ref={cameraRef} />}
         {location && (
           <MapLibreRN.UserLocation
             animated={true}

+ 0 - 1
src/screens/InAppScreens/TravelsScreen/AddNewTripScreen/index.tsx

@@ -577,7 +577,6 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
               style={styles.wheelPicker}
               textColor={Colors.DARK_BLUE}
               itemStyle={{ fontSize: 16, fontFamily: 'montserrat-600' }}
-              isCyclic={true}
               pickerData={years}
               selectedValue={selectedYear ? selectedYear.toString() : '-'}
               onValueChange={(value: string) => {

+ 97 - 5
src/screens/InAppScreens/TravelsScreen/AddRegionsScreen/index.tsx

@@ -63,6 +63,9 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
   const [regionPopupVisible, setRegionPopupVisible] = useState(false);
   const mapRef = useRef<MapLibreRN.MapViewRef>(null);
   const cameraRef = useRef<MapLibreRN.CameraRef>(null);
+  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
+  const isAnimatingRef = useRef(false);
+  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
 
   const [filterSelectedRegions, setFilterSelectedRegions] = useState<any[]>(generateFilter([]));
   const [isLocationLoading, setIsLocationLoading] = useState(false);
@@ -70,6 +73,87 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
   const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
   const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
 
+  const cameraController = {
+    flyTo: useCallback((coordinates: number[], duration: number = 1000) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.flyTo(coordinates, duration);
+        });
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.flyTo(coordinates, duration);
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, []),
+
+    setCamera: useCallback((config: any) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.setCamera(config);
+        });
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+            setRenderCamera(false);
+          },
+          (config.animationDuration ?? 1000) + 200
+        );
+      } else {
+        cameraRef.current?.setCamera(config);
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+          },
+          (config.animationDuration ?? 1000) + 100
+        );
+      }
+    }, []),
+
+    fitBounds: useCallback((ne: number[], sw: number[], padding: number[], duration: number) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.fitBounds(ne, sw, padding, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.fitBounds(ne, sw, padding, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, [])
+  };
+
   useEffect(() => {
     if (data && data.regions) {
       setRegions(data.regions);
@@ -95,6 +179,14 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
     addRegionsAsync();
   }, [regionsParams]);
 
+  useEffect(() => {
+    return () => {
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+    };
+  }, []);
+
   const addRegionFromSearch = async (searchRegion: RegionAddData) => {
     const regionIndex = selectedRegions.findIndex((region) => region.id === searchRegion.id);
     const regionFromApi = regions?.find((region) => region.id === searchRegion.id);
@@ -113,7 +205,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
         const region = regionsList.data.find((region) => region.id === searchRegion.id);
         if (region) {
           const bounds = turf.bbox(region.bbox);
-          cameraRef.current?.fitBounds(
+          cameraController.fitBounds(
             [bounds[2], bounds[3]],
             [bounds[0], bounds[1]],
             [50, 50, 50, 50],
@@ -190,7 +282,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
               const region = regionsList.data.find((region) => region.id === id);
               if (region) {
                 const bounds = turf.bbox(region.bbox);
-                cameraRef.current?.fitBounds(
+                cameraController.fitBounds(
                   [bounds[2], bounds[3]],
                   [bounds[0], bounds[1]],
                   [50, 50, 50, 50],
@@ -233,7 +325,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
       setLocation(currentLocation.coords);
 
       if (currentLocation.coords) {
-        cameraRef.current?.flyTo(
+        cameraController.flyTo(
           [currentLocation.coords.longitude, currentLocation.coords.latitude],
           1000
         );
@@ -294,7 +386,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
           attributionEnabled={false}
           onPress={handleMapPress}
         >
-          {Platform.OS === 'ios' && <MapLibreRN.Camera ref={cameraRef} />}
+          {(Platform.OS === 'ios' || renderCamera) && <MapLibreRN.Camera ref={cameraRef} />}
 
           <MapLibreRN.LineLayer
             id="nm-regions-line-layer"
@@ -339,7 +431,7 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
                 const currentZoom = await mapRef.current?.getZoom();
                 const newZoom = (currentZoom || 0) + 2;
 
-                cameraRef.current?.setCamera({
+                cameraController.setCamera({
                   centerCoordinate: [location.longitude, location.latitude],
                   zoomLevel: newZoom,
                   animationDuration: 500,

+ 97 - 5
src/screens/OfflineMapsScreen/SelectRegionsScreen/index.tsx

@@ -95,6 +95,90 @@ export const SelectRegionScreen = ({ navigation }: { navigation: any }) => {
   const [location, setLocation] = useState<any | null>(null);
   const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
   const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
+  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
+  const isAnimatingRef = useRef(false);
+  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
+
+  const cameraController = {
+    flyTo: useCallback((coordinates: number[], duration: number = 1000) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.flyTo(coordinates, duration);
+        });
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.flyTo(coordinates, duration);
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, []),
+
+    setCamera: useCallback((config: any) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.setCamera(config);
+        });
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+            setRenderCamera(false);
+          },
+          (config.animationDuration ?? 1000) + 200
+        );
+      } else {
+        cameraRef.current?.setCamera(config);
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+          },
+          (config.animationDuration ?? 1000) + 100
+        );
+      }
+    }, []),
+
+    fitBounds: useCallback((ne: number[], sw: number[], padding: number[], duration: number) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.fitBounds(ne, sw, padding, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.fitBounds(ne, sw, padding, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, [])
+  };
 
   useEffect(() => {
     if (data && data.regions) {
@@ -125,6 +209,14 @@ export const SelectRegionScreen = ({ navigation }: { navigation: any }) => {
     checkConnectionType();
   }, []);
 
+  useEffect(() => {
+    return () => {
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+    };
+  }, []);
+
   const closeModal = () => {
     setModalState({
       visible: false,
@@ -182,7 +274,7 @@ export const SelectRegionScreen = ({ navigation }: { navigation: any }) => {
         const region = regionsList.data.find((region) => region.id === searchRegion.id);
         if (region) {
           const bounds = turf.bbox(region.bbox);
-          cameraRef.current?.fitBounds(
+          cameraController.fitBounds(
             [bounds[2], bounds[3]],
             [bounds[0], bounds[1]],
             [50, 50, 50, 50],
@@ -370,7 +462,7 @@ export const SelectRegionScreen = ({ navigation }: { navigation: any }) => {
               const region = regionsList.data.find((region) => region.id === id);
               if (region) {
                 const bounds = turf.bbox(region.bbox);
-                cameraRef.current?.fitBounds(
+                cameraController.fitBounds(
                   [bounds[2], bounds[3]],
                   [bounds[0], bounds[1]],
                   [50, 50, 50, 50],
@@ -414,7 +506,7 @@ export const SelectRegionScreen = ({ navigation }: { navigation: any }) => {
       setLocation(currentLocation.coords);
 
       if (currentLocation.coords) {
-        cameraRef.current?.flyTo(
+        cameraController.flyTo(
           [currentLocation.coords.longitude, currentLocation.coords.latitude],
           1000
         );
@@ -475,7 +567,7 @@ export const SelectRegionScreen = ({ navigation }: { navigation: any }) => {
           attributionEnabled={false}
           onPress={handleMapPress}
         >
-          {Platform.OS === 'ios' && <MapLibreRN.Camera ref={cameraRef} />}
+          {(Platform.OS === 'ios' || renderCamera) && <MapLibreRN.Camera ref={cameraRef} />}
 
           <MapLibreRN.LineLayer
             id="nm-regions-line-layer"
@@ -520,7 +612,7 @@ export const SelectRegionScreen = ({ navigation }: { navigation: any }) => {
                 const currentZoom = await mapRef.current?.getZoom();
                 const newZoom = (currentZoom || 0) + 2;
 
-                cameraRef.current?.setCamera({
+                cameraController.setCamera({
                   centerCoordinate: [location.longitude, location.latitude],
                   zoomLevel: newZoom,
                   animationDuration: 500,