mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2026-05-06 22:56:12 -04:00
* Replace name in permission requests * TakePhoto TS * PermissionGate TS * Type * PermissionGateContainer TS * Interface * Types * LocationGate TS * Remove LocationPermissionGate from Camera * Remove write only permission * Type * ObsPhotoSelectionList TS * Code style * Show the improve with location button * Create useLocationPermission.tsx * Use new hook on suggestions * Doc comment * Use new hook in camera view * Add strings * Refactor Explore main content * Use permission hook on RootExplore * Add no location permission component * Rename function * Prop request permissions and use with button * Default to Nearby label * Remove Node type * Projects TS * Use useLocationPermission hook in projects screen * Add string * Prop permission down * Refactor list render * Refactor tab id into enum * Tab type * On nearby tab if without permission show button to prompt * Leftovers * Remove location permission gate from ObsEdit * Use location permission hook on evidence section * SearchBar TS * Do not autoFocus on search bar in location picker. Closes #1743 * Update type * LocationSearch TS * Show location permission gate on location picker's mount * Add location permission to CurrentLocationButton * Remove unused props of Map * Remove unused exports from useMapLocation * Migration * Revert "Show location permission gate on location picker's mount" This reverts commit 30ff75698c53d54d0b14cd2bd629f7155b743bf8. * Add callbacks to useLocationPermission hook * Show location permission ask on Obs Edit * Remove unused string * Reset explore filters should set location always to worldwide * Add helper function to show place text in Explore * Remove unused state of filter modal * Show place text in filters modal with helper * Show location permission button only for Nearby explore state * Add a placeMode state * Do not send placeMode to API * Also treat limited permission as yes * useLocationPermission in ExploreLocationSearch * Refactor to setting place mode Instead of logic based on the translated text of the place_guess string that is stored in ExploreContext, we are switching to an enum state that signifies which mode to show on explore: 1.) Nearby: Filters explore results based on the user's location. This also has a state without location permission that does not query the API. 2.) Place: Filtering by a specific place (as retrieved by /places API). 3.) Worldwide: Retrieve worldwide results, i.e. not having a place filter set. 4.) Map area: Filtering explore results precisely to the map rectangle shown on the explore map. * Remove import from test * Remove export * Use blocked title only for blocked permission asks * Move gallery permission container to Tab navigator as are the others * Add gallery save title * Split location permission explanation into two * Update strings.ftl * Only nav to location picker if permission was not granted * Check permission on app being foregrounded * The location permission part is handled by useLocationPermission * Do not store permission result in hook * Use hasPermission from permissions hook * Update fetchUserLocation.e2e-mock * Move hook one higher * Show user location if permission is given * PermissionGate callbacks should use useCallback * Add permission hook to map usage * Fix test * Update layout to be asserted * Add location permission hook to Explore * Remove console.log * Few TS fixes * Indentation * Remove superficial check * Update Podfile.lock
159 lines
4.5 KiB
TypeScript
159 lines
4.5 KiB
TypeScript
import { searchObservations } from "api/observations";
|
|
import classnames from "classnames";
|
|
import {
|
|
Body1,
|
|
Button,
|
|
Map
|
|
} from "components/SharedComponents";
|
|
import { getMapRegion } from "components/SharedComponents/Map/helpers/mapHelpers.ts";
|
|
import { View } from "components/styledComponents";
|
|
import React, { useState } from "react";
|
|
import { Platform } from "react-native";
|
|
import { Region } from "react-native-maps";
|
|
import { useDebugMode, useTranslation } from "sharedHooks";
|
|
import useAuthenticatedQuery from "sharedHooks/useAuthenticatedQuery";
|
|
import { getShadowForColor } from "styles/global";
|
|
import colors from "styles/tailwindColors";
|
|
|
|
import useMapLocation from "./hooks/useMapLocation";
|
|
|
|
const DROP_SHADOW = getShadowForColor( colors.darkGray, {
|
|
offsetHeight: 4,
|
|
elevation: 6
|
|
} );
|
|
|
|
interface Props {
|
|
observations: Object[];
|
|
queryParams: {
|
|
taxon_id?: number;
|
|
};
|
|
}
|
|
|
|
const MapView = ( {
|
|
observations,
|
|
queryParams
|
|
}: Props ) => {
|
|
const { t } = useTranslation( );
|
|
const { isDebug } = useDebugMode( );
|
|
const [zoom, setZoom] = useState( -1 );
|
|
|
|
const {
|
|
onPanDrag,
|
|
onZoomToNearby,
|
|
redoSearchInMapArea,
|
|
region,
|
|
showMapBoundaryButton,
|
|
startAtNearby,
|
|
updateMapBoundaries
|
|
} = useMapLocation( );
|
|
|
|
/*
|
|
* Query for the bounding box of the taxon_id, if it hasn't been fetched yet, and
|
|
* zoom to that bounding box on the map
|
|
*/
|
|
interface StoredBoundingBoxes {
|
|
[taxonId: number]: Region;
|
|
}
|
|
const [storedBoundingBoxes, setStoredBoundingBoxes] = useState<StoredBoundingBoxes>( {} );
|
|
const obsParams = {
|
|
...queryParams, return_bounds: true, per_page: 0
|
|
};
|
|
const {
|
|
data
|
|
} = useAuthenticatedQuery(
|
|
["fetchTaxonBoundingBox"],
|
|
( optsWithAuth: Object ) => searchObservations( obsParams, optsWithAuth ),
|
|
{
|
|
enabled: obsParams.taxon_id && !storedBoundingBoxes[obsParams.taxon_id]
|
|
}
|
|
);
|
|
// Only update the map once per taxon_id, so that it only zooms to the
|
|
// bounding box on initial load
|
|
if ( obsParams.taxon_id && !storedBoundingBoxes[obsParams.taxon_id] ) {
|
|
if ( data && data.total_bounds && data.total_bounds.nelat !== undefined ) {
|
|
const boundsRegion = getMapRegion( data.total_bounds );
|
|
updateMapBoundaries( boundsRegion );
|
|
setStoredBoundingBoxes( {
|
|
...storedBoundingBoxes,
|
|
[obsParams.taxon_id]: boundsRegion
|
|
} );
|
|
}
|
|
}
|
|
|
|
const tileMapParams = {
|
|
...queryParams
|
|
};
|
|
// Tile queries never need these params
|
|
delete tileMapParams.return_bounds;
|
|
delete tileMapParams.order;
|
|
delete tileMapParams.orderBy;
|
|
|
|
return (
|
|
<View className="flex-1 overflow-hidden h-full">
|
|
<View className="z-10">
|
|
{showMapBoundaryButton && (
|
|
<View
|
|
className="mx-auto"
|
|
style={DROP_SHADOW}
|
|
>
|
|
<Button
|
|
text={t( "REDO-SEARCH-IN-MAP-AREA" )}
|
|
level="focus"
|
|
className="top-[60px] absolute self-center"
|
|
onPress={redoSearchInMapArea}
|
|
/>
|
|
</View>
|
|
)}
|
|
</View>
|
|
{ isDebug && (
|
|
<View
|
|
className={classnames(
|
|
"absolute",
|
|
"left-5",
|
|
"bottom-[140px]",
|
|
"bg-deeppink",
|
|
"p-1",
|
|
"z-10"
|
|
)}
|
|
>
|
|
<Body1 className="text-white">
|
|
{`Zoom: ${zoom}`}
|
|
</Body1>
|
|
</View>
|
|
) }
|
|
<Map
|
|
currentLocationButtonClassName="left-5 bottom-20"
|
|
observations={observations}
|
|
onPanDrag={onPanDrag}
|
|
onRegionChangeComplete={async ( newRegion, boundaries ) => {
|
|
// Seems to be a bug in react-native-maps where
|
|
// onRegionChangeComplete fires once on initial load before the
|
|
// region actually changes, so we're just ignoring that update
|
|
// here
|
|
if ( Platform.OS === "android" && Math.round( newRegion.latitude ) === 0 ) {
|
|
return;
|
|
}
|
|
await updateMapBoundaries( newRegion, boundaries );
|
|
if ( startAtNearby ) {
|
|
onZoomToNearby( newRegion, boundaries );
|
|
}
|
|
}}
|
|
onZoomToNearby={onZoomToNearby}
|
|
onZoomChange={newZoom => setZoom( newZoom )}
|
|
region={region}
|
|
showCurrentLocationButton
|
|
showExplore
|
|
showSwitchMapTypeButton
|
|
showsCompass={false}
|
|
startAtNearby={startAtNearby}
|
|
switchMapTypeButtonClassName="left-20 bottom-20"
|
|
tileMapParams={tileMapParams}
|
|
withPressableObsTiles={tileMapParams !== null}
|
|
currentLocationZoomLevel={15}
|
|
/>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default MapView;
|