import {useCallback} from 'react' import {Keyboard} from 'react-native' import {ImagePickerAsset} from 'expo-image-picker' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {SUPPORTED_MIME_TYPES, SupportedMimeTypes} from '#/lib/constants' import {BSKY_SERVICE} from '#/lib/constants' import {useVideoLibraryPermission} from '#/lib/hooks/usePermissions' import {getHostnameFromUrl} from '#/lib/strings/url-helpers' import {isWeb} from '#/platform/detection' import {isNative} from '#/platform/detection' import {useSession} from '#/state/session' import {atoms as a, useTheme} from '#/alf' import {Button} from '#/components/Button' import {useDialogControl} from '#/components/Dialog' import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog' import {VideoClip_Stroke2_Corner0_Rounded as VideoClipIcon} from '#/components/icons/VideoClip' import * as Prompt from '#/components/Prompt' import {pickVideo} from './pickVideo' const VIDEO_MAX_DURATION = 60 * 1000 // 60s in milliseconds type Props = { onSelectVideo: (video: ImagePickerAsset) => void disabled?: boolean setError: (error: string) => void } export function SelectVideoBtn({onSelectVideo, disabled, setError}: Props) { const {_} = useLingui() const t = useTheme() const {requestVideoAccessIfNeeded} = useVideoLibraryPermission() const control = Prompt.usePromptControl() const {currentAccount} = useSession() const onPressSelectVideo = useCallback(async () => { if (isNative && !(await requestVideoAccessIfNeeded())) { return } if ( currentAccount && !currentAccount.emailConfirmed && getHostnameFromUrl(currentAccount.service) === getHostnameFromUrl(BSKY_SERVICE) ) { Keyboard.dismiss() control.open() } else { const response = await pickVideo() if (response.assets && response.assets.length > 0) { const asset = response.assets[0] try { if (isWeb) { // asset.duration is null for gifs (see the TODO in pickVideo.web.ts) if (asset.duration && asset.duration > VIDEO_MAX_DURATION) { throw Error(_(msg`Videos must be less than 60 seconds long`)) } // compression step on native converts to mp4, so no need to check there if ( !SUPPORTED_MIME_TYPES.includes( asset.mimeType as SupportedMimeTypes, ) ) { throw Error(_(msg`Unsupported video type: ${asset.mimeType}`)) } } else { if (typeof asset.duration !== 'number') { throw Error('Asset is not a video') } if (asset.duration > VIDEO_MAX_DURATION) { throw Error(_(msg`Videos must be less than 60 seconds long`)) } } onSelectVideo(asset) } catch (err) { if (err instanceof Error) { setError(err.message) } else { setError(_(msg`An error occurred while selecting the video`)) } } } } }, [ requestVideoAccessIfNeeded, currentAccount, control, setError, _, onSelectVideo, ]) return ( <> ) } function VerifyEmailPrompt({control}: {control: Prompt.PromptControlProps}) { const {_} = useLingui() const verifyEmailDialogControl = useDialogControl() return ( <> { verifyEmailDialogControl.open() }} /> ) }