Replace image picker with expo-image-picker (#649)
* Replace image picker with expo-image-picker * Fix cropper & picker on web --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>zio/stable
parent
d5bec4ff37
commit
5f66adc9a6
|
@ -75,7 +75,7 @@
|
||||||
"expo-device": "~5.2.1",
|
"expo-device": "~5.2.1",
|
||||||
"expo-image": "^1.2.1",
|
"expo-image": "^1.2.1",
|
||||||
"expo-image-manipulator": "^11.1.1",
|
"expo-image-manipulator": "^11.1.1",
|
||||||
"expo-image-picker": "~14.1.1",
|
"expo-image-picker": "^14.1.1",
|
||||||
"expo-localization": "~14.1.1",
|
"expo-localization": "~14.1.1",
|
||||||
"expo-media-library": "~15.2.3",
|
"expo-media-library": "~15.2.3",
|
||||||
"expo-sharing": "~11.2.2",
|
"expo-sharing": "~11.2.2",
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
import {
|
import {
|
||||||
openPicker as openPickerFn,
|
|
||||||
openCamera as openCameraFn,
|
openCamera as openCameraFn,
|
||||||
openCropper as openCropperFn,
|
openCropper as openCropperFn,
|
||||||
ImageOrVideo,
|
Image as RNImage,
|
||||||
} from 'react-native-image-crop-picker'
|
} from 'react-native-image-crop-picker'
|
||||||
import {RootStoreModel} from 'state/index'
|
import {RootStoreModel} from 'state/index'
|
||||||
import {PickerOpts, CameraOpts, CropperOptions} from './types'
|
import {CameraOpts, CropperOptions} from './types'
|
||||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
import {
|
||||||
|
ImagePickerOptions,
|
||||||
|
launchImageLibraryAsync,
|
||||||
|
MediaTypeOptions,
|
||||||
|
} from 'expo-image-picker'
|
||||||
|
import {getDataUriSize} from './util'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE
|
* NOTE
|
||||||
|
@ -19,27 +23,22 @@ import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||||
|
|
||||||
export async function openPicker(
|
export async function openPicker(
|
||||||
_store: RootStoreModel,
|
_store: RootStoreModel,
|
||||||
opts?: PickerOpts,
|
opts?: ImagePickerOptions,
|
||||||
): Promise<RNImage[]> {
|
) {
|
||||||
const items = await openPickerFn({
|
const response = await launchImageLibraryAsync({
|
||||||
mediaType: 'photo', // TODO: eventually add other media types
|
exif: false,
|
||||||
multiple: opts?.multiple,
|
mediaTypes: MediaTypeOptions.Images,
|
||||||
maxFiles: opts?.maxFiles,
|
quality: 1,
|
||||||
forceJpg: true, // ios only
|
...opts,
|
||||||
compressImageQuality: 0.8,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const toMedia = (item: ImageOrVideo) => ({
|
return (response.assets ?? []).map(image => ({
|
||||||
path: item.path,
|
mime: 'image/jpeg',
|
||||||
mime: item.mime,
|
height: image.height,
|
||||||
size: item.size,
|
width: image.width,
|
||||||
width: item.width,
|
path: image.uri,
|
||||||
height: item.height,
|
size: getDataUriSize(image.uri),
|
||||||
})
|
}))
|
||||||
if (Array.isArray(items)) {
|
|
||||||
return items.map(toMedia)
|
|
||||||
}
|
|
||||||
return [toMedia(items)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function openCamera(
|
export async function openCamera(
|
||||||
|
@ -55,6 +54,7 @@ export async function openCamera(
|
||||||
forceJpg: true, // ios only
|
forceJpg: true, // ios only
|
||||||
compressImageQuality: 0.8,
|
compressImageQuality: 0.8,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
path: item.path,
|
path: item.path,
|
||||||
mime: item.mime,
|
mime: item.mime,
|
||||||
|
@ -67,11 +67,10 @@ export async function openCamera(
|
||||||
export async function openCropper(
|
export async function openCropper(
|
||||||
_store: RootStoreModel,
|
_store: RootStoreModel,
|
||||||
opts: CropperOptions,
|
opts: CropperOptions,
|
||||||
): Promise<RNImage> {
|
) {
|
||||||
const item = await openCropperFn({
|
const item = await openCropperFn({
|
||||||
...opts,
|
...opts,
|
||||||
forceJpg: true, // ios only
|
forceJpg: true, // ios only
|
||||||
compressImageQuality: 0.8,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -102,10 +102,14 @@ export class GalleryModel {
|
||||||
|
|
||||||
async pick() {
|
async pick() {
|
||||||
const images = await openPicker(this.rootStore, {
|
const images = await openPicker(this.rootStore, {
|
||||||
multiple: true,
|
selectionLimit: 4 - this.size,
|
||||||
maxFiles: 4 - this.images.length,
|
allowsMultipleSelection: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
await Promise.all(images.map(image => this.add(image)))
|
return await Promise.all(
|
||||||
|
images.map(image => {
|
||||||
|
this.add(image)
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ export class ImageModel implements RNImage {
|
||||||
// Only for mobile
|
// Only for mobile
|
||||||
async crop() {
|
async crop() {
|
||||||
try {
|
try {
|
||||||
const cropped = await openCropper(this.rootStore, {
|
const cropped = await openCropper({
|
||||||
mediaType: 'photo',
|
mediaType: 'photo',
|
||||||
path: this.path,
|
path: this.path,
|
||||||
freeStyleCropEnabled: true,
|
freeStyleCropEnabled: true,
|
||||||
|
|
|
@ -65,7 +65,7 @@ export function Component({
|
||||||
}
|
}
|
||||||
const onSelectNewAvatar = useCallback(
|
const onSelectNewAvatar = useCallback(
|
||||||
async (img: RNImage | null) => {
|
async (img: RNImage | null) => {
|
||||||
if (!img) {
|
if (img === null) {
|
||||||
setNewUserAvatar(null)
|
setNewUserAvatar(null)
|
||||||
setUserAvatar(null)
|
setUserAvatar(null)
|
||||||
return
|
return
|
||||||
|
@ -81,6 +81,7 @@ export function Component({
|
||||||
},
|
},
|
||||||
[track, setNewUserAvatar, setUserAvatar, setError],
|
[track, setNewUserAvatar, setUserAvatar, setError],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onSelectNewBanner = useCallback(
|
const onSelectNewBanner = useCallback(
|
||||||
async (img: RNImage | null) => {
|
async (img: RNImage | null) => {
|
||||||
if (!img) {
|
if (!img) {
|
||||||
|
@ -99,6 +100,7 @@ export function Component({
|
||||||
},
|
},
|
||||||
[track, setNewUserBanner, setUserBanner, setError],
|
[track, setNewUserBanner, setUserBanner, setError],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPressSave = useCallback(async () => {
|
const onPressSave = useCallback(async () => {
|
||||||
track('EditProfile:Save')
|
track('EditProfile:Save')
|
||||||
setProcessing(true)
|
setProcessing(true)
|
||||||
|
|
|
@ -66,6 +66,7 @@ export function UserAvatar({
|
||||||
if (!(await requestCameraAccessIfNeeded())) {
|
if (!(await requestCameraAccessIfNeeded())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectNewAvatar?.(
|
onSelectNewAvatar?.(
|
||||||
await openCamera(store, {
|
await openCamera(store, {
|
||||||
width: 1000,
|
width: 1000,
|
||||||
|
@ -83,20 +84,21 @@ export function UserAvatar({
|
||||||
if (!(await requestPhotoAccessIfNeeded())) {
|
if (!(await requestPhotoAccessIfNeeded())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = await openPicker(store, {
|
const items = await openPicker(store, {
|
||||||
|
aspect: [1, 1],
|
||||||
|
})
|
||||||
|
const item = items[0]
|
||||||
|
|
||||||
|
const croppedImage = await openCropper(store, {
|
||||||
mediaType: 'photo',
|
mediaType: 'photo',
|
||||||
multiple: false,
|
cropperCircleOverlay: true,
|
||||||
|
height: item.height,
|
||||||
|
width: item.width,
|
||||||
|
path: item.path,
|
||||||
})
|
})
|
||||||
|
|
||||||
onSelectNewAvatar?.(
|
onSelectNewAvatar?.(croppedImage)
|
||||||
await openCropper(store, {
|
|
||||||
mediaType: 'photo',
|
|
||||||
path: items[0].path,
|
|
||||||
width: 1000,
|
|
||||||
height: 1000,
|
|
||||||
cropperCircleOverlay: true,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,10 +55,8 @@ export function UserBanner({
|
||||||
if (!(await requestPhotoAccessIfNeeded())) {
|
if (!(await requestPhotoAccessIfNeeded())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const items = await openPicker(store, {
|
const items = await openPicker(store)
|
||||||
mediaType: 'photo',
|
|
||||||
multiple: false,
|
|
||||||
})
|
|
||||||
onSelectNewBanner?.(
|
onSelectNewBanner?.(
|
||||||
await openCropper(store, {
|
await openCropper(store, {
|
||||||
mediaType: 'photo',
|
mediaType: 'photo',
|
||||||
|
|
|
@ -8731,7 +8731,7 @@ expo-image-manipulator@^11.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
expo-image-loader "~4.1.0"
|
expo-image-loader "~4.1.0"
|
||||||
|
|
||||||
expo-image-picker@~14.1.1:
|
expo-image-picker@^14.1.1:
|
||||||
version "14.1.1"
|
version "14.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/expo-image-picker/-/expo-image-picker-14.1.1.tgz#181f1348ba6a43df7b87cee4a601d45c79b7c2d7"
|
resolved "https://registry.yarnpkg.com/expo-image-picker/-/expo-image-picker-14.1.1.tgz#181f1348ba6a43df7b87cee4a601d45c79b7c2d7"
|
||||||
integrity sha512-SvWtnkLW7jp5Ntvk3lVcRQmhFYja8psmiR7O6P/+7S6f4llt3vaFwb4I3+pUXqJxxpi7BHc2+95qOLf0SFOIag==
|
integrity sha512-SvWtnkLW7jp5Ntvk3lVcRQmhFYja8psmiR7O6P/+7S6f4llt3vaFwb4I3+pUXqJxxpi7BHc2+95qOLf0SFOIag==
|
||||||
|
|
Loading…
Reference in New Issue