Fix handling for new picker version, improve size validation

This commit is contained in:
Eric Bailey
2025-08-17 18:26:42 -05:00
parent d59f37014f
commit f5160d0848
+34 -27
View File
@@ -13,7 +13,7 @@ import {
usePhotoLibraryPermission, usePhotoLibraryPermission,
useVideoLibraryPermission, useVideoLibraryPermission,
} from '#/lib/hooks/usePermissions' } from '#/lib/hooks/usePermissions'
import {extractDataUriMime, getDataUriSize} from '#/lib/media/util' import {extractDataUriMime} from '#/lib/media/util'
import {mimeToExt} from '#/lib/media/video/util' import {mimeToExt} from '#/lib/media/video/util'
import {logger} from '#/logger' import {logger} from '#/logger'
import {isIOS, isNative, isWeb} from '#/platform/detection' import {isIOS, isNative, isWeb} from '#/platform/detection'
@@ -316,31 +316,6 @@ async function processImagePickerAssets(
let supportedAssets: ValidatedImagePickerAsset[] = [] let supportedAssets: ValidatedImagePickerAsset[] = []
for (const asset of assets) { for (const asset of assets) {
/*
* Some browsers won't even load massive files e.g. Arc
*/
if (!asset.uri) {
errors.add(SelectedAssetError.FileTooBig)
continue
}
/*
* If the file _did_ load, great, we can just check the size here.
*/
if (asset.file && asset.file.size > VIDEO_MAX_SIZE) {
errors.add(SelectedAssetError.FileTooBig)
continue
}
/*
* In other cases e.g. Safari, we don't even get a `file`, so we want to
* approximate the size and fail early if we can.
*/
if (getDataUriSize(asset.uri) > VIDEO_MAX_SIZE) {
errors.add(SelectedAssetError.FileTooBig)
continue
}
const {success, type, mimeType} = classifyImagePickerAsset(asset) const {success, type, mimeType} = classifyImagePickerAsset(asset)
if (!success) { if (!success) {
@@ -370,6 +345,16 @@ async function processImagePickerAssets(
errors.add(SelectedAssetError.Unsupported) errors.add(SelectedAssetError.Unsupported)
continue continue
} }
/*
* Filesize appears to be stable across all platforms, so we can use it
* to filter out large files on web. On native, we compress these anyway,
* so we only check on web.
*/
if (isWeb && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) {
errors.add(SelectedAssetError.FileTooBig)
continue
}
} }
if (type === 'image') { if (type === 'image') {
@@ -379,12 +364,33 @@ async function processImagePickerAssets(
} }
} }
if (type === 'gif') {
/*
* Filesize appears to be stable across all platforms, so we can use it
* to filter out large files on web. On native, we compress GIFs as
* videos anyway, so we only check on web.
*/
if (isWeb && asset.fileSize && asset.fileSize > VIDEO_MAX_SIZE) {
errors.add(SelectedAssetError.FileTooBig)
continue
}
}
/* /*
* All validations passed, we have an asset! * All validations passed, we have an asset!
*/ */
supportedAssets.push({ supportedAssets.push({
mimeType, mimeType,
...asset, ...asset,
/*
* In `expo-image-picker` >= v17, `uri` is now a `blob:` URL, not a
* data-uri. Our handling elsewhere in the app (for web) relies on the
* base64 data-uri, so we construct it here for web only.
*/
uri:
isWeb && asset.base64
? `data:${mimeType};base64,${asset.base64}`
: asset.uri,
}) })
} }
@@ -514,7 +520,7 @@ export function SelectMediaButton({
msg`You can only select one GIF at a time.`, msg`You can only select one GIF at a time.`,
), ),
[SelectedAssetError.FileTooBig]: _( [SelectedAssetError.FileTooBig]: _(
msg`This file is too large. Maximum size is 100mb.`, msg`One or more of your selected files is too large. Maximum size is 100MB.`,
), ),
}[error] }[error]
}) })
@@ -558,6 +564,7 @@ export function SelectMediaButton({
quality: 1, quality: 1,
allowsMultipleSelection: true, allowsMultipleSelection: true,
legacy: true, legacy: true,
base64: isWeb,
selectionLimit: isIOS ? selectionCountRemaining : undefined, selectionLimit: isIOS ? selectionCountRemaining : undefined,
preferredAssetRepresentationMode: preferredAssetRepresentationMode:
UIImagePickerPreferredAssetRepresentationMode.Current, UIImagePickerPreferredAssetRepresentationMode.Current,