Fixes to web avatar and banner cropper

This commit is contained in:
Paul Frazee
2024-05-08 22:26:24 -07:00
parent d57b344cd5
commit 8a12b606ee
7 changed files with 46 additions and 35 deletions
+2
View File
@@ -21,6 +21,8 @@ export async function openCropper(opts: CropperOptions): Promise<RNImage> {
opts.width && opts.height
? {width: opts.width, height: opts.height}
: undefined,
aspect: opts.webAspectRatio,
circular: opts.webCircularCrop,
onSelect: (img?: RNImage) => {
if (img) {
resolve(img)
+4 -1
View File
@@ -18,4 +18,7 @@ export interface CameraOpts {
cropperCircleOverlay?: boolean
}
export type CropperOptions = Parameters<typeof openCropper>[0]
export type CropperOptions = Parameters<typeof openCropper>[0] & {
webAspectRatio?: number
webCircularCrop?: boolean
}
+2
View File
@@ -40,6 +40,8 @@ export interface CropImageModal {
name: 'crop-image'
uri: string
dimensions?: {width: number; height: number}
aspect?: number
circular?: boolean
onSelect: (img?: RNImage) => void
}
@@ -29,7 +29,6 @@ const EditImageInner = ({control, image, onChange}: EditImageDialogProps) => {
const {initialCrop} = React.useMemo(() => {
const initialArea = manips?.crop
let crop: PercentCrop | undefined
if (initialArea) {
+35 -33
View File
@@ -7,6 +7,7 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import ReactCrop, {PercentCrop} from 'react-image-crop'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {useModalControls} from '#/state/modals'
import {usePalette} from 'lib/hooks/usePalette'
import {getDataUriSize} from 'lib/media/util'
@@ -17,60 +18,60 @@ export const snapPoints = ['0%']
export function Component({
uri,
dimensions,
aspect,
circular,
onSelect,
}: {
uri: string
dimensions?: {width: number; height: number}
aspect?: number
circular?: boolean
onSelect: (img?: RNImage) => void
}) {
const pal = usePalette('default')
const {_} = useLingui()
const {closeModal} = useModalControls()
const {isMobile} = useWebMediaQueries()
const imageRef = React.useRef<HTMLImageElement>(null)
const [crop, setCrop] = React.useState<PercentCrop>()
const isEmpty = !crop || (crop.width || crop.height) === 0
const aspect = dimensions ? dimensions.width / dimensions.height : undefined
const onPressCancel = () => {
onSelect(undefined)
closeModal()
}
const onPressDone = async () => {
if (!isEmpty) {
const img = imageRef.current!
const img = imageRef.current!
const result = await manipulateAsync(
uri,
[
{
crop: {
originX: (crop.x * img.width) / 100,
originY: (crop.y * img.height) / 100,
width: (crop.width * img.width) / 100,
height: (crop.height * img.height) / 100,
const result = await manipulateAsync(
uri,
isEmpty
? []
: [
{
crop: {
originX: (crop.x * img.naturalWidth) / 100,
originY: (crop.y * img.naturalHeight) / 100,
width: (crop.width * img.naturalWidth) / 100,
height: (crop.height * img.naturalHeight) / 100,
},
},
},
],
{
base64: true,
format: SaveFormat.JPEG,
},
)
],
{
base64: true,
format: SaveFormat.JPEG,
},
)
onSelect({
path: result.uri,
mime: 'image/jpeg',
size: result.base64 !== undefined ? getDataUriSize(result.base64) : 0,
width: result.width,
height: result.height,
})
} else {
onSelect(undefined)
}
onSelect({
path: result.uri,
mime: 'image/jpeg',
size: result.base64 !== undefined ? getDataUriSize(result.base64) : 0,
width: result.width,
height: result.height,
})
closeModal()
}
@@ -81,11 +82,12 @@ export function Component({
<ReactCrop
aspect={aspect}
crop={crop}
onChange={(_, next) => setCrop(next)}>
onChange={(_, next) => setCrop(next)}
circularCrop={circular}>
<img ref={imageRef} src={uri} style={{maxHeight: '75vh'}} />
</ReactCrop>
</View>
<View style={styles.btns}>
<View style={[styles.btns, isMobile && {paddingHorizontal: 16}]}>
<TouchableOpacity
onPress={onPressCancel}
accessibilityRole="button"
+2
View File
@@ -291,6 +291,8 @@ let EditableUserAvatar = ({
height: item.height,
width: item.width,
path: item.path,
webAspectRatio: 1,
webCircularCrop: true,
})
onSelectNewAvatar(croppedImage)
+1
View File
@@ -72,6 +72,7 @@ export function UserBanner({
path: items[0].path,
width: 3000,
height: 1000,
webAspectRatio: 3,
}),
)
} catch (e: any) {