diff options
Diffstat (limited to 'src/view/com/composer')
-rw-r--r-- | src/view/com/composer/Composer.tsx | 49 | ||||
-rw-r--r-- | src/view/com/composer/state.ts | 75 |
2 files changed, 103 insertions, 21 deletions
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 185a57fc3..59aae2951 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -82,11 +82,12 @@ import {useProfileQuery} from '#/state/queries/profile' import {Gif} from '#/state/queries/tenor' import {ThreadgateAllowUISetting} from '#/state/queries/threadgate' import {threadgateViewToAllowUISetting} from '#/state/queries/threadgate/util' +import {NO_VIDEO, NoVideoState} from '#/state/queries/video/video' import { - createVideoState, processVideo, - State as VideoUploadState, - videoReducer, + VideoAction, + VideoState, + VideoState as VideoUploadState, } from '#/state/queries/video/video' import {useAgent, useSession} from '#/state/session' import {useComposerControls} from '#/state/shell/composer' @@ -192,24 +193,38 @@ export const ComposePost = ({ const [videoAltText, setVideoAltText] = useState('') const [captions, setCaptions] = useState<{lang: string; file: File}[]>([]) - const [videoUploadState, videoDispatch] = useReducer( - videoReducer, - undefined, - createVideoState, + // TODO: Move more state here. + const [composerState, dispatch] = useReducer( + composerReducer, + {initImageUris}, + createComposerState, + ) + + let videoUploadState: VideoState | NoVideoState = NO_VIDEO + if (composerState.embed.media?.type === 'video') { + videoUploadState = composerState.embed.media.video + } + const videoDispatch = useCallback( + (videoAction: VideoAction) => { + dispatch({type: 'embed_update_video', videoAction}) + }, + [dispatch], ) const selectVideo = React.useCallback( (asset: ImagePickerAsset) => { + const abortController = new AbortController() + dispatch({type: 'embed_add_video', asset, abortController}) processVideo( asset, videoDispatch, agent, currentDid, - videoUploadState.abortController.signal, + abortController.signal, _, ) }, - [_, videoUploadState.abortController, videoDispatch, agent, currentDid], + [_, videoDispatch, agent, currentDid], ) // Whenever we receive an initial video uri, we should immediately run compression if necessary @@ -221,8 +236,8 @@ export const ComposePost = ({ const clearVideo = React.useCallback(() => { videoUploadState.abortController.abort() - videoDispatch({type: 'to_idle', nextController: new AbortController()}) - }, [videoUploadState.abortController, videoDispatch]) + dispatch({type: 'embed_remove_video'}) + }, [videoUploadState.abortController, dispatch]) const updateVideoDimensions = useCallback( (width: number, height: number) => { @@ -233,7 +248,7 @@ export const ComposePost = ({ signal: videoUploadState.abortController.signal, }) }, - [videoUploadState.abortController], + [videoUploadState.abortController, videoDispatch], ) const hasVideo = Boolean(videoUploadState.asset || videoUploadState.video) @@ -249,12 +264,6 @@ export const ComposePost = ({ ) const [postgate, setPostgate] = useState(createPostgateRecord({post: ''})) - // TODO: Move more state here. - const [composerState, dispatch] = useReducer( - composerReducer, - {initImageUris}, - createComposerState, - ) let images = NO_IMAGES if (composerState.embed.media?.type === 'images') { images = composerState.embed.media.images @@ -857,7 +866,7 @@ export const ComposePost = ({ /> <SelectVideoBtn onSelectVideo={selectVideo} - disabled={!canSelectImages} + disabled={!canSelectImages || images?.length > 0} setError={setError} /> <OpenCameraBtn disabled={!canSelectImages} onAdd={onImageAdd} /> @@ -1117,7 +1126,7 @@ function ErrorBanner({ clearVideo, }: { error: string - videoUploadState: VideoUploadState + videoUploadState: VideoUploadState | NoVideoState clearError: () => void clearVideo: () => void }) { diff --git a/src/view/com/composer/state.ts b/src/view/com/composer/state.ts index 5588de1aa..8e974ad7a 100644 --- a/src/view/com/composer/state.ts +++ b/src/view/com/composer/state.ts @@ -1,4 +1,12 @@ +import {ImagePickerAsset} from 'expo-image-picker' + import {ComposerImage, createInitialImages} from '#/state/gallery' +import { + createVideoState, + VideoAction, + videoReducer, + VideoState, +} from '#/state/queries/video/video' import {ComposerOpts} from '#/state/shell/composer' type PostRecord = { @@ -11,11 +19,16 @@ type ImagesMedia = { labels: string[] } +type VideoMedia = { + type: 'video' + video: VideoState +} + type ComposerEmbed = { // TODO: Other record types. record: PostRecord | undefined // TODO: Other media types. - media: ImagesMedia | undefined + media: ImagesMedia | VideoMedia | undefined } export type ComposerState = { @@ -27,6 +40,13 @@ export type ComposerAction = | {type: 'embed_add_images'; images: ComposerImage[]} | {type: 'embed_update_image'; image: ComposerImage} | {type: 'embed_remove_image'; image: ComposerImage} + | { + type: 'embed_add_video' + asset: ImagePickerAsset + abortController: AbortController + } + | {type: 'embed_remove_video'} + | {type: 'embed_update_video'; videoAction: VideoAction} const MAX_IMAGES = 4 @@ -36,6 +56,9 @@ export function composerReducer( ): ComposerState { switch (action.type) { case 'embed_add_images': { + if (action.images.length === 0) { + return state + } const prevMedia = state.embed.media let nextMedia = prevMedia if (!prevMedia) { @@ -104,6 +127,55 @@ export function composerReducer( } return state } + case 'embed_add_video': { + const prevMedia = state.embed.media + let nextMedia = prevMedia + if (!prevMedia) { + nextMedia = { + type: 'video', + video: createVideoState(action.asset, action.abortController), + } + } + return { + ...state, + embed: { + ...state.embed, + media: nextMedia, + }, + } + } + case 'embed_update_video': { + const videoAction = action.videoAction + const prevMedia = state.embed.media + let nextMedia = prevMedia + if (prevMedia?.type === 'video') { + nextMedia = { + ...prevMedia, + video: videoReducer(prevMedia.video, videoAction), + } + } + return { + ...state, + embed: { + ...state.embed, + media: nextMedia, + }, + } + } + case 'embed_remove_video': { + const prevMedia = state.embed.media + let nextMedia = prevMedia + if (prevMedia?.type === 'video') { + nextMedia = undefined + } + return { + ...state, + embed: { + ...state.embed, + media: nextMedia, + }, + } + } default: return state } @@ -122,6 +194,7 @@ export function createComposerState({ labels: [], } } + // TODO: initial video. return { embed: { record: undefined, |