Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix native map download #1114

Merged
merged 1 commit into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/app/components/card/LargeCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,14 @@ const loadStyles = (theme: any) => {
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
padding: currentTheme.size.cardPadding,
padding:
Platform.OS === 'web'
? currentTheme.size.cardPadding
: currentTheme.size.mobilePadding,
paddingHorizontal: currentTheme.padding.paddingInside,
marginBottom: 20,
height: Platform.OS === 'web' ? 650 : '23%',
minHeight: 350,
overflow: 'hidden',
},
};
Expand Down
128 changes: 70 additions & 58 deletions packages/app/components/destination/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,69 +132,80 @@ export const DestinationPage = () => {
const map = () => <MapContainer shape={shape} />;

return (
<ScrollView>
{isLoading && (
<RText style={{ width: '90%', alignSelf: 'center' }}>Loading...</RText>
)}
{!isLoading && !isError && (
<View style={styles.container}>
<View
style={{
zIndex: 1,
width: '100%',
...styles.headerContainer,
}}
<View style={styles.container}>
<ScrollView>
{isLoading && (
<RText
style={{ width: '90%', alignSelf: 'center', textAlign: 'center' }}
>
{Platform.OS === 'web' ? (
<PlacesAutocomplete
onSelect={handleSearchSelect}
placeholder={'Search by park, city, or trail'}
/>
) : (
<RButton
Loading...
</RText>
)}
<View style={{ flex: 1, marginBottom: 40 }}>
{!isLoading && !isError && (
<>
<View
style={{
backgroundColor: currentTheme.colors.text,
minWidth: '100%',
height: 25,
flexDirection: 'row',
}}
onPress={() => {
router.push('/search');
zIndex: 1,
width: '100%',
...styles.headerContainer,
}}
>
<MaterialCommunityIcons
name="magnify"
size={24}
color={currentTheme.colors.background}
/>
<RText color={currentTheme.colors.textDarkGrey} opacity={0.6}>
Search by park, city, or trail
</RText>
</RButton>
)}
</View>

<DestinationHeader
geoJSON={geoJSON}
selectedSearchResult={currentDestination}
/>
<LargeCard
title="Map"
Icon={() => (
<Ionicons
name="location"
size={24}
color={currentTheme.colors.textPrimary}
{Platform.OS === 'web' ? (
<PlacesAutocomplete
onSelect={handleSearchSelect}
placeholder={'Search by park, city, or trail'}
/>
) : (
<RButton
style={{
backgroundColor: currentTheme.colors.text,
minWidth: '100%',
height: 25,
flexDirection: 'row',
}}
onPress={() => {
router.push('/search');
}}
>
<MaterialCommunityIcons
name="magnify"
size={24}
color={currentTheme.colors.background}
/>
<RText
color={currentTheme.colors.textDarkGrey}
opacity={0.6}
>
Search by park, city, or trail
</RText>
</RButton>
)}
</View>

<DestinationHeader
geoJSON={geoJSON}
selectedSearchResult={currentDestination}
/>
<LargeCard
title="Map"
Icon={() => (
<Ionicons
name="location"
size={24}
color={currentTheme.colors.textPrimary}
/>
)}
ContentComponent={map}
contentProps={{ shape }}
type="map"
/>
)}
ContentComponent={map}
contentProps={{ shape }}
type="map"
/>
<WeatherData latLng={latLng} />
<WeatherData latLng={latLng} />
</>
)}
</View>
)}
</ScrollView>
</ScrollView>
</View>
);
};

Expand All @@ -208,7 +219,6 @@ const loadStyles = (theme) => {
paddingBottom: 12,
paddingLeft: 16,
width: '100%',
marginBottom: 40,
backgroundColor: currentTheme.colors.background,
},
headerContainer: {
Expand Down Expand Up @@ -246,6 +256,8 @@ const loadStyles = (theme) => {
justifyContent: 'space-between',
marginBottom: 20,
width: '100%',
backgroundColor: isDark ? '#2D2D2D' : currentTheme.colors.white,
padding: 25,
},
};
};
88 changes: 65 additions & 23 deletions packages/app/components/map/Map.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
RButton as OriginalRButton,
RInput as OriginalRInput,
RStack,
RText,
} from '@packrat/ui';

import { MAPBOX_ACCESS_TOKEN } from '@packrat/config';
Expand All @@ -37,6 +38,8 @@ import * as DocumentPicker from 'expo-document-picker';
import * as FileSystem from 'expo-file-system';
import { DOMParser } from 'xmldom';
import { MapProps } from './models';
import { useUserQuery } from 'app/auth/hooks';
import { useUpdateUser } from 'app/hooks/user/useUpdateUser';

