refactor: restore old image cropper

This commit is contained in:
Mary
2024-05-08 11:20:32 +07:00
parent f6515fe199
commit c67043738d
4 changed files with 145 additions and 4 deletions
-4
View File
@@ -17,10 +17,6 @@ export async function openCropper(opts: CropperOptions): Promise<RNImage> {
unstable__openModal({ unstable__openModal({
name: 'crop-image', name: 'crop-image',
uri: opts.path, uri: opts.path,
dimensions:
opts.height && opts.width
? {width: opts.width, height: opts.height}
: undefined,
onSelect: (img?: RNImage) => { onSelect: (img?: RNImage) => {
if (img) { if (img) {
resolve(img) resolve(img)
+8
View File
@@ -1,4 +1,5 @@
import React from 'react' import React from 'react'
import {Image as RNImage} from 'react-native-image-crop-picker'
import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api' import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
@@ -35,6 +36,12 @@ export interface ListAddRemoveUsersModal {
) => void ) => void
} }
export interface CropImageModal {
name: 'crop-image'
uri: string
onSelect: (img?: RNImage) => void
}
export interface DeleteAccountModal { export interface DeleteAccountModal {
name: 'delete-account' name: 'delete-account'
} }
@@ -130,6 +137,7 @@ export type Modal =
| ListAddRemoveUsersModal | ListAddRemoveUsersModal
// Posts // Posts
| CropImageModal
| RepostModal | RepostModal
| SelfLabelModal | SelfLabelModal
| ThreadgateModal | ThreadgateModal
+134
View File
@@ -0,0 +1,134 @@
import React from 'react'
import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {Image as RNImage} from 'react-native-image-crop-picker'
import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
import {LinearGradient} from 'expo-linear-gradient'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import ReactCrop, {PixelCrop} from 'react-image-crop'
import {useModalControls} from '#/state/modals'
import {usePalette} from 'lib/hooks/usePalette'
import {getDataUriSize} from 'lib/media/util'
import {gradients, s} from 'lib/styles'
import {Text} from 'view/com/util/text/Text'
export const snapPoints = ['0%']
export function Component({
uri,
onSelect,
}: {
uri: string
onSelect: (img?: RNImage) => void
}) {
const pal = usePalette('default')
const {_} = useLingui()
const {closeModal} = useModalControls()
const [crop, setCrop] = React.useState<PixelCrop>()
const isEmpty = !crop || (crop.width || crop.height) === 0
const onPressCancel = () => {
onSelect(undefined)
closeModal()
}
const onPressDone = async () => {
if (!isEmpty) {
const result = await manipulateAsync(
uri,
[
{
crop: {
originX: crop.x,
originY: crop.y,
width: crop.width,
height: crop.height,
},
},
],
{
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)
}
closeModal()
}
return (
<View>
<View style={[styles.cropper, pal.borderDark]}>
<ReactCrop crop={crop} onChange={setCrop}>
<img src={uri} style={{maxHeight: '75vh'}} />
</ReactCrop>
</View>
<View style={styles.btns}>
<TouchableOpacity
onPress={onPressCancel}
accessibilityRole="button"
accessibilityLabel={_(msg`Cancel image crop`)}
accessibilityHint={_(msg`Exits image cropping process`)}>
<Text type="xl" style={pal.link}>
<Trans>Cancel</Trans>
</Text>
</TouchableOpacity>
<View style={s.flex1} />
<TouchableOpacity
onPress={onPressDone}
accessibilityRole="button"
accessibilityLabel={_(msg`Save image crop`)}
accessibilityHint={_(msg`Saves image crop settings`)}>
<LinearGradient
colors={[gradients.blueLight.start, gradients.blueLight.end]}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
style={[styles.btn]}>
<Text type="xl-medium" style={s.white}>
<Trans>Done</Trans>
</Text>
</LinearGradient>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
cropper: {
marginLeft: 'auto',
marginRight: 'auto',
borderWidth: 1,
borderRadius: 4,
overflow: 'hidden',
alignItems: 'center',
},
ctrls: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 10,
},
btns: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 10,
},
btn: {
borderRadius: 4,
paddingVertical: 8,
paddingHorizontal: 24,
},
})
+3
View File
@@ -12,6 +12,7 @@ import * as ChangeEmailModal from './ChangeEmail'
import * as ChangeHandleModal from './ChangeHandle' import * as ChangeHandleModal from './ChangeHandle'
import * as ChangePasswordModal from './ChangePassword' import * as ChangePasswordModal from './ChangePassword'
import * as CreateOrEditListModal from './CreateOrEditList' import * as CreateOrEditListModal from './CreateOrEditList'
import * as CropImage from './CropImage.web'
import * as DeleteAccountModal from './DeleteAccount' import * as DeleteAccountModal from './DeleteAccount'
import * as EditProfileModal from './EditProfile' import * as EditProfileModal from './EditProfile'
import * as InviteCodesModal from './InviteCodes' import * as InviteCodesModal from './InviteCodes'
@@ -69,6 +70,8 @@ function Modal({modal}: {modal: ModalIface}) {
element = <UserAddRemoveLists.Component {...modal} /> element = <UserAddRemoveLists.Component {...modal} />
} else if (modal.name === 'list-add-remove-users') { } else if (modal.name === 'list-add-remove-users') {
element = <ListAddUserModal.Component {...modal} /> element = <ListAddUserModal.Component {...modal} />
} else if (modal.name === 'crop-image') {
element = <CropImage.Component {...modal} />
} else if (modal.name === 'delete-account') { } else if (modal.name === 'delete-account') {
element = <DeleteAccountModal.Component /> element = <DeleteAccountModal.Component />
} else if (modal.name === 'repost') { } else if (modal.name === 'repost') {