|
@@ -9,7 +9,7 @@ import {
|
|
|
Image,
|
|
|
StatusBar
|
|
|
} from 'react-native';
|
|
|
-import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
|
|
|
+import React, { useEffect, useRef, useState, useCallback } from 'react';
|
|
|
|
|
|
import MapLibreGL, { CameraRef, MapViewRef } from '@maplibre/maplibre-react-native';
|
|
|
import { styles } from './style';
|
|
@@ -28,8 +28,8 @@ import ProfileIcon from 'assets/icons/bottom-navigation/profile.svg';
|
|
|
import RegionPopup from 'src/components/RegionPopup';
|
|
|
import { useRegion } from 'src/contexts/RegionContext';
|
|
|
import { qualityOptions } from '../TravelsScreen/utils/constants';
|
|
|
-import { AvatarWithInitials, EditNmModal, LocationPopup, WarningModal } from 'src/components';
|
|
|
-import { API_HOST } from 'src/constants';
|
|
|
+import { AvatarWithInitials, EditNmModal, WarningModal } from 'src/components';
|
|
|
+import { API_HOST, MAP_HOST } from 'src/constants';
|
|
|
import { NAVIGATION_PAGES } from 'src/types';
|
|
|
import Animated, {
|
|
|
Easing,
|
|
@@ -57,13 +57,16 @@ import moment from 'moment';
|
|
|
import {
|
|
|
usePostGetVisitedCountriesIdsQuery,
|
|
|
usePostGetVisitedDareIdsQuery,
|
|
|
- usePostGetVisitedRegionsIdsQuery
|
|
|
+ usePostGetVisitedRegionsIdsQuery,
|
|
|
+ usePostGetVisitedSeriesIdsQuery
|
|
|
} from '@api/maps';
|
|
|
import FilterModal from './FilterModal';
|
|
|
import { useGetListDareQuery } from '@api/myDARE';
|
|
|
+import { useGetIconsQuery, usePostSetToggleItem } from '@api/series';
|
|
|
+import MarkerItem from './MarkerItem';
|
|
|
|
|
|
MapLibreGL.setAccessToken(null);
|
|
|
-// MapLibreGL.Logger.setLogLevel('error');
|
|
|
+MapLibreGL.Logger.setLogLevel('error');
|
|
|
|
|
|
const generateFilter = (ids: number[]) => {
|
|
|
return ids?.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
|
|
@@ -95,7 +98,7 @@ let countries_visited = {
|
|
|
fillOutlineColor: 'rgba(14, 80, 109, 1)'
|
|
|
},
|
|
|
filter: generateFilter([]),
|
|
|
- maxzoom: 12
|
|
|
+ maxzoom: 10
|
|
|
};
|
|
|
|
|
|
let dare_visited = {
|
|
@@ -163,46 +166,43 @@ let selected_region = {
|
|
|
maxzoom: 12
|
|
|
};
|
|
|
|
|
|
-let series_layer_cluster = {
|
|
|
- id: 'series_layer_cluster',
|
|
|
+let series_layer = {
|
|
|
+ id: 'series_layer',
|
|
|
type: 'symbol',
|
|
|
- source: 'nomadmania_series_cluster',
|
|
|
+ source: 'nomadmania_series',
|
|
|
'source-layer': 'series',
|
|
|
- minzoom: 0,
|
|
|
- maxzoom: 10,
|
|
|
- filter: ['==', 'clustered', true],
|
|
|
layout: {
|
|
|
- 'icon-image': 'series',
|
|
|
+ 'icon-image': '{series_id}',
|
|
|
'icon-size': 0.1,
|
|
|
'text-anchor': 'top',
|
|
|
- 'text-field': '{point_count}',
|
|
|
- 'text-font': ['Noto Sans Bold'],
|
|
|
+ 'text-field': '{series_name} - {name}',
|
|
|
+ 'text-font': ['Noto Sans Regular'],
|
|
|
'text-max-width': 9,
|
|
|
'text-offset': [0, 0.6],
|
|
|
'text-padding': 2,
|
|
|
'text-size': 12,
|
|
|
visibility: 'visible',
|
|
|
'text-optional': true,
|
|
|
- 'text-ignore-placement': true
|
|
|
+ 'text-ignore-placement': true,
|
|
|
+ 'text-allow-overlap': true
|
|
|
},
|
|
|
paint: {
|
|
|
'text-color': '#666',
|
|
|
'text-halo-blur': 0.5,
|
|
|
'text-halo-color': '#ffffff',
|
|
|
'text-halo-width': 1
|
|
|
- }
|
|
|
+ },
|
|
|
+ filter: generateFilter([])
|
|
|
};
|
|
|
|
|
|
-let series_layer = {
|
|
|
- id: 'series_layer',
|
|
|
+let series_visited = {
|
|
|
+ id: 'series_visited',
|
|
|
type: 'symbol',
|
|
|
source: 'nomadmania_series',
|
|
|
'source-layer': 'series',
|
|
|
- minzoom: 0,
|
|
|
- maxzoom: 24,
|
|
|
layout: {
|
|
|
- 'icon-image': '{series_id}',
|
|
|
- 'icon-size': 0.1,
|
|
|
+ 'icon-image': '{series_id}v',
|
|
|
+ 'icon-size': 0.15,
|
|
|
'text-anchor': 'top',
|
|
|
'text-field': '{series_name} - {name}',
|
|
|
'text-font': ['Noto Sans Regular'],
|
|
@@ -221,7 +221,7 @@ let series_layer = {
|
|
|
'text-halo-color': '#ffffff',
|
|
|
'text-halo-width': 1
|
|
|
},
|
|
|
- filter: ['!=', 'clustered', true]
|
|
|
+ filter: generateFilter([])
|
|
|
};
|
|
|
|
|
|
const INITIAL_REGION = {
|
|
@@ -277,6 +277,8 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
+userId,
|
|
|
type === 'dare' && !!userId
|
|
|
);
|
|
|
+ const { data: visitedSeriesIds } = usePostGetVisitedSeriesIdsQuery(token, !!userId);
|
|
|
+ const { data: seriesIcons } = useGetIconsQuery(true);
|
|
|
const userInfo = storage.get('currentUserData', StoreType.STRING) as string;
|
|
|
const { mutateAsync: mutateUserData } = fetchUserData();
|
|
|
const { mutateAsync: mutateUserDataDare } = fetchUserDataDare();
|
|
@@ -289,7 +291,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
const [location, setLocation] = useState<any | null>(null);
|
|
|
const [userAvatars, setUserAvatars] = useState<string[]>([]);
|
|
|
const [userInfoData, setUserInfoData] = useState<any>(null);
|
|
|
- const [selectedMarker, setSelectedMarker] = useState(null);
|
|
|
+ const [selectedMarker, setSelectedMarker] = useState<any>(null);
|
|
|
|
|
|
const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
|
|
|
const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
|
|
@@ -326,9 +328,38 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
const [regionsVisitedFilter, setRegionsVisitedFilter] = useState(generateFilter([]));
|
|
|
const [countriesVisitedFilter, setCountriesVisitedFilter] = useState(generateFilter([]));
|
|
|
const [dareVisitedFilter, setDareVisitedFilter] = useState(generateFilter([]));
|
|
|
+ const [seriesVisitedFilter, setSeriesVisitedFilter] = useState(generateFilter([]));
|
|
|
+ const [seriesNotVisitedFilter, setSeriesNotVisitedFilter] = useState(generateFilter([]));
|
|
|
const [regionsVisited, setRegionsVisited] = useState<any[]>([]);
|
|
|
const [countriesVisited, setCountriesVisited] = useState<any[]>([]);
|
|
|
const [dareVisited, setDareVisited] = useState<any[]>([]);
|
|
|
+ const [seriesVisited, setSeriesVisited] = useState<any[]>([]);
|
|
|
+ const [images, setImages] = useState<any>({});
|
|
|
+ const { mutateAsync: updateSeriesItem } = usePostSetToggleItem();
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (seriesIcons) {
|
|
|
+ let loadedImages: any = {};
|
|
|
+
|
|
|
+ seriesIcons.data.forEach(async (icon) => {
|
|
|
+ const id = icon.id;
|
|
|
+ const img = API_HOST + '/static/img/series_new2/' + icon.new_icon_png;
|
|
|
+ const imgVisited = API_HOST + '/static/img/series_new2/' + icon.new_icon_visited_png;
|
|
|
+ if (!img || !imgVisited) return;
|
|
|
+ try {
|
|
|
+ const iconImage = { uri: img };
|
|
|
+ const visitedIconImage = { uri: imgVisited };
|
|
|
+
|
|
|
+ loadedImages[id] = iconImage;
|
|
|
+ loadedImages[`${id}v`] = visitedIconImage;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`Error loading icon for series_id ${id}:`, error);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ setImages(loadedImages);
|
|
|
+ }
|
|
|
+ }, [seriesIcons]);
|
|
|
|
|
|
useEffect(() => {
|
|
|
const loadDatabases = async () => {
|
|
@@ -362,9 +393,11 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
|
|
|
useFocusEffect(
|
|
|
useCallback(() => {
|
|
|
- refetchVisitedRegions();
|
|
|
- refetchVisitedCountries();
|
|
|
- refetchVisitedDare();
|
|
|
+ if (token) {
|
|
|
+ refetchVisitedRegions();
|
|
|
+ refetchVisitedCountries();
|
|
|
+ refetchVisitedDare();
|
|
|
+ }
|
|
|
}, [navigation])
|
|
|
);
|
|
|
|
|
@@ -387,6 +420,12 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
}
|
|
|
}, [visitedDareIds]);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (visitedSeriesIds && token) {
|
|
|
+ setSeriesVisited(visitedSeriesIds.ids);
|
|
|
+ }
|
|
|
+ }, [visitedSeriesIds]);
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
if (regionsVisited && regionsVisited.length) {
|
|
|
setRegionsVisitedFilter(generateFilter(regionsVisited));
|
|
@@ -405,6 +444,37 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
}
|
|
|
}, [dareVisited]);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (!seriesFilter.visible) {
|
|
|
+ setSeriesVisitedFilter(generateFilter([]));
|
|
|
+ setSeriesNotVisitedFilter(generateFilter([]));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (seriesFilter.applied) {
|
|
|
+ if (seriesVisited?.length) {
|
|
|
+ setSeriesVisitedFilter([
|
|
|
+ 'all',
|
|
|
+ ['any', ...seriesVisited.map((id) => ['==', 'id', id])],
|
|
|
+ ['any', ...seriesFilter.groups.map((groupId: number) => ['==', 'series_id', groupId])]
|
|
|
+ ]);
|
|
|
+ setSeriesNotVisitedFilter([
|
|
|
+ 'all',
|
|
|
+ ['all', ...seriesVisited.map((id) => ['!=', 'id', id])],
|
|
|
+ ['any', ...seriesFilter.groups.map((groupId: number) => ['==', 'series_id', groupId])]
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ setSeriesNotVisitedFilter([
|
|
|
+ 'any',
|
|
|
+ ...seriesFilter.groups.map((groupId: number) => ['==', 'series_id', groupId])
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ setSeriesVisitedFilter(['any', ...seriesVisited.map((id) => ['==', 'id', id])]);
|
|
|
+ setSeriesNotVisitedFilter(['all', ...seriesVisited.map((id) => ['!=', 'id', id])]);
|
|
|
+ }
|
|
|
+ }, [seriesVisited, seriesFilter]);
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
if (route.params?.id && route.params?.type && db1 && db2 && db3) {
|
|
|
handleFindRegion(route.params?.id, route.params?.type);
|
|
@@ -513,7 +583,10 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
|
|
|
const onMapPress = async (event: any) => {
|
|
|
if (!mapRef.current) return;
|
|
|
- closeCallout();
|
|
|
+ if (selectedMarker) {
|
|
|
+ closeCallout();
|
|
|
+ return;
|
|
|
+ }
|
|
|
try {
|
|
|
const { screenPointX, screenPointY } = event.properties;
|
|
|
|
|
@@ -813,15 +886,26 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // to do
|
|
|
- const handleMarkerPress = async (event) => {
|
|
|
+ const handleMarkerPress = async (event: any) => {
|
|
|
const { features } = event;
|
|
|
if (features?.length) {
|
|
|
const selectedFeature = features[0];
|
|
|
const { coordinates } = selectedFeature.geometry;
|
|
|
- const { name, icon, description, series_name } = selectedFeature.properties;
|
|
|
-
|
|
|
- setSelectedMarker({ coordinates, name, icon, description, series_name });
|
|
|
+ const visited = seriesVisited.includes(selectedFeature.properties.id) ? 1 : 0;
|
|
|
+ const icon = images[selectedFeature.properties.series_id];
|
|
|
+
|
|
|
+ const { name, description, series_name, series_id, id } = selectedFeature.properties;
|
|
|
+
|
|
|
+ setSelectedMarker({
|
|
|
+ coordinates,
|
|
|
+ name,
|
|
|
+ icon,
|
|
|
+ description,
|
|
|
+ series_name,
|
|
|
+ visited,
|
|
|
+ series_id,
|
|
|
+ id
|
|
|
+ });
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -831,9 +915,33 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
|
|
|
const toggleSeries = useCallback(
|
|
|
async (item: any) => {
|
|
|
- console.log('toggleSeries', item);
|
|
|
+ if (!token) {
|
|
|
+ setIsWarningModalVisible(true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const itemData = {
|
|
|
+ token,
|
|
|
+ series_id: item.series_id,
|
|
|
+ item_id: item.id,
|
|
|
+ checked: (item.visited === 0 ? 1 : 0) as 0 | 1,
|
|
|
+ double: 0 as 0 | 1
|
|
|
+ };
|
|
|
+
|
|
|
+ try {
|
|
|
+ updateSeriesItem(itemData);
|
|
|
+ if (item.visited === 1) {
|
|
|
+ setSeriesVisited((current) => current.filter((id) => id !== item.id));
|
|
|
+ setSelectedMarker((current: any) => ({ ...current, visited: 0 }));
|
|
|
+ } else {
|
|
|
+ setSeriesVisited((current) => [...current, item.id]);
|
|
|
+ setSelectedMarker((current: any) => ({ ...current, visited: 1 }));
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Failed to update series state', error);
|
|
|
+ }
|
|
|
},
|
|
|
- [token]
|
|
|
+ [token, updateSeriesItem]
|
|
|
);
|
|
|
|
|
|
const handleModalStateChange = (updates: { [key: string]: any }) => {
|
|
@@ -853,6 +961,10 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
onPress={onMapPress}
|
|
|
onRegionDidChange={handleRegionDidChange}
|
|
|
>
|
|
|
+ <MapLibreGL.Images images={images}>
|
|
|
+ <View />
|
|
|
+ </MapLibreGL.Images>
|
|
|
+
|
|
|
{type === 'regions' && (
|
|
|
<>
|
|
|
<MapLibreGL.FillLayer
|
|
@@ -871,7 +983,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
filter={regionsVisitedFilter as any}
|
|
|
style={regions_visited.style}
|
|
|
maxZoomLevel={regions_visited.maxzoom}
|
|
|
- belowLayerID="series_layer_cluster_circle"
|
|
|
+ belowLayerID="waterway-name"
|
|
|
/>
|
|
|
</>
|
|
|
)}
|
|
@@ -893,7 +1005,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
filter={countriesVisitedFilter as any}
|
|
|
style={countries_visited.style}
|
|
|
maxZoomLevel={countries_visited.maxzoom}
|
|
|
- belowLayerID="series_layer_cluster_circle"
|
|
|
+ belowLayerID="waterway-name"
|
|
|
/>
|
|
|
</>
|
|
|
)}
|
|
@@ -915,7 +1027,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
filter={dareVisitedFilter as any}
|
|
|
style={dare_visited.style}
|
|
|
maxZoomLevel={dare_visited.maxzoom}
|
|
|
- belowLayerID="series_layer_cluster_circle"
|
|
|
+ belowLayerID="waterway-name"
|
|
|
/>
|
|
|
</>
|
|
|
)}
|
|
@@ -927,153 +1039,62 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
filter={['==', 'id', selectedRegion]}
|
|
|
style={selected_region.style}
|
|
|
maxZoomLevel={selected_region.maxzoom}
|
|
|
- belowLayerID="series_layer_cluster_circle"
|
|
|
+ belowLayerID="waterway-name"
|
|
|
/>
|
|
|
)}
|
|
|
|
|
|
- <MapLibreGL.VectorSource
|
|
|
- id="nomadmania_series_cluster"
|
|
|
- // to do
|
|
|
- tileUrlTemplates={[
|
|
|
- 'https://maps.nomadmania.eu/tileserver/series_cluster/{z}/{x}/{y}.pbf'
|
|
|
- ]}
|
|
|
- onPress={(event) => console.log('series_cluster', event.features)}
|
|
|
- minZoomLevel={0}
|
|
|
- maxZoomLevel={24}
|
|
|
- >
|
|
|
- <MapLibreGL.CircleLayer
|
|
|
- id="series_layer_cluster_circle"
|
|
|
- sourceID={series_layer_cluster.source}
|
|
|
- sourceLayerID={series_layer_cluster['source-layer']}
|
|
|
- style={{
|
|
|
- circleRadius: 14,
|
|
|
- circleColor: '#FFFFFF',
|
|
|
- circleStrokeColor: '#000000',
|
|
|
- circleStrokeWidth: 2,
|
|
|
- circleOpacity: 1
|
|
|
- }}
|
|
|
- maxZoomLevel={series_layer_cluster.maxzoom}
|
|
|
- />
|
|
|
- <MapLibreGL.SymbolLayer
|
|
|
- id={series_layer_cluster.id}
|
|
|
- sourceID={series_layer_cluster.source}
|
|
|
- sourceLayerID={series_layer_cluster['source-layer']}
|
|
|
- aboveLayerID="series_layer_cluster_circle"
|
|
|
- style={{
|
|
|
- textField: '{point_count}',
|
|
|
- textFont: ['Noto Sans Bold'],
|
|
|
- textSize: 12,
|
|
|
- textColor: '#000000',
|
|
|
- textHaloColor: '#FFFFFF',
|
|
|
- textHaloWidth: 1,
|
|
|
- textAnchor: 'center',
|
|
|
- textOffset: [0, 0],
|
|
|
- textAllowOverlap: true
|
|
|
- }}
|
|
|
- maxZoomLevel={series_layer_cluster.maxzoom}
|
|
|
- />
|
|
|
- </MapLibreGL.VectorSource>
|
|
|
<MapLibreGL.VectorSource
|
|
|
id="nomadmania_series"
|
|
|
- tileUrlTemplates={['https://maps.nomadmania.eu/tileserver/series/{z}/{x}/{y}.pbf']}
|
|
|
+ tileUrlTemplates={[MAP_HOST + '/tileserver/series/{z}/{x}/{y}.pbf']}
|
|
|
onPress={handleMarkerPress}
|
|
|
- minZoomLevel={0}
|
|
|
- maxZoomLevel={24}
|
|
|
>
|
|
|
- <MapLibreGL.CircleLayer
|
|
|
- id="series_layer_circle"
|
|
|
- sourceID={series_layer.source}
|
|
|
- sourceLayerID={series_layer['source-layer']}
|
|
|
- aboveLayerID="series_layer_cluster"
|
|
|
- minZoomLevel={series_layer.minzoom}
|
|
|
- maxZoomLevel={series_layer.maxzoom}
|
|
|
- style={{
|
|
|
- circleRadius: 14,
|
|
|
- circleColor: '#FFFFFF',
|
|
|
- circleStrokeWidth: 2,
|
|
|
- circleStrokeColor: '#000000',
|
|
|
- circleOpacity: 1
|
|
|
- }}
|
|
|
- />
|
|
|
- <MapLibreGL.SymbolLayer
|
|
|
- id={series_layer.id}
|
|
|
- sourceID={series_layer.source}
|
|
|
- sourceLayerID={series_layer['source-layer']}
|
|
|
- aboveLayerID="series_layer_cluster"
|
|
|
- style={{
|
|
|
- iconImage: '{series_id}',
|
|
|
- iconSize: 0.1,
|
|
|
- textAnchor: 'top',
|
|
|
- textField: '{series_name} - {name}',
|
|
|
- textFont: ['Noto Sans Regular'],
|
|
|
- textMaxWidth: 9,
|
|
|
- textOffset: [0, 0.6],
|
|
|
- textPadding: 2,
|
|
|
- textSize: 12,
|
|
|
- visibility: 'visible',
|
|
|
- textOptional: true,
|
|
|
- textIgnorePlacement: true,
|
|
|
- iconColor: '#666',
|
|
|
- iconOpacity: 1,
|
|
|
- iconHaloColor: '#ffffff',
|
|
|
- iconHaloWidth: 1,
|
|
|
- iconHaloBlur: 0.5,
|
|
|
- textHaloBlur: 0.5,
|
|
|
- textHaloColor: '#ffffff',
|
|
|
- textHaloWidth: 1,
|
|
|
- textColor: '#666'
|
|
|
- }}
|
|
|
- minZoomLevel={series_layer.minzoom}
|
|
|
- maxZoomLevel={series_layer.maxzoom}
|
|
|
- />
|
|
|
+ {seriesFilter.status !== 1 ? (
|
|
|
+ <MapLibreGL.SymbolLayer
|
|
|
+ id={series_layer.id}
|
|
|
+ sourceID={series_layer.source}
|
|
|
+ sourceLayerID={series_layer['source-layer']}
|
|
|
+ belowLayerID={Platform.OS === 'android' ? 'waterway-name' : undefined}
|
|
|
+ filter={seriesNotVisitedFilter as any}
|
|
|
+ style={{
|
|
|
+ iconImage: ['get', 'series_id'],
|
|
|
+ iconSize: 0.18,
|
|
|
+ visibility: 'visible',
|
|
|
+ iconColor: '#666',
|
|
|
+ iconOpacity: 1,
|
|
|
+ iconHaloColor: '#ffffff',
|
|
|
+ iconHaloWidth: 1,
|
|
|
+ iconHaloBlur: 0.5
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <></>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {seriesFilter.status !== 0 ? (
|
|
|
+ <MapLibreGL.SymbolLayer
|
|
|
+ id={series_visited.id}
|
|
|
+ sourceID={series_visited.source}
|
|
|
+ sourceLayerID={series_visited['source-layer']}
|
|
|
+ belowLayerID={Platform.OS === 'android' ? 'waterway-name' : undefined}
|
|
|
+ filter={seriesVisitedFilter as any}
|
|
|
+ style={{
|
|
|
+ iconImage: '{series_id}v',
|
|
|
+ iconSize: 0.18,
|
|
|
+ visibility: 'visible',
|
|
|
+ iconColor: '#666',
|
|
|
+ iconOpacity: 1,
|
|
|
+ iconHaloColor: '#ffffff',
|
|
|
+ iconHaloWidth: 1,
|
|
|
+ iconHaloBlur: 0.5
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <></>
|
|
|
+ )}
|
|
|
</MapLibreGL.VectorSource>
|
|
|
|
|
|
{selectedMarker && (
|
|
|
- <MapLibreGL.PointAnnotation
|
|
|
- id="selected_marker_callout"
|
|
|
- coordinate={selectedMarker.coordinates}
|
|
|
- anchor={{ x: 0.5, y: 1 }}
|
|
|
- >
|
|
|
- <View style={styles.customView}>
|
|
|
- <View style={styles.calloutContainer}>
|
|
|
- <View style={styles.calloutImageContainer}>
|
|
|
- <Image
|
|
|
- source={{ uri: selectedMarker.icon }}
|
|
|
- style={styles.calloutImage}
|
|
|
- resizeMode="contain"
|
|
|
- />
|
|
|
- </View>
|
|
|
- <View style={styles.calloutTextContainer}>
|
|
|
- <Text style={styles.seriesName}>{selectedMarker.series_name}</Text>
|
|
|
- <Text style={styles.markerName}>{selectedMarker.name}</Text>
|
|
|
- </View>
|
|
|
- <TouchableOpacity
|
|
|
- style={[
|
|
|
- styles.calloutButton,
|
|
|
- (selectedMarker.visited === 1 &&
|
|
|
- token && {
|
|
|
- backgroundColor: Colors.WHITE,
|
|
|
- borderWidth: 1,
|
|
|
- borderColor: Colors.BORDER_LIGHT
|
|
|
- }) ||
|
|
|
- {}
|
|
|
- ]}
|
|
|
- onPress={() => toggleSeries(selectedMarker)}
|
|
|
- >
|
|
|
- {selectedMarker?.visited === 1 && token ? (
|
|
|
- <View style={styles.completedContainer}>
|
|
|
- <CheckSvg width={14} height={14} fill={Colors.DARK_BLUE} />
|
|
|
- <Text style={[styles.calloutButtonText, { color: Colors.DARK_BLUE }]}>
|
|
|
- Completed
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- ) : (
|
|
|
- <Text style={styles.calloutButtonText}>Mark Completed</Text>
|
|
|
- )}
|
|
|
- </TouchableOpacity>
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- </MapLibreGL.PointAnnotation>
|
|
|
+ <MarkerItem marker={selectedMarker} toggleSeries={toggleSeries} token={token} />
|
|
|
)}
|
|
|
<MapLibreGL.Camera ref={cameraRef} />
|
|
|
{location && (
|
|
@@ -1210,6 +1231,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
|
|
|
style={[styles.cornerButton, styles.bottomButton, styles.bottomLeftButton]}
|
|
|
onPress={() => {
|
|
|
setIsFilterVisible(true);
|
|
|
+ closeCallout();
|
|
|
}}
|
|
|
>
|
|
|
<FilterIcon />
|