about summary refs log tree commit diff
path: root/src/state
diff options
context:
space:
mode:
Diffstat (limited to 'src/state')
-rw-r--r--src/state/queries/video/compress-video.ts17
-rw-r--r--src/state/queries/video/video-upload.ts8
-rw-r--r--src/state/queries/video/video-upload.web.ts8
-rw-r--r--src/state/queries/video/video.ts65
4 files changed, 62 insertions, 36 deletions
diff --git a/src/state/queries/video/compress-video.ts b/src/state/queries/video/compress-video.ts
index a2c739cfd..a4c17eace 100644
--- a/src/state/queries/video/compress-video.ts
+++ b/src/state/queries/video/compress-video.ts
@@ -1,23 +1,30 @@
 import {ImagePickerAsset} from 'expo-image-picker'
 import {useMutation} from '@tanstack/react-query'
 
+import {cancelable} from '#/lib/async/cancelable'
 import {CompressedVideo, compressVideo} from 'lib/media/video/compress'
 
 export function useCompressVideoMutation({
   onProgress,
   onSuccess,
   onError,
+  signal,
 }: {
   onProgress: (progress: number) => void
   onError: (e: any) => void
   onSuccess: (video: CompressedVideo) => void
+  signal: AbortSignal
 }) {
   return useMutation({
-    mutationFn: async (asset: ImagePickerAsset) => {
-      return await compressVideo(asset.uri, {
-        onProgress: num => onProgress(trunc2dp(num)),
-      })
-    },
+    mutationKey: ['video', 'compress'],
+    mutationFn: cancelable(
+      (asset: ImagePickerAsset) =>
+        compressVideo(asset.uri, {
+          onProgress: num => onProgress(trunc2dp(num)),
+          signal,
+        }),
+      signal,
+    ),
     onError,
     onSuccess,
     onMutate: () => {
diff --git a/src/state/queries/video/video-upload.ts b/src/state/queries/video/video-upload.ts
index d806249c9..a41d4dd1e 100644
--- a/src/state/queries/video/video-upload.ts
+++ b/src/state/queries/video/video-upload.ts
@@ -3,6 +3,7 @@ import {AppBskyVideoDefs} from '@atproto/api'
 import {useMutation} from '@tanstack/react-query'
 import {nanoid} from 'nanoid/non-secure'
 
+import {cancelable} from '#/lib/async/cancelable'
 import {CompressedVideo} from '#/lib/media/video/compress'
 import {createVideoEndpointUrl} from '#/state/queries/video/util'
 import {useAgent, useSession} from '#/state/session'
@@ -11,16 +12,19 @@ export const useUploadVideoMutation = ({
   onSuccess,
   onError,
   setProgress,
+  signal,
 }: {
   onSuccess: (response: AppBskyVideoDefs.JobStatus) => void
   onError: (e: any) => void
   setProgress: (progress: number) => void
+  signal: AbortSignal
 }) => {
   const {currentAccount} = useSession()
   const agent = useAgent()
 
   return useMutation({
-    mutationFn: async (video: CompressedVideo) => {
+    mutationKey: ['video', 'upload'],
+    mutationFn: cancelable(async (video: CompressedVideo) => {
       const uri = createVideoEndpointUrl('/xrpc/app.bsky.video.uploadVideo', {
         did: currentAccount!.did,
         name: `${nanoid(12)}.mp4`, // @TODO what are we limiting this to?
@@ -59,7 +63,7 @@ export const useUploadVideoMutation = ({
 
       const responseBody = JSON.parse(res.body) as AppBskyVideoDefs.JobStatus
       return responseBody
-    },
+    }, signal),
     onError,
     onSuccess,
   })
diff --git a/src/state/queries/video/video-upload.web.ts b/src/state/queries/video/video-upload.web.ts
index 09d107423..85e07c4e1 100644
--- a/src/state/queries/video/video-upload.web.ts
+++ b/src/state/queries/video/video-upload.web.ts
@@ -2,6 +2,7 @@ import {AppBskyVideoDefs} from '@atproto/api'
 import {useMutation} from '@tanstack/react-query'
 import {nanoid} from 'nanoid/non-secure'
 
+import {cancelable} from '#/lib/async/cancelable'
 import {CompressedVideo} from '#/lib/media/video/compress'
 import {createVideoEndpointUrl} from '#/state/queries/video/util'
 import {useAgent, useSession} from '#/state/session'
@@ -10,16 +11,19 @@ export const useUploadVideoMutation = ({
   onSuccess,
   onError,
   setProgress,
+  signal,
 }: {
   onSuccess: (response: AppBskyVideoDefs.JobStatus) => void
   onError: (e: any) => void
   setProgress: (progress: number) => void
+  signal: AbortSignal
 }) => {
   const {currentAccount} = useSession()
   const agent = useAgent()
 
   return useMutation({
-    mutationFn: async (video: CompressedVideo) => {
+    mutationKey: ['video', 'upload'],
+    mutationFn: cancelable(async (video: CompressedVideo) => {
       const uri = createVideoEndpointUrl('/xrpc/app.bsky.video.uploadVideo', {
         did: currentAccount!.did,
         name: `${nanoid(12)}.mp4`, // @TODO: make sure it's always mp4'
@@ -70,7 +74,7 @@ export const useUploadVideoMutation = ({
       )
 
       return res
-    },
+    }, signal),
     onError,
     onSuccess,
   })
diff --git a/src/state/queries/video/video.ts b/src/state/queries/video/video.ts
index 64390801e..035dc5081 100644
--- a/src/state/queries/video/video.ts
+++ b/src/state/queries/video/video.ts
@@ -3,7 +3,7 @@ import {ImagePickerAsset} from 'expo-image-picker'
 import {AppBskyVideoDefs, BlobRef} from '@atproto/api'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import {useQuery} from '@tanstack/react-query'
+import {QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
 
 import {logger} from '#/logger'
 import {CompressedVideo} from 'lib/media/video/compress'
@@ -32,33 +32,41 @@ export interface State {
   jobStatus?: AppBskyVideoDefs.JobStatus
   blobRef?: BlobRef
   error?: string
+  abortController: AbortController
 }
 
-function reducer(state: State, action: Action): State {
-  let updatedState = state
-  if (action.type === 'SetStatus') {
-    updatedState = {...state, status: action.status}
-  } else if (action.type === 'SetProgress') {
-    updatedState = {...state, progress: action.progress}
-  } else if (action.type === 'SetError') {
-    updatedState = {...state, error: action.error}
-  } else if (action.type === 'Reset') {
-    updatedState = {
-      status: 'idle',
-      progress: 0,
-      video: null,
-      blobRef: undefined,
+function reducer(queryClient: QueryClient) {
+  return (state: State, action: Action): State => {
+    let updatedState = state
+    if (action.type === 'SetStatus') {
+      updatedState = {...state, status: action.status}
+    } else if (action.type === 'SetProgress') {
+      updatedState = {...state, progress: action.progress}
+    } else if (action.type === 'SetError') {
+      updatedState = {...state, error: action.error}
+    } else if (action.type === 'Reset') {
+      state.abortController.abort()
+      queryClient.cancelQueries({
+        queryKey: ['video'],
+      })
+      updatedState = {
+        status: 'idle',
+        progress: 0,
+        video: null,
+        blobRef: undefined,
+        abortController: new AbortController(),
+      }
+    } else if (action.type === 'SetAsset') {
+      updatedState = {...state, asset: action.asset}
+    } else if (action.type === 'SetVideo') {
+      updatedState = {...state, video: action.video}
+    } else if (action.type === 'SetJobStatus') {
+      updatedState = {...state, jobStatus: action.jobStatus}
+    } else if (action.type === 'SetBlobRef') {
+      updatedState = {...state, blobRef: action.blobRef}
     }
-  } else if (action.type === 'SetAsset') {
-    updatedState = {...state, asset: action.asset}
-  } else if (action.type === 'SetVideo') {
-    updatedState = {...state, video: action.video}
-  } else if (action.type === 'SetJobStatus') {
-    updatedState = {...state, jobStatus: action.jobStatus}
-  } else if (action.type === 'SetBlobRef') {
-    updatedState = {...state, blobRef: action.blobRef}
+    return updatedState
   }
-  return updatedState
 }
 
 export function useUploadVideo({
@@ -69,10 +77,12 @@ export function useUploadVideo({
   onSuccess: () => void
 }) {
   const {_} = useLingui()
-  const [state, dispatch] = React.useReducer(reducer, {
+  const queryClient = useQueryClient()
+  const [state, dispatch] = React.useReducer(reducer(queryClient), {
     status: 'idle',
     progress: 0,
     video: null,
+    abortController: new AbortController(),
   })
 
   const {setJobId} = useUploadStatusQuery({
@@ -116,6 +126,7 @@ export function useUploadVideo({
     setProgress: p => {
       dispatch({type: 'SetProgress', progress: p})
     },
+    signal: state.abortController.signal,
   })
 
   const {mutate: onSelectVideo} = useCompressVideoMutation({
@@ -148,6 +159,7 @@ export function useUploadVideo({
       })
       onVideoCompressed(video)
     },
+    signal: state.abortController.signal,
   })
 
   const selectVideo = (asset: ImagePickerAsset) => {
@@ -163,7 +175,6 @@ export function useUploadVideo({
   }
 
   const clearVideo = () => {
-    // @TODO cancel any running jobs
     dispatch({type: 'Reset'})
   }
 
@@ -187,7 +198,7 @@ const useUploadStatusQuery = ({
   const [jobId, setJobId] = React.useState<string>()
 
   const {isLoading, isError} = useQuery({
-    queryKey: ['video-upload', jobId],
+    queryKey: ['video', 'upload status', jobId],
     queryFn: async () => {
       if (!jobId) return // this won't happen, can ignore