From b4c95746e12d68ff7783f5f4d3f92a8b658e8527 Mon Sep 17 00:00:00 2001
From: ErikSin <67773827+ErikSin@users.noreply.github.com>
Date: Wed, 5 Feb 2025 10:59:48 -0500
Subject: [PATCH] chore: update bottom sheet architecture (#927)
* chore: create new bottom sheet wrapper
* chore: reusable hook to disable android back button
* chore: prevent back button hook in bottom sheet wrapper
* chore: added bottom sheet description
* chore: updated sync settings to use new modal
* chore: update border radius
* chore: unsubscribe from listener
---
messages/en.json | 45 +-
src/frontend/Navigation/Stack/AppScreens.tsx | 579 +++++++++---------
src/frontend/hooks/server/mediaSync.ts | 2 +
.../hooks/usePreventAndroidBackButton.ts | 18 +
.../ProjectSettings/MediaSyncSettings.tsx | 173 ------
.../SyncEverythingBottomSheet.tsx | 75 +++
.../SyncPreviewsBottomSheet.tsx | 82 +++
.../MediaSyncSettings/index.tsx | 107 ++++
.../sharedComponents/BottomSheetWrapper.tsx | 59 ++
src/frontend/sharedTypes/navigation.ts | 2 +
10 files changed, 674 insertions(+), 468 deletions(-)
create mode 100644 src/frontend/hooks/usePreventAndroidBackButton.ts
delete mode 100644 src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings.tsx
create mode 100644 src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncEverythingBottomSheet.tsx
create mode 100644 src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncPreviewsBottomSheet.tsx
create mode 100644 src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/index.tsx
create mode 100644 src/frontend/sharedComponents/BottomSheetWrapper.tsx
diff --git a/messages/en.json b/messages/en.json
index daab4fb84..87ab76403 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -871,36 +871,18 @@
"screens.MediaSyncSettings.syncEverything": {
"message": "Sync Everything"
},
- "screens.MediaSyncSettings.syncEverythingButtonBottomSheet": {
- "message": "Sync Everything?"
- },
"screens.MediaSyncSettings.syncEverythingDescription": {
"message": "Your device will sync all content at full size, including photos, audio, and videos."
},
- "screens.MediaSyncSettings.syncEverythingDescriptionBottomSheet": {
- "message": "You are about to sync everything. This may increase the disk space used on your device."
- },
"screens.MediaSyncSettings.syncEverythingWarning": {
"message": "Note: This will use more storage."
},
- "screens.MediaSyncSettings.syncPreviewWarningBottomSheet": {
- "message": "You will no longer sync Audio or Video."
- },
"screens.MediaSyncSettings.syncPreviews": {
"message": "Sync Previews (Photos Only)"
},
- "screens.MediaSyncSettings.syncPreviewsBottomSheetConfirm": {
- "message": "Sync Previews"
- },
- "screens.MediaSyncSettings.syncPreviewsButtonBottomSheet": {
- "message": "Sync Previews?"
- },
"screens.MediaSyncSettings.syncPreviewsDescription": {
"message": "Photos will sync at a reduced smaller size. Device will not sync audio or video."
},
- "screens.MediaSyncSettings.syncPreviewsDescriptionBottomSheet": {
- "message": "Your device will keep all existing data but new observations will sync in a smaller, preview size."
- },
"screens.MediaSyncSettings.title": {
"message": "Sync Settings"
},
@@ -1565,6 +1547,33 @@
"screens.Sync.ProjectSyncDisplay.waitingForDevices": {
"message": "Waiting for devices"
},
+ "screens.SyncEverythingBottomSheet.cancel": {
+ "message": "Cancel"
+ },
+ "screens.SyncEverythingBottomSheet.confirm": {
+ "message": "Sync Everything"
+ },
+ "screens.SyncEverythingBottomSheet.syncEverything": {
+ "message": "Sync Everything?"
+ },
+ "screens.SyncEverythingBottomSheet.syncEverythingDescription": {
+ "message": "You are about to sync everything. This may increase the disk space used on your device."
+ },
+ "screens.SyncPreviewBottomSheet.cancel": {
+ "message": "Cancel"
+ },
+ "screens.SyncPreviewBottomSheet.confirm": {
+ "message": "Sync Previews"
+ },
+ "screens.SyncPreviewBottomSheet.syncPreviewWarningBottomSheet": {
+ "message": "You will no longer sync Audio or Video."
+ },
+ "screens.SyncPreviewBottomSheet.syncPreviewsButtonBottomSheet": {
+ "message": "Sync Previews?"
+ },
+ "screens.SyncPreviewBottomSheet.syncPreviewsDescriptionBottomSheet": {
+ "message": "Your device will keep all existing data but new observations will sync in a smaller, preview size."
+ },
"screens.Track.ObservationList.observation": {
"message": "Observation"
},
diff --git a/src/frontend/Navigation/Stack/AppScreens.tsx b/src/frontend/Navigation/Stack/AppScreens.tsx
index 2c386a9ff..7dfa3bc6d 100644
--- a/src/frontend/Navigation/Stack/AppScreens.tsx
+++ b/src/frontend/Navigation/Stack/AppScreens.tsx
@@ -69,7 +69,7 @@ import {
TrackScreen,
createNavigationOptions as createTrackNavigationOptions,
} from '../../screens/Track/index.tsx';
-import {MediaSyncSettings} from '../../screens/Settings/ProjectSettings/MediaSyncSettings.tsx';
+import {MediaSyncSettings} from '../../screens/Settings/ProjectSettings/MediaSyncSettings/index.tsx';
import {DataAndPrivacy} from '../../screens/Settings/DataAndPrivacy/DataAndPrivacy';
import {SettingsPrivacyPolicy} from '../../screens/Settings/DataAndPrivacy/SettingsPrivacyPolicy';
import {TrackEdit} from '../../screens/TrackEdit/index.tsx';
@@ -92,6 +92,8 @@ import {
createNavigationOptions as createBackgroundMapsNavigationOptions,
BackgroundMapsScreen,
} from '../../screens/Settings/MapManagement/BackgroundMaps.tsx';
+import {SyncPreviewsBottomSheet} from '../../screens/Settings/ProjectSettings/MediaSyncSettings/SyncPreviewsBottomSheet.tsx';
+import {SyncEverythingBottomSheet} from '../../screens/Settings/ProjectSettings/MediaSyncSettings/SyncEverythingBottomSheet.tsx';
export const TAB_BAR_HEIGHT = 70;
@@ -102,284 +104,307 @@ export const createDefaultScreenGroup = ({
}: {
intl: (title: MessageDescriptor) => string;
}) => (
-
- (
-
- {/* This provider allows the bottoms sheet used by tracks to open up behind the drawers */}
-
-
-
-
- )}
- />
-
-
-
- (
-
- ),
- }}
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ <>
+
+ (
+
+ {/* This provider allows the bottoms sheet used by tracks to open up behind the drawers */}
+
+
+
+
+ )}
+ />
+
+
+
+ (
+
+ ),
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
- {process.env.EXPO_PUBLIC_FEATURE_TEST_DATA_UI && (
-
- )}
-
- {}} isLoading={false} />,
- }}
- />
-
-
-
+ {process.env.EXPO_PUBLIC_FEATURE_TEST_DATA_UI && (
+
+ )}
+
+ (
+ {}} isLoading={false} />
+ ),
+ }}
+ />
+
+
+
+
+
+
+
+ >
);
diff --git a/src/frontend/hooks/server/mediaSync.ts b/src/frontend/hooks/server/mediaSync.ts
index 1c7ec2531..d493ffb91 100644
--- a/src/frontend/hooks/server/mediaSync.ts
+++ b/src/frontend/hooks/server/mediaSync.ts
@@ -7,6 +7,7 @@ import {
import {MediaSyncSetting} from '../../sharedTypes';
export const MEDIA_SYNC_SETTING_KEY = 'media_sync_setting';
+export const UPDATE_MEDIA_SETTING = 'update_media_setting';
export function convertMediaSyncSetting(isArchive: boolean): MediaSyncSetting {
return isArchive ? 'everything' : 'previews';
@@ -33,6 +34,7 @@ export function useSetMediaSyncSetting() {
const queryClient = useQueryClient();
return useMutation({
+ mutationKey: [UPDATE_MEDIA_SETTING],
mutationFn: async (newSetting: MediaSyncSetting) => {
const isArchive = isArchiveDevice(newSetting);
return api.setIsArchiveDevice(isArchive);
diff --git a/src/frontend/hooks/usePreventAndroidBackButton.ts b/src/frontend/hooks/usePreventAndroidBackButton.ts
new file mode 100644
index 000000000..c5ab335fd
--- /dev/null
+++ b/src/frontend/hooks/usePreventAndroidBackButton.ts
@@ -0,0 +1,18 @@
+import {useFocusEffect} from '@react-navigation/native';
+import {useCallback} from 'react';
+import {BackHandler} from 'react-native';
+
+export const usePreventAndroidBackButton = () => {
+ return useFocusEffect(
+ useCallback(() => {
+ const onBackPress = () => true;
+
+ const subscription = BackHandler.addEventListener(
+ 'hardwareBackPress',
+ onBackPress,
+ );
+
+ return () => subscription.remove();
+ }, []),
+ );
+};
diff --git a/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings.tsx b/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings.tsx
deleted file mode 100644
index a79136512..000000000
--- a/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-import * as React from 'react';
-import {ScrollView, StyleSheet} from 'react-native';
-import {useIntl, defineMessages} from 'react-intl';
-import {SelectOne} from '../../../sharedComponents/SelectOne';
-import {SYNC_BACKGROUND} from '../../../lib/styles';
-import {MediaSyncActionSheetContent} from './MediaSyncActionSheetContent';
-import {
- useBottomSheetModal,
- BottomSheetModal,
-} from '../../../sharedComponents/BottomSheetModal';
-import {MediaSyncSetting} from '../../../sharedTypes';
-import {
- useGetMediaSyncSetting,
- useSetMediaSyncSetting,
-} from '../../../hooks/server/mediaSync';
-
-const m = defineMessages({
- syncSettingsTitle: {
- id: 'screens.MediaSyncSettings.title',
- defaultMessage: 'Sync Settings',
- },
- syncPreviews: {
- id: 'screens.MediaSyncSettings.syncPreviews',
- defaultMessage: 'Sync Previews (Photos Only)',
- },
- syncPreviewsDescription: {
- id: 'screens.MediaSyncSettings.syncPreviewsDescription',
- defaultMessage:
- 'Photos will sync at a reduced smaller size. Device will not sync audio or video.',
- },
- syncEverything: {
- id: 'screens.MediaSyncSettings.syncEverything',
- defaultMessage: 'Sync Everything',
- },
- syncEverythingDescription: {
- id: 'screens.MediaSyncSettings.syncEverythingDescription',
- defaultMessage:
- 'Your device will sync all content at full size, including photos, audio, and videos.',
- },
- syncEverythingWarning: {
- id: 'screens.MediaSyncSettings.syncEverythingWarning',
- defaultMessage: 'Note: This will use more storage.',
- },
- syncPreviewsBottomSheet: {
- id: 'screens.MediaSyncSettings.syncPreviewsButtonBottomSheet',
- defaultMessage: 'Sync Previews?',
- },
- syncEverythingBottomSheet: {
- id: 'screens.MediaSyncSettings.syncEverythingButtonBottomSheet',
- defaultMessage: 'Sync Everything?',
- },
- syncPreviewsDescriptionBottomSheet: {
- id: 'screens.MediaSyncSettings.syncPreviewsDescriptionBottomSheet',
- defaultMessage:
- 'Your device will keep all existing data but new observations will sync in a smaller, preview size.',
- },
- syncPreviewWarningBottomSheet: {
- id: 'screens.MediaSyncSettings.syncPreviewWarningBottomSheet',
- defaultMessage: 'You will no longer sync Audio or Video.',
- },
- syncEverythingDescriptionBottomSheet: {
- id: 'screens.MediaSyncSettings.syncEverythingDescriptionBottomSheet',
- defaultMessage:
- 'You are about to sync everything. This may increase the disk space used on your device.',
- },
- syncPreviewsBottomSheetConfirm: {
- id: 'screens.MediaSyncSettings.syncPreviewsBottomSheetConfirm',
- defaultMessage: 'Sync Previews',
- },
-});
-
-export const MediaSyncSettings = () => {
- const {formatMessage: t} = useIntl();
- const {data: mediaSyncSetting} = useGetMediaSyncSetting();
- const {
- mutate: setMediaSyncSetting,
- variables,
- isPending,
- } = useSetMediaSyncSetting();
- const [possibleSetting, setPossibleSetting] =
- React.useState(null);
-
- const {isOpen, openSheet, closeSheet, sheetRef} = useBottomSheetModal({
- openOnMount: false,
- });
-
- const handleOptionChange = (value: MediaSyncSetting) => {
- setPossibleSetting(value);
- openSheet();
- };
-
- const handleConfirm = () => {
- if (possibleSetting) {
- setMediaSyncSetting(possibleSetting);
- }
- closeSheet();
- };
-
- const handleDismiss = () => {
- setPossibleSetting(null);
- closeSheet();
- };
-
- const options: {
- value: MediaSyncSetting;
- label: string;
- hint: React.ReactNode;
- }[] = [
- {
- value: 'previews',
- label: t(m.syncPreviews),
- hint: t(m.syncPreviewsDescription),
- },
- {
- value: 'everything',
- label: t(m.syncEverything),
- hint: (
- <>
- {t(m.syncEverythingDescription)}
- {'\n\n'}
- {t(m.syncEverythingWarning)}
- >
- ),
- },
- ];
-
- return (
-
-
-
-
- {t(m.syncPreviewsDescriptionBottomSheet)}
- {'\n\n'}
- {t(m.syncPreviewWarningBottomSheet)}
- >
- ) : (
- t(m.syncEverythingDescriptionBottomSheet)
- )
- }
- confirmActionText={
- possibleSetting === 'previews'
- ? t(m.syncPreviewsBottomSheetConfirm)
- : t(m.syncEverything)
- }
- confirmAction={handleConfirm}
- onDismiss={handleDismiss}
- />
-
-
- );
-};
-
-MediaSyncSettings.navTitle = m.syncSettingsTitle;
-
-const styles = StyleSheet.create({
- container: {
- padding: 20,
- },
-});
diff --git a/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncEverythingBottomSheet.tsx b/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncEverythingBottomSheet.tsx
new file mode 100644
index 000000000..af99ff64f
--- /dev/null
+++ b/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncEverythingBottomSheet.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import {View, StyleSheet} from 'react-native';
+import {BottomSheetWrapper} from '../../../../sharedComponents/BottomSheetWrapper';
+import {defineMessages, useIntl} from 'react-intl';
+import Warning from '../../../../images/Warning.svg';
+import {Button} from '../../../../sharedComponents/Button';
+import {HeaderText} from '../../../../sharedComponents/Text/HeaderText';
+import {useNavigationFromRoot} from '../../../../hooks/useNavigationWithTypes';
+import {BodyText} from '../../../../sharedComponents/Text/BodyText';
+import {useSetMediaSyncSetting} from '../../../../hooks/server/mediaSync';
+
+const m = defineMessages({
+ cancel: {
+ id: 'screens.SyncEverythingBottomSheet.cancel',
+ defaultMessage: 'Cancel',
+ },
+ confirm: {
+ id: 'screens.SyncEverythingBottomSheet.confirm',
+ defaultMessage: 'Sync Everything',
+ },
+ syncEverything: {
+ id: 'screens.SyncEverythingBottomSheet.syncEverything',
+ defaultMessage: 'Sync Everything?',
+ },
+ syncEverythingDescription: {
+ id: 'screens.SyncEverythingBottomSheet.syncEverythingDescription',
+ defaultMessage:
+ 'You are about to sync everything. This may increase the disk space used on your device.',
+ },
+});
+
+export const SyncEverythingBottomSheet = () => {
+ const {formatMessage} = useIntl();
+ const {goBack} = useNavigationFromRoot();
+ const {mutate: setMediaSyncSetting} = useSetMediaSyncSetting();
+ return (
+
+
+
+
+ {formatMessage(m.syncEverything)}
+
+
+ {formatMessage(m.syncEverythingDescription)}
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ },
+ bodyText: {
+ marginTop: 10,
+ textAlign: 'center',
+ },
+});
diff --git a/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncPreviewsBottomSheet.tsx b/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncPreviewsBottomSheet.tsx
new file mode 100644
index 000000000..5fad50bb6
--- /dev/null
+++ b/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/SyncPreviewsBottomSheet.tsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import {View, StyleSheet} from 'react-native';
+import {BottomSheetWrapper} from '../../../../sharedComponents/BottomSheetWrapper';
+import {defineMessages, useIntl} from 'react-intl';
+import Warning from '../../../../images/Warning.svg';
+import {Button} from '../../../../sharedComponents/Button';
+import {HeaderText} from '../../../../sharedComponents/Text/HeaderText';
+import {useNavigationFromRoot} from '../../../../hooks/useNavigationWithTypes';
+import {BodyText} from '../../../../sharedComponents/Text/BodyText';
+import {useSetMediaSyncSetting} from '../../../../hooks/server/mediaSync';
+
+const m = defineMessages({
+ syncPreviewsBottomSheet: {
+ id: 'screens.SyncPreviewBottomSheet.syncPreviewsButtonBottomSheet',
+ defaultMessage: 'Sync Previews?',
+ },
+ syncPreviewsDescriptionBottomSheet: {
+ id: 'screens.SyncPreviewBottomSheet.syncPreviewsDescriptionBottomSheet',
+ defaultMessage:
+ 'Your device will keep all existing data but new observations will sync in a smaller, preview size.',
+ },
+ syncPreviewWarningBottomSheet: {
+ id: 'screens.SyncPreviewBottomSheet.syncPreviewWarningBottomSheet',
+ defaultMessage: 'You will no longer sync Audio or Video.',
+ },
+ cancel: {
+ id: 'screens.SyncPreviewBottomSheet.cancel',
+ defaultMessage: 'Cancel',
+ },
+ confirm: {
+ id: 'screens.SyncPreviewBottomSheet.confirm',
+ defaultMessage: 'Sync Previews',
+ },
+});
+
+export const SyncPreviewsBottomSheet = () => {
+ const {formatMessage} = useIntl();
+ const {goBack} = useNavigationFromRoot();
+ const {mutate: setMediaSyncSetting} = useSetMediaSyncSetting();
+ return (
+
+
+
+
+ {formatMessage(m.syncPreviewsBottomSheet)}
+
+
+ {formatMessage(m.syncPreviewsDescriptionBottomSheet)}
+
+
+ {formatMessage(m.syncPreviewWarningBottomSheet)}
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ },
+ bodyText: {
+ marginTop: 10,
+ textAlign: 'center',
+ },
+});
diff --git a/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/index.tsx b/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/index.tsx
new file mode 100644
index 000000000..a824a8403
--- /dev/null
+++ b/src/frontend/screens/Settings/ProjectSettings/MediaSyncSettings/index.tsx
@@ -0,0 +1,107 @@
+import * as React from 'react';
+import {ScrollView, StyleSheet} from 'react-native';
+import {useIntl, defineMessages} from 'react-intl';
+import {SelectOne} from '../../../../sharedComponents/SelectOne';
+import {SYNC_BACKGROUND} from '../../../../lib/styles';
+import {MediaSyncSetting} from '../../../../sharedTypes';
+import {
+ UPDATE_MEDIA_SETTING,
+ useGetMediaSyncSetting,
+} from '../../../../hooks/server/mediaSync';
+import {NativeNavigationComponent} from '../../../../sharedTypes/navigation';
+import {useMutationState} from '@tanstack/react-query';
+
+const m = defineMessages({
+ syncSettingsTitle: {
+ id: 'screens.MediaSyncSettings.title',
+ defaultMessage: 'Sync Settings',
+ },
+ syncPreviews: {
+ id: 'screens.MediaSyncSettings.syncPreviews',
+ defaultMessage: 'Sync Previews (Photos Only)',
+ },
+ syncPreviewsDescription: {
+ id: 'screens.MediaSyncSettings.syncPreviewsDescription',
+ defaultMessage:
+ 'Photos will sync at a reduced smaller size. Device will not sync audio or video.',
+ },
+ syncEverything: {
+ id: 'screens.MediaSyncSettings.syncEverything',
+ defaultMessage: 'Sync Everything',
+ },
+ syncEverythingDescription: {
+ id: 'screens.MediaSyncSettings.syncEverythingDescription',
+ defaultMessage:
+ 'Your device will sync all content at full size, including photos, audio, and videos.',
+ },
+ syncEverythingWarning: {
+ id: 'screens.MediaSyncSettings.syncEverythingWarning',
+ defaultMessage: 'Note: This will use more storage.',
+ },
+});
+
+export const MediaSyncSettings: NativeNavigationComponent<
+ 'MediaSyncSettings'
+> = ({navigation}) => {
+ const {formatMessage: t} = useIntl();
+ const {data: mediaSyncSetting} = useGetMediaSyncSetting();
+
+ const optimisticSyncSetting = useMutationState({
+ filters: {mutationKey: [UPDATE_MEDIA_SETTING], status: 'pending'},
+ select: mutation => mutation.state.variables as MediaSyncSetting,
+ })[0];
+
+ const handleOptionChange = (value: MediaSyncSetting) => {
+ if (value === 'previews') {
+ navigation.navigate('SyncPreviewsBottomSheet');
+ return;
+ }
+ if (value === 'everything') {
+ navigation.navigate('SyncEverythingBottomSheet');
+ return;
+ }
+ };
+
+ const options: {
+ value: MediaSyncSetting;
+ label: string;
+ hint: React.ReactNode;
+ }[] = [
+ {
+ value: 'previews',
+ label: t(m.syncPreviews),
+ hint: t(m.syncPreviewsDescription),
+ },
+ {
+ value: 'everything',
+ label: t(m.syncEverything),
+ hint: (
+ <>
+ {t(m.syncEverythingDescription)}
+ {'\n\n'}
+ {t(m.syncEverythingWarning)}
+ >
+ ),
+ },
+ ];
+
+ return (
+
+
+
+ );
+};
+
+MediaSyncSettings.navTitle = m.syncSettingsTitle;
+
+const styles = StyleSheet.create({
+ container: {
+ padding: 20,
+ },
+});
diff --git a/src/frontend/sharedComponents/BottomSheetWrapper.tsx b/src/frontend/sharedComponents/BottomSheetWrapper.tsx
new file mode 100644
index 000000000..b0ce05f2b
--- /dev/null
+++ b/src/frontend/sharedComponents/BottomSheetWrapper.tsx
@@ -0,0 +1,59 @@
+import * as React from 'react';
+import {View} from 'react-native';
+import Animated, {SlideInDown, SlideOutDown} from 'react-native-reanimated';
+import {WHITE} from '../lib/styles';
+import {useNavigation} from '@react-navigation/native';
+import {usePreventAndroidBackButton} from '../hooks/usePreventAndroidBackButton';
+
+/**
+ *
+ * @description A wrapper component that should be used for bottom sheets. It will handle the animation and prevent the back button from closing the bottom sheet.
+ *
+ * When pushing a bottom sheet ontop of another bottom sheet use `navigation.replace`, to close the original bottom sheet first.
+ */
+export const BottomSheetWrapper = ({children}: {children: React.ReactNode}) => {
+ const navigation = useNavigation();
+
+ const [displayContent, setDisplayContent] = React.useState(true);
+
+ usePreventAndroidBackButton();
+
+ // This effect is used to prevent the bottom sheet from being removed before the animation is complete
+ React.useEffect(() => {
+ const unsubscribe = navigation.addListener('beforeRemove', e => {
+ e.preventDefault();
+ setDisplayContent(false);
+ setTimeout(() => {
+ navigation.dispatch(e.data.action);
+ }, 140);
+ });
+
+ return () => {
+ unsubscribe();
+ };
+ }, [navigation]);
+
+ return (
+
+ {displayContent && (
+
+ {children}
+
+ )}
+
+ );
+};
diff --git a/src/frontend/sharedTypes/navigation.ts b/src/frontend/sharedTypes/navigation.ts
index 862c506e7..6f629ae1e 100644
--- a/src/frontend/sharedTypes/navigation.ts
+++ b/src/frontend/sharedTypes/navigation.ts
@@ -101,6 +101,8 @@ export type RootStackParamsList = {
Audio: {isEditing: boolean; uri?: string; isSavedUri?: boolean};
MapManagement: undefined;
BackgroundMaps: undefined;
+ SyncPreviewsBottomSheet: undefined;
+ SyncEverythingBottomSheet: undefined;
};
export type OnboardingParamsList = {