Cleanup, comments

(cherry picked from commit 6c9c98648e37257285a9c8caeb1eadcc56c81402)
This commit is contained in:
Eric Bailey
2025-08-12 18:06:22 -05:00
committed by Samuel Newman
parent 81c0456794
commit 82018c1a1e
+45 -18
View File
@@ -21,7 +21,7 @@ import {getVideoMetadata} from '#/view/com/composer/videos/pickVideo'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button} from '#/components/Button' import {Button} from '#/components/Button'
import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper' import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper'
import {Image_Stroke2_Corner0_Rounded as Image} from '#/components/icons/Image' import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image'
import {toast} from '#/components/Toast' import {toast} from '#/components/Toast'
export type Props = { export type Props = {
@@ -30,22 +30,28 @@ export type Props = {
setError: (error: string) => void setError: (error: string) => void
selectedAssetsCount: number selectedAssetsCount: number
onSelectAssets: (props: { onSelectAssets: (props: {
type: SelectedAsset['type'] type: AssetType
assets: ImagePickerAsset[] assets: ImagePickerAsset[]
errors: string[] errors: string[]
}) => void }) => void
} }
export type SelectedAsset = { /**
asset: ImagePickerAsset * Generic asset classes, or buckets, that we support.
type: 'video' | 'image' | 'gif' */
} type AssetType = 'video' | 'image' | 'gif'
export type ValidatedImagePickerAsset = Omit<ImagePickerAsset, 'mimeType'> & { /**
* Shadows `ImagePickerAsset` from `expo-image-picker`, but with a guaranteed `mimeType`
*/
type ValidatedImagePickerAsset = Omit<ImagePickerAsset, 'mimeType'> & {
mimeType: string mimeType: string
} }
export enum SelectedAssetError { /**
* Codes for known validation states
*/
enum SelectedAssetError {
Unsupported = 'Unsupported', Unsupported = 'Unsupported',
MixedTypes = 'MixedTypes', MixedTypes = 'MixedTypes',
MaxImages = 'MaxImages', MaxImages = 'MaxImages',
@@ -55,20 +61,27 @@ export enum SelectedAssetError {
NoGifsOnNative = 'NoGifsOnNative', NoGifsOnNative = 'NoGifsOnNative',
} }
/**
* Supported video mime types. This differs slightly from
* `SUPPORTED_MIME_TYPES` from `#/lib/constants` because we only care about
* videos here.
*/
const SUPPORTED_VIDEO_MIME_TYPES = [ const SUPPORTED_VIDEO_MIME_TYPES = [
'video/mp4', 'video/mp4',
'video/mpeg', 'video/mpeg',
'video/webm', 'video/webm',
'video/quicktime', 'video/quicktime',
] as const ] as const
export type SupportedVideoMimeType = (typeof SUPPORTED_VIDEO_MIME_TYPES)[number] type SupportedVideoMimeType = (typeof SUPPORTED_VIDEO_MIME_TYPES)[number]
function isSupportedVideoMimeType( function isSupportedVideoMimeType(
mimeType: string, mimeType: string,
): mimeType is SupportedVideoMimeType { ): mimeType is SupportedVideoMimeType {
return SUPPORTED_VIDEO_MIME_TYPES.includes(mimeType as SupportedVideoMimeType) return SUPPORTED_VIDEO_MIME_TYPES.includes(mimeType as SupportedVideoMimeType)
} }
/**
* Supported image mime types.
*/
const SUPPORTED_IMAGE_MIME_TYPES = ( const SUPPORTED_IMAGE_MIME_TYPES = (
[ [
'image/gif', 'image/gif',
@@ -79,17 +92,19 @@ const SUPPORTED_IMAGE_MIME_TYPES = (
isIOS && 'image/heic', isIOS && 'image/heic',
] as const ] as const
).filter(Boolean) ).filter(Boolean)
export type SupportedImageMimeType = Exclude< type SupportedImageMimeType = Exclude<
(typeof SUPPORTED_IMAGE_MIME_TYPES)[number], (typeof SUPPORTED_IMAGE_MIME_TYPES)[number],
boolean boolean
> >
function isSupportedImageMimeType( function isSupportedImageMimeType(
mimeType: string, mimeType: string,
): mimeType is SupportedImageMimeType { ): mimeType is SupportedImageMimeType {
return SUPPORTED_IMAGE_MIME_TYPES.includes(mimeType as SupportedImageMimeType) return SUPPORTED_IMAGE_MIME_TYPES.includes(mimeType as SupportedImageMimeType)
} }
/**
* This is a last-ditch effort type thing here, try not to rely on this.
*/
const extensionToMimeType: Record< const extensionToMimeType: Record<
string, string,
SupportedVideoMimeType | SupportedImageMimeType SupportedVideoMimeType | SupportedImageMimeType
@@ -97,6 +112,7 @@ const extensionToMimeType: Record<
mp4: 'video/mp4', mp4: 'video/mp4',
mov: 'video/quicktime', mov: 'video/quicktime',
webm: 'video/webm', webm: 'video/webm',
webp: 'image/webp',
gif: 'image/gif', gif: 'image/gif',
jpg: 'image/jpeg', jpg: 'image/jpeg',
jpeg: 'image/jpeg', jpeg: 'image/jpeg',
@@ -105,10 +121,15 @@ const extensionToMimeType: Record<
heic: 'image/heic', heic: 'image/heic',
} }
/**
* Attemps to bucket the given asset into one of our known types based on its
* `mimeType`. If `mimeType` is not available, we try to infer it through
* various means.
*/
function classifyImagePickerAsset(asset: ImagePickerAsset): function classifyImagePickerAsset(asset: ImagePickerAsset):
| { | {
success: true success: true
type: SelectedAsset['type'] type: AssetType
mimeType: string mimeType: string
} }
| { | {
@@ -153,7 +174,7 @@ function classifyImagePickerAsset(asset: ImagePickerAsset):
/* /*
* Distill this down into a type "class". * Distill this down into a type "class".
*/ */
let type: SelectedAsset['type'] | undefined let type: AssetType | undefined
if (mimeType === 'image/gif') { if (mimeType === 'image/gif') {
type = 'gif' type = 'gif'
} else if (mimeType?.startsWith('video/')) { } else if (mimeType?.startsWith('video/')) {
@@ -187,8 +208,9 @@ function classifyImagePickerAsset(asset: ImagePickerAsset):
} }
/* /*
* On web, certain file formats (like `.mov`) don't give us a duration or * WEB ONLY. On web, certain file formats (like `.mov`) don't give us a
* dimensions, so we need to load the file manually to extract this. * duration or dimensions, so we need to load the file manually to extract
* this.
*/ */
async function getAdditionalVideoMetadata(asset: ValidatedImagePickerAsset) { async function getAdditionalVideoMetadata(asset: ValidatedImagePickerAsset) {
if (isNative) return asset if (isNative) return asset
@@ -203,6 +225,11 @@ async function getAdditionalVideoMetadata(asset: ValidatedImagePickerAsset) {
return await getVideoMetadata(file) return await getVideoMetadata(file)
} }
/**
* Takes in raw assets from `expo-image-picker` and applies validation. Returns
* the dominant `AssetType`, any valid assets, and any errors encountered along
* the way.
*/
async function processImagePickerAssets( async function processImagePickerAssets(
assets: ImagePickerAsset[], assets: ImagePickerAsset[],
{ {
@@ -220,7 +247,7 @@ async function processImagePickerAssets(
* We only support selecting a single type of media at a time, so this * We only support selecting a single type of media at a time, so this
* gets set to whatever the first asset type is. * gets set to whatever the first asset type is.
*/ */
let primaryMediaType: SelectedAsset['type'] | undefined let primaryMediaType: AssetType | undefined
/* /*
* This will hold the assets that we can actually use, after filtering * This will hold the assets that we can actually use, after filtering
@@ -452,7 +479,7 @@ export function SelectMediaBtn({
shape="round" shape="round"
color="primary" color="primary"
disabled={disabled}> disabled={disabled}>
<Image <ImageIcon
size="lg" size="lg"
style={disabled && t.atoms.text_contrast_low} style={disabled && t.atoms.text_contrast_low}
accessibilityIgnoresInvertColors={true} accessibilityIgnoresInvertColors={true}