|
|
@@ -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,
|