tooot/src/screens/Compose/Root/Footer/addAttachment.ts

149 lines
3.7 KiB
TypeScript
Raw Normal View History

2021-01-04 14:55:34 +01:00
import * as Crypto from 'expo-crypto'
2020-12-30 00:56:25 +01:00
import * as VideoThumbnails from 'expo-video-thumbnails'
import { Dispatch } from 'react'
2021-05-09 21:59:03 +02:00
import { Alert } from 'react-native'
2021-01-19 01:13:45 +01:00
import { ComposeAction } from '../../utils/types'
2021-01-13 01:03:46 +01:00
import { ActionSheetOptions } from '@expo/react-native-action-sheet'
2021-01-19 01:13:45 +01:00
import i18next from 'i18next'
2021-02-20 19:12:44 +01:00
import apiInstance from '@api/instance'
2021-05-09 21:59:03 +02:00
import mediaSelector from '@components/mediaSelector'
2022-06-05 17:58:18 +02:00
import { ImageOrVideo } from 'react-native-image-crop-picker'
2020-12-30 00:56:25 +01:00
export interface Props {
composeDispatch: Dispatch<ComposeAction>
2021-01-14 00:43:35 +01:00
showActionSheetWithOptions: (
options: ActionSheetOptions,
2021-11-15 22:34:43 +01:00
callback: (i?: number | undefined) => void | Promise<void>
2021-01-14 00:43:35 +01:00
) => void
2020-12-30 00:56:25 +01:00
}
2022-05-02 22:31:22 +02:00
export const uploadAttachment = async ({
2021-01-14 00:43:35 +01:00
composeDispatch,
2022-06-05 17:58:18 +02:00
media
2022-05-02 22:31:22 +02:00
}: {
composeDispatch: Dispatch<ComposeAction>
2022-06-09 21:33:10 +02:00
media: { uri: string } & Pick<ImageOrVideo, 'mime' | 'width' | 'height'>
2022-05-02 22:31:22 +02:00
}) => {
const hash = await Crypto.digestStringAsync(
Crypto.CryptoDigestAlgorithm.SHA256,
2022-06-09 21:33:10 +02:00
media.uri + Math.random()
2022-05-02 22:31:22 +02:00
)
2020-12-30 00:56:25 +01:00
2022-06-05 17:58:18 +02:00
switch (media.mime.split('/')[0]) {
2022-05-02 22:31:22 +02:00
case 'image':
2021-01-19 01:13:45 +01:00
composeDispatch({
2022-05-02 22:31:22 +02:00
type: 'attachment/upload/start',
payload: {
2022-06-09 21:33:10 +02:00
local: { ...media, type: 'image', local_thumbnail: media.uri, hash },
2022-05-02 22:31:22 +02:00
uploading: true
}
2021-01-19 01:13:45 +01:00
})
2022-05-02 22:31:22 +02:00
break
case 'video':
2022-06-09 21:33:10 +02:00
VideoThumbnails.getThumbnailAsync(media.uri)
2022-05-02 22:31:22 +02:00
.then(({ uri, width, height }) =>
2020-12-30 00:56:25 +01:00
composeDispatch({
2022-05-02 22:31:22 +02:00
type: 'attachment/upload/start',
payload: {
local: {
2022-06-05 17:58:18 +02:00
...media,
type: 'video',
2022-05-02 22:31:22 +02:00
local_thumbnail: uri,
hash,
width,
height
},
uploading: true
}
2020-12-30 00:56:25 +01:00
})
2022-05-02 22:31:22 +02:00
)
.catch(() =>
composeDispatch({
type: 'attachment/upload/start',
payload: {
2022-06-05 17:58:18 +02:00
local: { ...media, type: 'video', hash },
2022-05-02 22:31:22 +02:00
uploading: true
}
})
)
break
default:
composeDispatch({
type: 'attachment/upload/start',
payload: {
2022-06-05 17:58:18 +02:00
local: { ...media, type: 'unknown', hash },
2022-05-02 22:31:22 +02:00
uploading: true
2020-12-30 00:56:25 +01:00
}
})
2022-05-02 22:31:22 +02:00
break
2020-12-30 00:56:25 +01:00
}
2022-06-08 21:36:18 +02:00
const uploadFailed = (message?: string) => {
2022-05-02 22:31:22 +02:00
composeDispatch({
type: 'attachment/upload/fail',
payload: hash
})
Alert.alert(
i18next.t(
'screenCompose:content.root.actions.attachment.failed.alert.title'
),
2022-06-08 21:36:18 +02:00
message,
2022-05-02 22:31:22 +02:00
[
{
text: i18next.t(
'screenCompose:content.root.actions.attachment.failed.alert.button'
),
onPress: () => {}
}
]
)
}
const formData = new FormData()
formData.append('file', {
2022-06-09 21:33:10 +02:00
uri: media.uri,
name: media.uri.match(new RegExp(/.*\/(.*)/))?.[1] || 'file.jpg',
type: media.mime
2022-06-05 17:58:18 +02:00
} as any)
2022-05-02 22:31:22 +02:00
return apiInstance<Mastodon.Attachment>({
method: 'post',
2022-06-05 17:58:18 +02:00
version: 'v2',
2022-05-02 22:31:22 +02:00
url: 'media',
body: formData
})
.then(res => {
if (res.body.id) {
composeDispatch({
type: 'attachment/upload/end',
2022-06-05 17:58:18 +02:00
payload: { remote: res.body, local: media }
2022-05-02 22:31:22 +02:00
})
} else {
uploadFailed()
}
})
2022-06-08 21:36:18 +02:00
.catch((err: any) => {
uploadFailed(
err?.message && typeof err?.message === 'string'
? err?.message.slice(0, 50)
: undefined
)
2022-05-02 22:31:22 +02:00
})
}
const chooseAndUploadAttachment = async ({
composeDispatch,
showActionSheetWithOptions
}: Props): Promise<any> => {
2022-06-05 17:58:18 +02:00
const result = await mediaSelector({
indicateMaximum: true,
showActionSheetWithOptions
})
for (const media of result) {
uploadAttachment({ composeDispatch, media })
2022-06-08 21:36:18 +02:00
await new Promise(res => setTimeout(res, 500))
2022-06-05 17:58:18 +02:00
}
2020-12-30 00:56:25 +01:00
}
2022-05-02 22:31:22 +02:00
export default chooseAndUploadAttachment