diff options
author | Mary <148872143+mary-ext@users.noreply.github.com> | 2024-09-24 23:27:40 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-25 01:27:40 +0900 |
commit | b9516202fa17325a3d54e54372ddd56149be129c (patch) | |
tree | e95ff75e6b6e8d6ef3ab6a3ccd34fe293a4a3568 /src/view/com/composer | |
parent | ed512d6dc5390555232bb4ac3f96f477751c33b1 (diff) | |
download | voidsky-b9516202fa17325a3d54e54372ddd56149be129c.tar.zst |
Revamp image editor (#5462)
* new image editor * Rm react-avatar-editor --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Diffstat (limited to 'src/view/com/composer')
-rw-r--r-- | src/view/com/composer/photos/EditImageDialog.tsx | 14 | ||||
-rw-r--r-- | src/view/com/composer/photos/EditImageDialog.web.tsx | 105 | ||||
-rw-r--r-- | src/view/com/composer/photos/Gallery.tsx | 34 |
3 files changed, 138 insertions, 15 deletions
diff --git a/src/view/com/composer/photos/EditImageDialog.tsx b/src/view/com/composer/photos/EditImageDialog.tsx new file mode 100644 index 000000000..4263587fd --- /dev/null +++ b/src/view/com/composer/photos/EditImageDialog.tsx @@ -0,0 +1,14 @@ +import React from 'react' + +import {ComposerImage} from '#/state/gallery' +import * as Dialog from '#/components/Dialog' + +export type EditImageDialogProps = { + control: Dialog.DialogOuterProps['control'] + image: ComposerImage + onChange: (next: ComposerImage) => void +} + +export const EditImageDialog = ({}: EditImageDialogProps): React.ReactNode => { + return null +} diff --git a/src/view/com/composer/photos/EditImageDialog.web.tsx b/src/view/com/composer/photos/EditImageDialog.web.tsx new file mode 100644 index 000000000..0afb83ed9 --- /dev/null +++ b/src/view/com/composer/photos/EditImageDialog.web.tsx @@ -0,0 +1,105 @@ +import 'react-image-crop/dist/ReactCrop.css' + +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import ReactCrop, {PercentCrop} from 'react-image-crop' + +import { + ImageSource, + ImageTransformation, + manipulateImage, +} from '#/state/gallery' +import {atoms as a} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import * as Dialog from '#/components/Dialog' +import {Text} from '#/components/Typography' +import {EditImageDialogProps} from './EditImageDialog' + +export const EditImageDialog = (props: EditImageDialogProps) => { + return ( + <Dialog.Outer control={props.control}> + <EditImageInner key={props.image.source.id} {...props} /> + </Dialog.Outer> + ) +} + +const EditImageInner = ({control, image, onChange}: EditImageDialogProps) => { + const {_} = useLingui() + + const source = image.source + + const initialCrop = getInitialCrop(source, image.manips) + const [crop, setCrop] = React.useState(initialCrop) + + const isEmpty = !crop || (crop.width || crop.height) === 0 + const isNew = initialCrop ? true : !isEmpty + + const onPressSubmit = React.useCallback(async () => { + const result = await manipulateImage(image, { + crop: + crop && (crop.width || crop.height) !== 0 + ? { + originX: (crop.x * source.width) / 100, + originY: (crop.y * source.height) / 100, + width: (crop.width * source.width) / 100, + height: (crop.height * source.height) / 100, + } + : undefined, + }) + + onChange(result) + control.close() + }, [crop, image, source, control, onChange]) + + return ( + <Dialog.Inner label={_(msg`Edit image`)}> + <Dialog.Close /> + + <Text style={[a.text_2xl, a.font_bold, a.leading_tight, a.pb_sm]}> + <Trans>Edit image</Trans> + </Text> + + <View style={[a.align_center]}> + <ReactCrop + crop={crop} + onChange={(_pixelCrop, percentCrop) => setCrop(percentCrop)} + className="ReactCrop--no-animate"> + <img src={source.path} style={{maxHeight: `50vh`}} /> + </ReactCrop> + </View> + + <View style={[a.mt_md, a.gap_md]}> + <Button + disabled={!isNew} + label={_(msg`Save`)} + size="large" + color="primary" + variant="solid" + onPress={onPressSubmit}> + <ButtonText> + <Trans>Save</Trans> + </ButtonText> + </Button> + </View> + </Dialog.Inner> + ) +} + +const getInitialCrop = ( + source: ImageSource, + manips: ImageTransformation | undefined, +): PercentCrop | undefined => { + const initialArea = manips?.crop + + if (initialArea) { + return { + unit: '%', + x: (initialArea.originX / source.width) * 100, + y: (initialArea.originY / source.height) * 100, + width: (initialArea.width / source.width) * 100, + height: (initialArea.height / source.height) * 100, + } + } +} diff --git a/src/view/com/composer/photos/Gallery.tsx b/src/view/com/composer/photos/Gallery.tsx index 83c1e3c80..369f08d74 100644 --- a/src/view/com/composer/photos/Gallery.tsx +++ b/src/view/com/composer/photos/Gallery.tsx @@ -21,6 +21,7 @@ import {ComposerImage, cropImage} from '#/state/gallery' import {Text} from '#/view/com/util/text/Text' import {useTheme} from '#/alf' import * as Dialog from '#/components/Dialog' +import {EditImageDialog} from './EditImageDialog' import {ImageAltTextDialog} from './ImageAltTextDialog' const IMAGE_GAP = 8 @@ -144,12 +145,15 @@ const GalleryItem = ({ const t = useTheme() const altTextControl = Dialog.useDialogControl() + const editControl = Dialog.useDialogControl() const onImageEdit = () => { if (isNative) { cropImage(image).then(next => { onChange(next) }) + } else { + editControl.open() } } @@ -185,21 +189,15 @@ const GalleryItem = ({ </Text> </TouchableOpacity> <View style={imageControlsStyle}> - {isNative && ( - <TouchableOpacity - testID="editPhotoButton" - accessibilityRole="button" - accessibilityLabel={_(msg`Edit image`)} - accessibilityHint="" - onPress={onImageEdit} - style={styles.imageControl}> - <FontAwesomeIcon - icon="pen" - size={12} - style={{color: colors.white}} - /> - </TouchableOpacity> - )} + <TouchableOpacity + testID="editPhotoButton" + accessibilityRole="button" + accessibilityLabel={_(msg`Edit image`)} + accessibilityHint="" + onPress={onImageEdit} + style={styles.imageControl}> + <FontAwesomeIcon icon="pen" size={12} style={{color: colors.white}} /> + </TouchableOpacity> <TouchableOpacity testID="removePhotoButton" accessibilityRole="button" @@ -237,6 +235,12 @@ const GalleryItem = ({ image={image} onChange={onChange} /> + + <EditImageDialog + control={editControl} + image={image} + onChange={onChange} + /> </View> ) } |