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

143 lines
3.5 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-08-07 01:18:10 +02:00
import { Asset } from 'react-native-image-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-08-07 01:18:10 +02:00
media: Required<Pick<Asset, 'uri' | 'type' | 'fileName'>>
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-08-07 01:18:10 +02:00
switch (media.type.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-08-07 01:18:10 +02:00
local: { ...media, 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-08-07 01:18:10 +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: {
2022-08-07 01:18:10 +02:00
local: { ...media, thumbnail: uri, hash, width, height },
2022-05-02 22:31:22 +02:00
uploading: true
}
2020-12-30 00:56:25 +01:00
})
2022-08-07 01:18:10 +02:00
})
2022-05-02 22:31:22 +02:00
.catch(() =>
composeDispatch({
type: 'attachment/upload/start',
payload: {
2022-08-07 01:18:10 +02:00
local: { ...media, hash },
2022-05-02 22:31:22 +02:00
uploading: true
}
})
)
break
default:
composeDispatch({
type: 'attachment/upload/start',
payload: {
2022-08-07 01:18:10 +02:00
local: { ...media, 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,
2022-08-07 01:18:10 +02:00
name: media.fileName,
type: media.type
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) {
2022-08-07 01:18:10 +02:00
const requiredMedia = media as Required<Asset>
uploadAttachment({ composeDispatch, media: requiredMedia })
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