diff --git a/native/media/image-modal.react.js b/native/media/image-modal.react.js --- a/native/media/image-modal.react.js +++ b/native/media/image-modal.react.js @@ -20,7 +20,6 @@ import Animated from 'react-native-reanimated'; import { type MediaInfo, type Dimensions } from 'lib/types/media-types'; -import { useIsReportEnabled } from 'lib/utils/report-utils'; import SWMansionIcon from '../components/swmansion-icon.react'; import ConnectedStatusBar from '../connected-status-bar.react'; @@ -49,7 +48,10 @@ runTiming, } from '../utils/animation-utils'; import Multimedia from './multimedia.react'; -import { intentionalSaveMedia } from './save-media'; +import { + useIntentionalSaveMedia, + type IntentionalSaveMedia, +} from './save-media'; /* eslint-disable import/no-named-as-default-member */ const { @@ -162,9 +164,9 @@ ...BaseProps, // Redux state +dimensions: DerivedDimensionsInfo, + +intentionalSaveMedia: IntentionalSaveMedia, // withOverlayContext +overlayContext: ?OverlayContextType, - +mediaReportsEnabled: boolean, }; type State = { +closeButtonEnabled: boolean, @@ -1138,9 +1140,7 @@ const { id: uploadID, uri } = mediaInfo; const { id: messageServerID, localID: messageLocalID } = item.messageInfo; const ids = { uploadID, messageServerID, messageLocalID }; - return intentionalSaveMedia(uri, ids, { - mediaReportsEnabled: this.props.mediaReportsEnabled, - }); + return this.props.intentionalSaveMedia(uri, ids); }; copy = () => { @@ -1265,13 +1265,13 @@ function ConnectedImageModal(props: BaseProps) { const dimensions = useSelector(derivedDimensionsInfoSelector); const overlayContext = React.useContext(OverlayContext); - const mediaReportsEnabled = useIsReportEnabled('mediaReports'); + const intentionalSaveMedia = useIntentionalSaveMedia(); return ( ); }, diff --git a/native/media/save-media.js b/native/media/save-media.js --- a/native/media/save-media.js +++ b/native/media/save-media.js @@ -2,8 +2,10 @@ import * as MediaLibrary from 'expo-media-library'; import invariant from 'invariant'; +import * as React from 'react'; import { Platform, PermissionsAndroid } from 'react-native'; import filesystem from 'react-native-fs'; +import { useDispatch } from 'react-redux'; import { queueReportsActionType } from 'lib/actions/report-actions'; import { readableFilename, pathFromURI } from 'lib/media/file-utils'; @@ -20,9 +22,9 @@ import { getConfig } from 'lib/utils/config'; import { getMessageForException } from 'lib/utils/errors'; import { promiseAll } from 'lib/utils/promises'; +import { useIsReportEnabled } from 'lib/utils/report-utils'; import { displayActionResultModal } from '../navigation/action-result-modal'; -import { dispatch } from '../redux/redux-setup'; import { requestAndroidPermission } from '../utils/android-permissions'; import { fetchBlob } from './blob-utils'; import { @@ -37,72 +39,85 @@ } from './file-utils'; import { getMediaLibraryIdentifier } from './identifier-utils'; -async function intentionalSaveMedia( +export type IntentionalSaveMedia = ( uri: string, ids: { uploadID: string, messageServerID: ?string, messageLocalID: ?string, }, - options: { - mediaReportsEnabled: boolean, - }, -): Promise { - const start = Date.now(); - const steps = [{ step: 'save_media', uri, time: start }]; - - const { resultPromise, reportPromise } = saveMedia(uri, 'request'); - const result = await resultPromise; - const userTime = Date.now() - start; - - let message; - if (result.success) { - message = 'saved!'; - } else if (result.reason === 'save_unsupported') { - const os = Platform.select({ - ios: 'iOS', - android: 'Android', - default: Platform.OS, - }); - message = `saving media is unsupported on ${os}`; - } else if (result.reason === 'missing_permission') { - message = 'don’t have permission :('; - } else if ( - result.reason === 'resolve_failed' || - result.reason === 'data_uri_failed' - ) { - message = 'failed to resolve :('; - } else if (result.reason === 'fetch_failed') { - message = 'failed to download :('; - } else { - message = 'failed to save :('; - } - displayActionResultModal(message); +) => Promise; + +function useIntentionalSaveMedia(): IntentionalSaveMedia { + const dispatch = useDispatch(); + const mediaReportsEnabled = useIsReportEnabled('mediaReports'); + return React.useCallback( + async ( + uri: string, + ids: { + uploadID: string, + messageServerID: ?string, + messageLocalID: ?string, + }, + ) => { + const start = Date.now(); + const steps = [{ step: 'save_media', uri, time: start }]; + + const { resultPromise, reportPromise } = saveMedia(uri, 'request'); + const result = await resultPromise; + const userTime = Date.now() - start; + + let message; + if (result.success) { + message = 'saved!'; + } else if (result.reason === 'save_unsupported') { + const os = Platform.select({ + ios: 'iOS', + android: 'Android', + default: Platform.OS, + }); + message = `saving media is unsupported on ${os}`; + } else if (result.reason === 'missing_permission') { + message = 'don’t have permission :('; + } else if ( + result.reason === 'resolve_failed' || + result.reason === 'data_uri_failed' + ) { + message = 'failed to resolve :('; + } else if (result.reason === 'fetch_failed') { + message = 'failed to download :('; + } else { + message = 'failed to save :('; + } + displayActionResultModal(message); - if (!options.mediaReportsEnabled) { - return; - } - const reportSteps = await reportPromise; - steps.push(...reportSteps); - const totalTime = Date.now() - start; - const mediaMission = { steps, result, userTime, totalTime }; - - const { uploadID, messageServerID, messageLocalID } = ids; - const uploadIDIsLocal = isLocalUploadID(uploadID); - const report: MediaMissionReportCreationRequest = { - type: reportTypes.MEDIA_MISSION, - time: Date.now(), - platformDetails: getConfig().platformDetails, - mediaMission, - uploadServerID: uploadIDIsLocal ? undefined : uploadID, - uploadLocalID: uploadIDIsLocal ? uploadID : undefined, - messageServerID, - messageLocalID, - }; - dispatch({ - type: queueReportsActionType, - payload: { reports: [report] }, - }); + if (!mediaReportsEnabled) { + return; + } + const reportSteps = await reportPromise; + steps.push(...reportSteps); + const totalTime = Date.now() - start; + const mediaMission = { steps, result, userTime, totalTime }; + + const { uploadID, messageServerID, messageLocalID } = ids; + const uploadIDIsLocal = isLocalUploadID(uploadID); + const report: MediaMissionReportCreationRequest = { + type: reportTypes.MEDIA_MISSION, + time: Date.now(), + platformDetails: getConfig().platformDetails, + mediaMission, + uploadServerID: uploadIDIsLocal ? undefined : uploadID, + uploadLocalID: uploadIDIsLocal ? uploadID : undefined, + messageServerID, + messageLocalID, + }; + dispatch({ + type: queueReportsActionType, + payload: { reports: [report] }, + }); + }, + [dispatch, mediaReportsEnabled], + ); } type Permissions = 'check' | 'request'; @@ -451,4 +466,4 @@ }; } -export { intentionalSaveMedia, saveMedia }; +export { useIntentionalSaveMedia, saveMedia };