mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Fixed #108
This commit is contained in:
@ -1,17 +1,20 @@
|
||||
import analytics from '@components/analytics'
|
||||
import { ActionSheetOptions } from '@expo/react-native-action-sheet'
|
||||
import * as ImageManipulator from 'expo-image-manipulator'
|
||||
import * as ImagePicker from 'expo-image-picker'
|
||||
import {
|
||||
ImageInfo,
|
||||
UIImagePickerPresentationStyle
|
||||
} from 'expo-image-picker/build/ImagePicker.types'
|
||||
import { store } from '@root/store'
|
||||
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
|
||||
import * as ExpoImagePicker from 'expo-image-picker'
|
||||
import i18next from 'i18next'
|
||||
import { Alert, Linking, Platform } from 'react-native'
|
||||
import { Alert, Linking } from 'react-native'
|
||||
import ImagePicker, {
|
||||
Image,
|
||||
ImageOrVideo
|
||||
} from 'react-native-image-crop-picker'
|
||||
|
||||
export interface Props {
|
||||
mediaTypes?: ImagePicker.MediaTypeOptions
|
||||
resize?: { width?: number; height?: number } // Resize mode contain
|
||||
mediaType?: 'photo' | 'video'
|
||||
resize?: { width?: number; height?: number }
|
||||
maximum?: number
|
||||
indicateMaximum?: boolean
|
||||
showActionSheetWithOptions: (
|
||||
options: ActionSheetOptions,
|
||||
callback: (i?: number | undefined) => void | Promise<void>
|
||||
@ -19,134 +22,157 @@ export interface Props {
|
||||
}
|
||||
|
||||
const mediaSelector = async ({
|
||||
mediaTypes = ImagePicker.MediaTypeOptions.All,
|
||||
mediaType,
|
||||
resize,
|
||||
maximum,
|
||||
indicateMaximum = false,
|
||||
showActionSheetWithOptions
|
||||
}: Props): Promise<ImageInfo> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const resolveResult = async (result: ImageInfo) => {
|
||||
if (resize && result.type === 'image') {
|
||||
let newResult: ImageManipulator.ImageResult
|
||||
if (resize.width && resize.height) {
|
||||
if (resize.width / resize.height > result.width / result.height) {
|
||||
newResult = await ImageManipulator.manipulateAsync(result.uri, [
|
||||
{ resize: { width: resize.width } }
|
||||
])
|
||||
} else {
|
||||
newResult = await ImageManipulator.manipulateAsync(result.uri, [
|
||||
{ resize: { height: resize.height } }
|
||||
])
|
||||
}: Props): Promise<ImageOrVideo[]> => {
|
||||
const checkLibraryPermission = async (): Promise<boolean> => {
|
||||
const { status } =
|
||||
await ExpoImagePicker.requestMediaLibraryPermissionsAsync()
|
||||
if (status !== 'granted') {
|
||||
Alert.alert(
|
||||
i18next.t('componentMediaSelector:library.alert.title'),
|
||||
i18next.t('componentMediaSelector:library.alert.message'),
|
||||
[
|
||||
{
|
||||
text: i18next.t('common:buttons.cancel'),
|
||||
style: 'cancel',
|
||||
onPress: () =>
|
||||
analytics('mediaSelector_nopermission', {
|
||||
action: 'cancel'
|
||||
})
|
||||
},
|
||||
{
|
||||
text: i18next.t(
|
||||
'componentMediaSelector:library.alert.buttons.settings'
|
||||
),
|
||||
style: 'default',
|
||||
onPress: () => {
|
||||
analytics('mediaSelector_nopermission', {
|
||||
action: 'settings'
|
||||
})
|
||||
Linking.openURL('app-settings:')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newResult = await ImageManipulator.manipulateAsync(result.uri, [
|
||||
{ resize }
|
||||
])
|
||||
}
|
||||
resolve({ ...newResult, cancelled: false })
|
||||
]
|
||||
)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const _maximum =
|
||||
maximum ||
|
||||
getInstanceConfigurationStatusMaxAttachments(store.getState()) ||
|
||||
4
|
||||
|
||||
const options = () => {
|
||||
switch (mediaType) {
|
||||
case 'photo':
|
||||
return [
|
||||
i18next.t(
|
||||
'componentMediaSelector:options.image',
|
||||
indicateMaximum ? { context: 'max', max: _maximum } : undefined
|
||||
),
|
||||
i18next.t('common:buttons.cancel')
|
||||
]
|
||||
case 'video':
|
||||
return [
|
||||
i18next.t(
|
||||
'componentMediaSelector:options.video',
|
||||
indicateMaximum ? { context: 'max', max: 1 } : undefined
|
||||
),
|
||||
i18next.t('common:buttons.cancel')
|
||||
]
|
||||
default:
|
||||
return [
|
||||
i18next.t(
|
||||
'componentMediaSelector:options.image',
|
||||
indicateMaximum ? { context: 'max', max: _maximum } : undefined
|
||||
),
|
||||
i18next.t(
|
||||
'componentMediaSelector:options.video',
|
||||
indicateMaximum ? { context: 'max', max: 1 } : undefined
|
||||
),
|
||||
i18next.t('common:buttons.cancel')
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const selectImage = async () => {
|
||||
const images = await ImagePicker.openPicker({
|
||||
mediaType: 'photo',
|
||||
includeExif: false,
|
||||
multiple: true,
|
||||
minFiles: 1,
|
||||
maxFiles: _maximum
|
||||
}).catch(() => {})
|
||||
|
||||
if (!images) {
|
||||
return reject()
|
||||
}
|
||||
|
||||
if (!resize) {
|
||||
return resolve(images)
|
||||
} else {
|
||||
resolve(result)
|
||||
const croppedImages: Image[] = []
|
||||
for (const image of images) {
|
||||
const croppedImage = await ImagePicker.openCropper({
|
||||
mediaType: 'photo',
|
||||
path: image.path,
|
||||
width: resize.width,
|
||||
height: resize.height
|
||||
}).catch(() => {})
|
||||
croppedImage && croppedImages.push(croppedImage)
|
||||
}
|
||||
return resolve(croppedImages)
|
||||
}
|
||||
}
|
||||
const selectVideo = async () => {
|
||||
const video = await ImagePicker.openPicker({
|
||||
mediaType: 'video',
|
||||
includeExif: false
|
||||
}).catch(() => {})
|
||||
|
||||
if (video) {
|
||||
return resolve([video])
|
||||
} else {
|
||||
return reject()
|
||||
}
|
||||
}
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: i18next.t('componentMediaSelector:title'),
|
||||
options: [
|
||||
i18next.t('componentMediaSelector:options.library'),
|
||||
i18next.t('componentMediaSelector:options.photo'),
|
||||
i18next.t('componentMediaSelector:options.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2
|
||||
options: options(),
|
||||
cancelButtonIndex: mediaType ? 1 : 2
|
||||
},
|
||||
async buttonIndex => {
|
||||
if (buttonIndex === 0) {
|
||||
const { status } =
|
||||
await ImagePicker.requestMediaLibraryPermissionsAsync()
|
||||
if (status !== 'granted') {
|
||||
Alert.alert(
|
||||
i18next.t('componentMediaSelector:library.alert.title'),
|
||||
i18next.t('componentMediaSelector:library.alert.message'),
|
||||
[
|
||||
{
|
||||
text: i18next.t(
|
||||
'componentMediaSelector:library.alert.buttons.cancel'
|
||||
),
|
||||
style: 'cancel',
|
||||
onPress: () =>
|
||||
analytics('mediaSelector_nopermission', {
|
||||
action: 'cancel'
|
||||
})
|
||||
},
|
||||
{
|
||||
text: i18next.t(
|
||||
'componentMediaSelector:library.alert.buttons.settings'
|
||||
),
|
||||
style: 'default',
|
||||
onPress: () => {
|
||||
analytics('mediaSelector_nopermission', {
|
||||
action: 'settings'
|
||||
})
|
||||
Linking.openURL('app-settings:')
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
} else {
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes,
|
||||
exif: false,
|
||||
presentationStyle:
|
||||
Platform.OS === 'ios' && parseInt(Platform.Version) < 13
|
||||
? UIImagePickerPresentationStyle.FULL_SCREEN
|
||||
: UIImagePickerPresentationStyle.AUTOMATIC
|
||||
})
|
||||
if (!(await checkLibraryPermission())) {
|
||||
return reject()
|
||||
}
|
||||
|
||||
if (!result.cancelled) {
|
||||
await resolveResult(result)
|
||||
switch (mediaType) {
|
||||
case 'photo':
|
||||
if (buttonIndex === 0) {
|
||||
await selectImage()
|
||||
}
|
||||
}
|
||||
} else if (buttonIndex === 1) {
|
||||
const { status } = await ImagePicker.requestCameraPermissionsAsync()
|
||||
if (status !== 'granted') {
|
||||
Alert.alert(
|
||||
i18next.t('componentMediaSelector:photo.alert.title'),
|
||||
i18next.t('componentMediaSelector:photo.alert.message'),
|
||||
[
|
||||
{
|
||||
text: i18next.t(
|
||||
'componentMediaSelector:photo.alert.buttons.cancel'
|
||||
),
|
||||
style: 'cancel',
|
||||
onPress: () => {
|
||||
analytics('compose_addattachment_camera_nopermission', {
|
||||
action: 'cancel'
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
text: i18next.t(
|
||||
'componentMediaSelector:photo.alert.buttons.settings'
|
||||
),
|
||||
style: 'default',
|
||||
onPress: () => {
|
||||
analytics('compose_addattachment_camera_nopermission', {
|
||||
action: 'settings'
|
||||
})
|
||||
Linking.openURL('app-settings:')
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
} else {
|
||||
const result = await ImagePicker.launchCameraAsync({
|
||||
mediaTypes,
|
||||
exif: false
|
||||
})
|
||||
|
||||
if (!result.cancelled) {
|
||||
await resolveResult(result)
|
||||
break
|
||||
case 'video':
|
||||
if (buttonIndex === 0) {
|
||||
await selectVideo()
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
if (buttonIndex === 0) {
|
||||
await selectImage()
|
||||
} else if (buttonIndex === 1) {
|
||||
await selectVideo()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
|
Reference in New Issue
Block a user