interface GeoJsonProperties {
name?: string;
Expand Down Expand Up @@ -66,9 +69,13 @@ Mapbox.setAccessToken(MAPBOX_ACCESS_TOKEN);
const NativeMap: React.FC<MapProps> = ({
shape: shapeProp,
onExitFullScreen,
mapName: predefinedMapName,
forceFullScreen = false,
downloadable = true,
shouldEnableDownload = true,
}) => {
const { user, refetch } = useUserQuery();
console.log({ user });
const updateUser = useUpdateUser();
const styles = useCustomStyles(loadStyles);
const {
camera,
Expand All @@ -85,7 +92,7 @@ const NativeMap: React.FC<MapProps> = ({
setShowMapNameInputDialog,
shape,
setShape,
mapName,
mapName: rawMapName,
setMapName,
trailCenterPoint,
setTrailCenterPoint,
Expand All @@ -99,6 +106,13 @@ const NativeMap: React.FC<MapProps> = ({
// For some reason not setting default state value not working from hook
const isFullScreenMode = forceFullScreen || mapFullscreen;

const mapName = rawMapName?.trim();
const mapNameErrorMessage = !mapName
? 'The map name must not be empty'
: user?.offlineMaps?.[mapName?.toLowerCase()] != null
? 'A map with the same name already exist'
: '';

const handleShapeUpload = async () => {
try {
const result: any = await DocumentPicker.getDocumentAsync({
Expand All @@ -116,6 +130,36 @@ const NativeMap: React.FC<MapProps> = ({
}
};

const handleDownloadMap = async () => {
const bounds = mapViewRef.current
? await mapViewRef.current.getVisibleBounds()
: null;
const downloadOptions = {
name: mapName,
styleURL: 'mapbox://styles/mapbox/outdoors-v11',
bounds,
minZoom: 0,
maxZoom: 8,
metadata: {
shape: JSON.stringify(shape),
},
};

// Save the map under user profile.
updateUser({
id: user.id,
offlineMaps: {
...(user.offlineMaps || {}),
[mapName.toLowerCase()]: downloadOptions,
},
})
.then(() => refetch())
.then(() => {
onDownload(downloadOptions);
})
.catch(() => {});
};

function CircleCapComp() {
return (
<View
Expand Down Expand Up @@ -298,13 +342,17 @@ const NativeMap: React.FC<MapProps> = ({
});
}}
styles={styles}
downloadable={downloadable || isShapeDownloadable(shape)}
downloadable={shouldEnableDownload && isShapeDownloadable(shape)}
downloading={downloading}
shape={shape}
onDownload={() => {
setShowMapNameInputDialog(true);
if (predefinedMapName) {
handleDownloadMap();
} else {
setShowMapNameInputDialog(true);
}
}}
handleGpxUpload={handleShapeUpload}
handleGpxUpload={shouldEnableDownload && handleShapeUpload}
progress={progress}
/>
</View>
Expand Down Expand Up @@ -334,11 +382,14 @@ const NativeMap: React.FC<MapProps> = ({
onChangeText={(text) => {
setMapName(text);
}}
value={mapName}
value={rawMapName}
mx="3"
placeholder="map name"
w="100%"
/>
<RText style={styles.mapNameFieldErrorMessage}>
{mapNameErrorMessage}
</RText>
</AlertDialog.Body>
<AlertDialog.Footer>
<RStack
Expand All @@ -360,24 +411,10 @@ const NativeMap: React.FC<MapProps> = ({
</RButton>
<RButton
colorScheme="success"
onPress={async () => {
setShowMapNameInputDialog(false);
const bounds = mapViewRef.current
? await mapViewRef.current.getVisibleBounds()
: null;
const downloadOptions = {
name: mapName,
styleURL: 'mapbox://styles/mapbox/outdoors-v11',
bounds,
minZoom: 0,
maxZoom: 8,
metadata: {
shape: JSON.stringify(shape),
},
};

onDownload(downloadOptions);
disabled={!!mapNameErrorMessage}
onPress={() => {
setShowMapNameInputDialog(false);
handleDownloadMap();
}}
>
OK
Expand Down Expand Up @@ -439,6 +476,11 @@ const loadStyles = () => ({
justifyContent: 'center',
alignItems: 'center',
},
mapNameFieldErrorMessage: {
color: theme.colors.error,
fontStyle: 'italic',
fontSize: 12,
},
});

export default NativeMap;
5 changes: 5 additions & 0 deletions packages/app/components/map/MapPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { RImage } from '@packrat/ui';
import { useProcessedShape, useMapPreviewData } from './useMapPreview';
import { useAuthUserToken } from 'app/auth/hooks';
export default function MapPreview({ shape }) {
const processedShape = useProcessedShape(shape);
const { token } = useAuthUserToken();
const mapPreviewData: any = useMapPreviewData(shape, processedShape);

if (!mapPreviewData) return null;
Expand All @@ -14,6 +16,9 @@ export default function MapPreview({ shape }) {
}}
source={{
uri: mapPreviewData.uri,
headers: {
Authorization: `Bearer ${token}`,
},
}}
/>
);
Expand Down
3 changes: 2 additions & 1 deletion packages/app/components/map/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export interface MapProps {
shape: any;
onExitFullScreen?: () => void;
forceFullScreen?: boolean;
downloadable?: boolean;
shouldEnableDownload?: boolean;
mapName?: string;
}
2 changes: 1 addition & 1 deletion packages/app/hooks/user/useUpdateUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useUpdateUser = () => {
setUser(updatedUser);
return updatedUser; // Return the updated user or a value to indicate success
} catch (error) {
console.error('Failed to update the user');
console.error('Failed to update the user', error);
throw error;
}
};
Expand Down
Loading
Loading