From 6feb771b2b33c67aedc0eb60f5e2e11fe3a4307e Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 2 Apr 2025 09:18:17 +0200 Subject: [PATCH 1/3] create context that holds the full screen loader --- src/App.tsx | 2 + src/components/FullScreenLoaderContext.tsx | 51 ++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/components/FullScreenLoaderContext.tsx diff --git a/src/App.tsx b/src/App.tsx index 3e6fc9ac2a27..789cac513431 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,6 +12,7 @@ import CustomStatusBarAndBackground from './components/CustomStatusBarAndBackgro import CustomStatusBarAndBackgroundContextProvider from './components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContextProvider'; import ErrorBoundary from './components/ErrorBoundary'; import FullScreenBlockingViewContextProvider from './components/FullScreenBlockingViewContextProvider'; +import FullScreenLoaderContextProvider from './components/FullScreenLoaderContext'; import HTMLEngineProvider from './components/HTMLEngineProvider'; import InitialURLContextProvider from './components/InitialURLContextProvider'; import {InputBlurContextProvider} from './components/InputBlurContext'; @@ -111,6 +112,7 @@ function App({url, hybridAppSettings, timestamp}: AppProps) { ProductTrainingContextProvider, InputBlurContextProvider, FullScreenBlockingViewContextProvider, + FullScreenLoaderContextProvider, ]} > diff --git a/src/components/FullScreenLoaderContext.tsx b/src/components/FullScreenLoaderContext.tsx new file mode 100644 index 000000000000..0ddd9fc9f64e --- /dev/null +++ b/src/components/FullScreenLoaderContext.tsx @@ -0,0 +1,51 @@ +import React, {createContext, useContext, useMemo, useState} from 'react'; +import type {ReactNode} from 'react'; +import FullScreenLoadingIndicator from './FullscreenLoadingIndicator'; + +type FullScreenLoaderContextType = { + isLoaderVisible: boolean; + setIsLoaderVisible: React.Dispatch>; +}; + +const FullScreenLoaderContext = createContext({ + isLoaderVisible: false, + setIsLoaderVisible: () => {}, +}); + +type FullScreenLoaderContextProviderProps = { + children: ReactNode; +}; + +function FullScreenLoaderContextProvider({children}: FullScreenLoaderContextProviderProps) { + const [isLoaderVisible, setIsLoaderVisible] = useState(false); + + const loaderContext = useMemo( + () => ({ + isLoaderVisible, + setIsLoaderVisible, + }), + [isLoaderVisible], + ); + + return ( + + {children} + {isLoaderVisible && } + + ); +} + +function useFullScreenLoader() { + const context = useContext(FullScreenLoaderContext); + + if (!context) { + throw new Error('useFullScreenLoader must be used within a FullScreenLoaderContextProvider'); + } + + return context; +} + +FullScreenLoaderContextProvider.displayName = 'FullScreenLoaderContextProvider'; + +export default FullScreenLoaderContextProvider; +export {FullScreenLoaderContext, useFullScreenLoader}; From 16ff62a411ef2d66184d0f2ff8eb1a9b0d87eb4c Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 2 Apr 2025 09:32:15 +0200 Subject: [PATCH 2/3] use fullscreen context in IOURequestStepScan --- .../AttachmentPicker/index.native.tsx | 4 +++- src/components/AttachmentPicker/types.ts | 3 +++ .../step/IOURequestStepScan/index.native.tsx | 20 +++++++++---------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/components/AttachmentPicker/index.native.tsx b/src/components/AttachmentPicker/index.native.tsx index 70966a05b918..af06a21ddd9c 100644 --- a/src/components/AttachmentPicker/index.native.tsx +++ b/src/components/AttachmentPicker/index.native.tsx @@ -116,6 +116,7 @@ function AttachmentPicker({ shouldValidateImage = true, shouldHideGalleryOption = false, fileLimit = 1, + onOpenPicker, }: AttachmentPickerProps) { const styles = useThemeStyles(); const [isVisible, setIsVisible] = useState(false); @@ -388,6 +389,7 @@ function AttachmentPicker({ */ const selectItem = useCallback( (item: Item) => { + onOpenPicker?.(); /* setTimeout delays execution to the frame after the modal closes * without this on iOS closing the modal closes the gallery/camera as well */ onModalHide.current = () => { @@ -400,7 +402,7 @@ function AttachmentPicker({ }; close(); }, - [pickAttachment], + [pickAttachment, onOpenPicker], ); useKeyboardShortcut( diff --git a/src/components/AttachmentPicker/types.ts b/src/components/AttachmentPicker/types.ts index 1e2e65761527..1958a94ac883 100644 --- a/src/components/AttachmentPicker/types.ts +++ b/src/components/AttachmentPicker/types.ts @@ -55,6 +55,9 @@ type AttachmentPickerProps = { /** Whether to allow multiple files to be selected. */ fileLimit?: number; + + /** A callback that will be called when the picker is opened. */ + onOpenPicker?: () => void; }; export default AttachmentPickerProps; diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 8778c9e56cdd..67798e08c1be 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -16,7 +16,7 @@ import Shutter from '@assets/images/shutter.svg'; import type {FileObject} from '@components/AttachmentModal'; import AttachmentPicker from '@components/AttachmentPicker'; import Button from '@components/Button'; -import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import {useFullScreenLoader} from '@components/FullScreenLoaderContext'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import ImageSVG from '@components/ImageSVG'; @@ -81,6 +81,7 @@ function IOURequestStepScan({ }: IOURequestStepScanProps) { const theme = useTheme(); const styles = useThemeStyles(); + const {isLoaderVisible, setIsLoaderVisible} = useFullScreenLoader(); const device = useCameraDevice('back', { physicalDevices: ['wide-angle-camera', 'ultra-wide-angle-camera'], }); @@ -105,7 +106,6 @@ function IOURequestStepScan({ const isPlatformMuted = mutedPlatforms[platform]; const [cameraPermissionStatus, setCameraPermissionStatus] = useState(null); const [didCapturePhoto, setDidCapturePhoto] = useState(false); - const [isLoadingReceipt, setIsLoadingReceipt] = useState(false); const isTabActive = useIsFocused(); const [pdfFile, setPdfFile] = useState(null); @@ -203,8 +203,12 @@ function IOURequestStepScan({ return () => { subscription.remove(); + + if (isLoaderVisible) { + setIsLoaderVisible(false); + } }; - }, []), + }, [isLoaderVisible, setIsLoaderVisible]), ); const validateReceipt = (file: FileObject) => { @@ -551,13 +555,7 @@ function IOURequestStepScan({ return; } - // With the image size > 24MB, we use manipulateAsync to resize the image. - // It takes a long time so we should display a loading indicator while the resize image progresses. - if (Str.isImage(originalFile.name ?? '') && (originalFile?.size ?? 0) > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) { - setIsLoadingReceipt(true); - } resizeImageIfNeeded(originalFile).then((file) => { - setIsLoadingReceipt(false); // Store the receipt on the transaction object in Onyx // On Android devices, fetching blob for a file with name containing spaces fails to retrieve the type of file. // So, let us also save the file type in receipt for later use during blob fetch @@ -702,7 +700,6 @@ function IOURequestStepScan({ setElementTop(e.nativeEvent.layout.height - (variables.tabSelectorButtonHeight + variables.tabSelectorButtonPadding) * 2); }} > - {isLoadingReceipt && } {!!pdfFile && ( - + setIsLoaderVisible(true)}> {({openPicker}) => ( { openPicker({ onPicked: (data) => setReceiptAndNavigate(data.at(0) ?? {}), + onCanceled: () => setIsLoaderVisible(false), }); }} > From 25181b5bf92ea514e9dd8f4445726d7659aa20f9 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Fri, 4 Apr 2025 10:39:40 +0200 Subject: [PATCH 3/3] add docs to types --- Mobile-Expensify | 2 +- src/components/FullScreenLoaderContext.tsx | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index a3e374271b4f..1add5d3d745d 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit a3e374271b4ffea3e038075ffe64e341b0772bc2 +Subproject commit 1add5d3d745d6b9132a155b096033bcb4f5c036d diff --git a/src/components/FullScreenLoaderContext.tsx b/src/components/FullScreenLoaderContext.tsx index 0ddd9fc9f64e..f06773992407 100644 --- a/src/components/FullScreenLoaderContext.tsx +++ b/src/components/FullScreenLoaderContext.tsx @@ -3,7 +3,13 @@ import type {ReactNode} from 'react'; import FullScreenLoadingIndicator from './FullscreenLoadingIndicator'; type FullScreenLoaderContextType = { + /** + * Whether the full screen loader is visible. + */ isLoaderVisible: boolean; + /** + * Set the full screen loader visibility. + */ setIsLoaderVisible: React.Dispatch>; }; @@ -13,6 +19,9 @@ const FullScreenLoaderContext = createContext({ }); type FullScreenLoaderContextProviderProps = { + /** + * The children of the full screen loader context provider. + */ children: ReactNode; };