mirror of
https://github.com/tooot-app/app
synced 2025-04-02 12:50:32 +02:00
Using proper image transformation
This commit is contained in:
parent
bd5a0948cf
commit
b5a5ce01a3
@ -4,6 +4,8 @@ PODS:
|
||||
- DoubleConversion (1.1.6)
|
||||
- EASClient (0.2.1):
|
||||
- ExpoModulesCore
|
||||
- EXApplication (4.1.0):
|
||||
- ExpoModulesCore
|
||||
- EXAV (11.2.3):
|
||||
- ExpoModulesCore
|
||||
- React-runtimeexecutor
|
||||
@ -23,6 +25,8 @@ PODS:
|
||||
- EXFirebaseCore (5.0.0):
|
||||
- ExpoModulesCore
|
||||
- Firebase/Core (= 8.14.0)
|
||||
- EXFont (10.1.0):
|
||||
- ExpoModulesCore
|
||||
- EXImageLoader (3.2.0):
|
||||
- ExpoModulesCore
|
||||
- React-Core
|
||||
@ -37,8 +41,13 @@ PODS:
|
||||
- ExpoModulesCore
|
||||
- ExpoHaptics (11.2.0):
|
||||
- ExpoModulesCore
|
||||
- ExpoImageManipulator (10.3.1):
|
||||
- EXImageLoader
|
||||
- ExpoModulesCore
|
||||
- ExpoImagePicker (13.1.1):
|
||||
- ExpoModulesCore
|
||||
- ExpoKeepAwake (10.1.1):
|
||||
- ExpoModulesCore
|
||||
- ExpoLocalization (13.0.0):
|
||||
- ExpoModulesCore
|
||||
- ExpoModulesCore (0.9.2):
|
||||
@ -590,6 +599,7 @@ DEPENDENCIES:
|
||||
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- EASClient (from `../node_modules/expo-eas-client/ios`)
|
||||
- EXApplication (from `../node_modules/expo-application/ios`)
|
||||
- EXAV (from `../node_modules/expo-av/ios`)
|
||||
- EXConstants (from `../node_modules/expo-constants/ios`)
|
||||
- EXDevice (from `../node_modules/expo-device/ios`)
|
||||
@ -597,6 +607,7 @@ DEPENDENCIES:
|
||||
- EXFileSystem (from `../node_modules/expo-file-system/ios`)
|
||||
- EXFirebaseAnalytics (from `../node_modules/expo-firebase-analytics/ios`)
|
||||
- EXFirebaseCore (from `../node_modules/expo-firebase-core/ios`)
|
||||
- EXFont (from `../node_modules/expo-font/ios`)
|
||||
- EXImageLoader (from `../node_modules/expo-image-loader/ios`)
|
||||
- EXJSONUtils (from `../node_modules/expo-json-utils/ios`)
|
||||
- EXManifests (from `../node_modules/expo-manifests/ios`)
|
||||
@ -604,7 +615,9 @@ DEPENDENCIES:
|
||||
- Expo (from `../node_modules/expo/ios`)
|
||||
- ExpoCrypto (from `../node_modules/expo-crypto/ios`)
|
||||
- ExpoHaptics (from `../node_modules/expo-haptics/ios`)
|
||||
- ExpoImageManipulator (from `../node_modules/expo-image-manipulator/ios`)
|
||||
- ExpoImagePicker (from `../node_modules/expo-image-picker/ios`)
|
||||
- ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`)
|
||||
- ExpoLocalization (from `../node_modules/expo-localization/ios`)
|
||||
- ExpoModulesCore (from `../node_modules/expo-modules-core/ios`)
|
||||
- ExpoRandom (from `../node_modules/expo-random/ios`)
|
||||
@ -701,6 +714,8 @@ EXTERNAL SOURCES:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
|
||||
EASClient:
|
||||
:path: "../node_modules/expo-eas-client/ios"
|
||||
EXApplication:
|
||||
:path: "../node_modules/expo-application/ios"
|
||||
EXAV:
|
||||
:path: "../node_modules/expo-av/ios"
|
||||
EXConstants:
|
||||
@ -715,6 +730,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/expo-firebase-analytics/ios"
|
||||
EXFirebaseCore:
|
||||
:path: "../node_modules/expo-firebase-core/ios"
|
||||
EXFont:
|
||||
:path: "../node_modules/expo-font/ios"
|
||||
EXImageLoader:
|
||||
:path: "../node_modules/expo-image-loader/ios"
|
||||
EXJSONUtils:
|
||||
@ -729,8 +746,12 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/expo-crypto/ios"
|
||||
ExpoHaptics:
|
||||
:path: "../node_modules/expo-haptics/ios"
|
||||
ExpoImageManipulator:
|
||||
:path: "../node_modules/expo-image-manipulator/ios"
|
||||
ExpoImagePicker:
|
||||
:path: "../node_modules/expo-image-picker/ios"
|
||||
ExpoKeepAwake:
|
||||
:path: "../node_modules/expo-keep-awake/ios"
|
||||
ExpoLocalization:
|
||||
:path: "../node_modules/expo-localization/ios"
|
||||
ExpoModulesCore:
|
||||
@ -859,6 +880,7 @@ SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
EASClient: 93565f4d024559b75eac62bc7d50acaa354614f6
|
||||
EXApplication: d6562af1204162e0ac46d341a7d4e5dc720b33de
|
||||
EXAV: 88f61c5af8415715b7ee51f084c1020235b85c56
|
||||
EXConstants: fdbe52259365b6a6faaa5e99a3b82cfa6bc2eb61
|
||||
EXDevice: 0115b360059ccd32c1701744e374e3259ffbdd3c
|
||||
@ -866,6 +888,7 @@ SPEC CHECKSUMS:
|
||||
EXFileSystem: 2aa2d9289f84bca9532b9ccbd81504fa31eb1ded
|
||||
EXFirebaseAnalytics: aeefc63f92277313c3ee86da6a7ecf892f345ed1
|
||||
EXFirebaseCore: bdfa87df74fa1b74a6b38957561456aabad28a4f
|
||||
EXFont: 04235cc22e6fef86028feb67db452978dc6f240f
|
||||
EXImageLoader: b88e053d760f85a82405b1db2de4abf11978fc9f
|
||||
EXJSONUtils: 2a74b8f40f1523cc3f92af99c91aa78201737a77
|
||||
EXManifests: 0c6134b7b6f3236a93a778c3f44ba1cfb3f9fa3d
|
||||
@ -873,7 +896,9 @@ SPEC CHECKSUMS:
|
||||
Expo: b9fff0a1eac0f424fc68ea49b4347fb308e52e17
|
||||
ExpoCrypto: d0d0f3e20875dc450b4ec88f0fb608da5c2c6c17
|
||||
ExpoHaptics: ad58ec96a25e57579c14a47c7d71f0de0de8656a
|
||||
ExpoImageManipulator: b55580bbc7b10099c7707949903e7176a8542ee8
|
||||
ExpoImagePicker: d9d6b4f29db437fc7796f13cee5f133f5b4b5f7c
|
||||
ExpoKeepAwake: c0c494b442ecd8122974c13b93ccfb57bd408e88
|
||||
ExpoLocalization: 8f619bb6eec64575cd5220bfabbd7b4e2d6f33f8
|
||||
ExpoModulesCore: e4278a668e8c13c0269ed8b8a4200989deea2973
|
||||
ExpoRandom: 14df0976aa363a71a730ceb7655250f3047c0e42
|
||||
|
@ -56,6 +56,7 @@
|
||||
"expo-file-system": "14.0.0",
|
||||
"expo-firebase-analytics": "7.0.0",
|
||||
"expo-haptics": "11.2.0",
|
||||
"expo-image-manipulator": "^10.3.1",
|
||||
"expo-image-picker": "13.1.1",
|
||||
"expo-linking": "3.1.0",
|
||||
"expo-localization": "13.0.0",
|
||||
@ -153,4 +154,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -178,11 +178,11 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
||||
}
|
||||
|
||||
let text: string | undefined = undefined
|
||||
let media: { path: string; mime: string }[] = []
|
||||
let media: { uri: string; mime: string }[] = []
|
||||
|
||||
const typesImage = ['png', 'jpg', 'jpeg', 'gif']
|
||||
const typesVideo = ['mp4', 'm4v', 'mov', 'webm', 'mpeg']
|
||||
const filterMedia = ({ path, mime }: { path: string; mime: string }) => {
|
||||
const filterMedia = ({ uri, mime }: { uri: string; mime: string }) => {
|
||||
if (mime.startsWith('image/')) {
|
||||
if (!typesImage.includes(mime.split('/')[1])) {
|
||||
console.warn('Image type not supported:', mime.split('/')[1])
|
||||
@ -195,7 +195,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
||||
})
|
||||
return
|
||||
}
|
||||
media.push({ path, mime })
|
||||
media.push({ uri, mime })
|
||||
} else if (mime.startsWith('video/')) {
|
||||
if (!typesVideo.includes(mime.split('/')[1])) {
|
||||
console.warn('Video type not supported:', mime.split('/')[1])
|
||||
@ -208,17 +208,17 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
||||
})
|
||||
return
|
||||
}
|
||||
media.push({ path, mime })
|
||||
media.push({ uri, mime })
|
||||
} else {
|
||||
if (typesImage.includes(path.split('.').pop() || '')) {
|
||||
media.push({ path: path, mime: 'image/jpg' })
|
||||
if (typesImage.includes(uri.split('.').pop() || '')) {
|
||||
media.push({ uri, mime: 'image/jpg' })
|
||||
return
|
||||
}
|
||||
if (typesVideo.includes(path.split('.').pop() || '')) {
|
||||
media.push({ path: path, mime: 'video/mp4' })
|
||||
if (typesVideo.includes(uri.split('.').pop() || '')) {
|
||||
media.push({ uri, mime: 'video/mp4' })
|
||||
return
|
||||
}
|
||||
text = !text ? path : text.concat(text, `\n${path}`)
|
||||
text = !text ? uri : text.concat(text, `\n${uri}`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
||||
|
||||
for (const d of item.data) {
|
||||
if (typeof d !== 'string') {
|
||||
filterMedia({ path: d.data, mime: d.mimeType })
|
||||
filterMedia({ uri: d.data, mime: d.mimeType })
|
||||
}
|
||||
}
|
||||
break
|
||||
@ -245,7 +245,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
||||
tempData = item.data
|
||||
}
|
||||
for (const d of item.data) {
|
||||
filterMedia({ path: d, mime: item.mimeType })
|
||||
filterMedia({ uri: d, mime: item.mimeType })
|
||||
}
|
||||
break
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ import analytics from '@components/analytics'
|
||||
import { ActionSheetOptions } from '@expo/react-native-action-sheet'
|
||||
import { store } from '@root/store'
|
||||
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
|
||||
import { manipulateAsync, SaveFormat } from 'expo-image-manipulator'
|
||||
import * as ExpoImagePicker from 'expo-image-picker'
|
||||
import i18next from 'i18next'
|
||||
import { Alert, Linking } from 'react-native'
|
||||
import { Alert, Linking, Platform } from 'react-native'
|
||||
import ImagePicker, {
|
||||
Image,
|
||||
ImageOrVideo
|
||||
@ -27,7 +28,7 @@ const mediaSelector = async ({
|
||||
maximum,
|
||||
indicateMaximum = false,
|
||||
showActionSheetWithOptions
|
||||
}: Props): Promise<ImageOrVideo[]> => {
|
||||
}: Props): Promise<({ uri: string } & Omit<ImageOrVideo, 'path'>)[]> => {
|
||||
const checkLibraryPermission = async (): Promise<boolean> => {
|
||||
const { status } =
|
||||
await ExpoImagePicker.requestMediaLibraryPermissionsAsync()
|
||||
@ -110,17 +111,40 @@ const mediaSelector = async ({
|
||||
multiple: true,
|
||||
minFiles: 1,
|
||||
maxFiles: _maximum,
|
||||
loadingLabelText: '',
|
||||
compressImageMaxWidth: 4096,
|
||||
compressImageMaxHeight: 4096
|
||||
smartAlbums: ['UserLibrary'],
|
||||
writeTempFile: false,
|
||||
loadingLabelText: ''
|
||||
}).catch(() => {})
|
||||
|
||||
if (!images) {
|
||||
return reject()
|
||||
}
|
||||
|
||||
// react-native-image-crop-picker may return HEIC as JPG that causes upload failure
|
||||
if (Platform.OS === 'ios') {
|
||||
for (const [index, image] of images.entries()) {
|
||||
if (image.mime === 'image/heic') {
|
||||
const converted = await manipulateAsync(image.sourceURL!, [], {
|
||||
base64: false,
|
||||
compress: 0.8,
|
||||
format: SaveFormat.JPEG
|
||||
})
|
||||
images[index] = {
|
||||
...images[index],
|
||||
sourceURL: converted.uri,
|
||||
mime: 'image/jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!resize) {
|
||||
return resolve(images)
|
||||
return resolve(
|
||||
images.map(image => ({
|
||||
...image,
|
||||
uri: image.sourceURL || `file://${image.path}`
|
||||
}))
|
||||
)
|
||||
} else {
|
||||
const croppedImages: Image[] = []
|
||||
for (const image of images) {
|
||||
@ -135,7 +159,12 @@ const mediaSelector = async ({
|
||||
}).catch(() => {})
|
||||
croppedImage && croppedImages.push(croppedImage)
|
||||
}
|
||||
return resolve(croppedImages)
|
||||
return resolve(
|
||||
croppedImages.map(image => ({
|
||||
...image,
|
||||
uri: `file://${image.path}`
|
||||
}))
|
||||
)
|
||||
}
|
||||
}
|
||||
const selectVideo = async () => {
|
||||
@ -146,7 +175,9 @@ const mediaSelector = async ({
|
||||
}).catch(() => {})
|
||||
|
||||
if (video) {
|
||||
return resolve([video])
|
||||
return resolve([
|
||||
{ ...video, uri: video.sourceURL || `file://${video.path}` }
|
||||
])
|
||||
} else {
|
||||
return reject()
|
||||
}
|
||||
|
@ -128,8 +128,8 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
|
||||
height: imageDimensionis.height
|
||||
}}
|
||||
source={{
|
||||
uri: theAttachmentLocal?.path
|
||||
? `file://${theAttachmentLocal?.path}`
|
||||
uri: theAttachmentLocal?.uri
|
||||
? theAttachmentLocal.uri
|
||||
: theAttachmentRemote?.preview_url
|
||||
}}
|
||||
/>
|
||||
|
@ -34,7 +34,7 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
|
||||
video={
|
||||
video.local
|
||||
? ({
|
||||
url: `file://${video.local.path}`,
|
||||
url: video.local.uri,
|
||||
preview_url: video.local.local_thumbnail,
|
||||
blurhash: video.remote?.blurhash
|
||||
} as Mastodon.AttachmentVideo)
|
||||
|
@ -22,28 +22,25 @@ export const uploadAttachment = async ({
|
||||
media
|
||||
}: {
|
||||
composeDispatch: Dispatch<ComposeAction>
|
||||
media: Pick<ImageOrVideo, 'path' | 'mime' | 'width' | 'height'>
|
||||
media: { uri: string } & Pick<ImageOrVideo, 'mime' | 'width' | 'height'>
|
||||
}) => {
|
||||
const hash = await Crypto.digestStringAsync(
|
||||
Crypto.CryptoDigestAlgorithm.SHA256,
|
||||
media.path + Math.random()
|
||||
media.uri + Math.random()
|
||||
)
|
||||
let attachmentType: string
|
||||
|
||||
switch (media.mime.split('/')[0]) {
|
||||
case 'image':
|
||||
attachmentType = `image/${media.path.split('.')[1]}`
|
||||
composeDispatch({
|
||||
type: 'attachment/upload/start',
|
||||
payload: {
|
||||
local: { ...media, type: 'image', local_thumbnail: media.path, hash },
|
||||
local: { ...media, type: 'image', local_thumbnail: media.uri, hash },
|
||||
uploading: true
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'video':
|
||||
attachmentType = `video/${media.path.split('.')[1]}`
|
||||
VideoThumbnails.getThumbnailAsync(media.path)
|
||||
VideoThumbnails.getThumbnailAsync(media.uri)
|
||||
.then(({ uri, width, height }) =>
|
||||
composeDispatch({
|
||||
type: 'attachment/upload/start',
|
||||
@ -71,7 +68,6 @@ export const uploadAttachment = async ({
|
||||
)
|
||||
break
|
||||
default:
|
||||
attachmentType = 'unknown'
|
||||
composeDispatch({
|
||||
type: 'attachment/upload/start',
|
||||
payload: {
|
||||
@ -105,9 +101,9 @@ export const uploadAttachment = async ({
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('file', {
|
||||
uri: `file://${media.path}`,
|
||||
name: attachmentType,
|
||||
type: attachmentType
|
||||
uri: media.uri,
|
||||
name: media.uri.match(new RegExp(/.*\/(.*)/))?.[1] || 'file.jpg',
|
||||
type: media.mime
|
||||
} as any)
|
||||
|
||||
return apiInstance<Mastodon.Attachment>({
|
||||
|
@ -90,7 +90,7 @@ const ComposeTextInput: React.FC = () => {
|
||||
uploadAttachment({
|
||||
composeDispatch,
|
||||
media: {
|
||||
path: file.uri,
|
||||
uri: file.uri,
|
||||
mime: file.type,
|
||||
width: 100,
|
||||
height: 100
|
||||
|
@ -58,7 +58,7 @@ const composeReducer = (
|
||||
attachments: {
|
||||
...state.attachments,
|
||||
uploads: state.attachments.uploads.map(upload =>
|
||||
upload.local?.path === action.payload.local?.path
|
||||
upload.local?.uri === action.payload.local?.uri
|
||||
? { ...upload, remote: action.payload.remote, uploading: false }
|
||||
: upload
|
||||
)
|
||||
|
12
src/screens/Compose/utils/types.d.ts
vendored
12
src/screens/Compose/utils/types.d.ts
vendored
@ -2,11 +2,11 @@ import { ImageOrVideo } from 'react-native-image-crop-picker'
|
||||
|
||||
export type ExtendedAttachment = {
|
||||
remote?: Mastodon.Attachment
|
||||
local?: Pick<ImageOrVideo, 'path' | 'width' | 'height' | 'mime'> & {
|
||||
type: 'image' | 'video' | 'unknown'
|
||||
local_thumbnail?: string
|
||||
hash?: string
|
||||
}
|
||||
local?: { uri: string } & Pick<ImageOrVideo, 'width' | 'height' | 'mime'> & {
|
||||
type: 'image' | 'video' | 'unknown'
|
||||
local_thumbnail?: string
|
||||
hash?: string
|
||||
}
|
||||
uploading?: boolean
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ export type ComposeAction =
|
||||
type: 'attachment/upload/end'
|
||||
payload: {
|
||||
remote: Mastodon.Attachment
|
||||
local: Pick<ImageOrVideo, 'path' | 'width' | 'height' | 'mime'>
|
||||
local: { uri: string } & Pick<ImageOrVideo, 'width' | 'height' | 'mime'>
|
||||
}
|
||||
}
|
||||
| {
|
||||
|
@ -46,7 +46,7 @@ const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
|
||||
failed: true
|
||||
},
|
||||
type,
|
||||
data: image[0].path
|
||||
data: image[0].uri
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
@ -42,7 +42,7 @@ export type RootStackParamList = {
|
||||
| {
|
||||
type: 'share'
|
||||
text?: string
|
||||
media?: { path: string; mime: string }[]
|
||||
media?: { uri: string; mime: string }[]
|
||||
}
|
||||
| undefined
|
||||
'Screen-ImagesViewer': {
|
||||
|
@ -4428,6 +4428,13 @@ expo-image-loader@~3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/expo-image-loader/-/expo-image-loader-3.2.0.tgz#d98b021660edef7243f7c5ec011b8d0545626d41"
|
||||
integrity sha512-LU3Q2prn64/HxdToDmxgMIRXS1ZvD9Q3iCxRVTZn1fPQNNDciIQFE5okaa74Ogx20DFHs90r6WoUd7w9Af1OGQ==
|
||||
|
||||
expo-image-manipulator@^10.3.1:
|
||||
version "10.3.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-image-manipulator/-/expo-image-manipulator-10.3.1.tgz#e16dd76a550c7f5d653a2a666f26429eba311a6b"
|
||||
integrity sha512-D08dMD6MerxBu23DmCIhurySQih+eLP7VxKvY5mWqYz9payjDOS1cAGs3HvXPrEDusPQFQ0uIfqc+oqeMNFBIA==
|
||||
dependencies:
|
||||
expo-image-loader "~3.2.0"
|
||||
|
||||
expo-image-picker@13.1.1:
|
||||
version "13.1.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-image-picker/-/expo-image-picker-13.1.1.tgz#e039bf9748ccb7b89370ff2969c3ef07cc949192"
|
||||
|
Loading…
x
Reference in New Issue
Block a user