refactor: restore old image cropper
This commit is contained in:
@@ -17,10 +17,6 @@ export async function openCropper(opts: CropperOptions): Promise<RNImage> {
|
||||
unstable__openModal({
|
||||
name: 'crop-image',
|
||||
uri: opts.path,
|
||||
dimensions:
|
||||
opts.height && opts.width
|
||||
? {width: opts.width, height: opts.height}
|
||||
: undefined,
|
||||
onSelect: (img?: RNImage) => {
|
||||
if (img) {
|
||||
resolve(img)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react'
|
||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||
import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
|
||||
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
@@ -35,6 +36,12 @@ export interface ListAddRemoveUsersModal {
|
||||
) => void
|
||||
}
|
||||
|
||||
export interface CropImageModal {
|
||||
name: 'crop-image'
|
||||
uri: string
|
||||
onSelect: (img?: RNImage) => void
|
||||
}
|
||||
|
||||
export interface DeleteAccountModal {
|
||||
name: 'delete-account'
|
||||
}
|
||||
@@ -130,6 +137,7 @@ export type Modal =
|
||||
| ListAddRemoveUsersModal
|
||||
|
||||
// Posts
|
||||
| CropImageModal
|
||||
| RepostModal
|
||||
| SelfLabelModal
|
||||
| ThreadgateModal
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
@@ -12,6 +12,7 @@ import * as ChangeEmailModal from './ChangeEmail'
|
||||
import * as ChangeHandleModal from './ChangeHandle'
|
||||
import * as ChangePasswordModal from './ChangePassword'
|
||||
import * as CreateOrEditListModal from './CreateOrEditList'
|
||||
import * as CropImage from './CropImage.web'
|
||||
import * as DeleteAccountModal from './DeleteAccount'
|
||||
import * as EditProfileModal from './EditProfile'
|
||||
import * as InviteCodesModal from './InviteCodes'
|
||||
@@ -69,6 +70,8 @@ function Modal({modal}: {modal: ModalIface}) {
|
||||
element = <UserAddRemoveLists.Component {...modal} />
|
||||
} else if (modal.name === 'list-add-remove-users') {
|
||||
element = <ListAddUserModal.Component {...modal} />
|
||||
} else if (modal.name === 'crop-image') {
|
||||
element = <CropImage.Component {...modal} />
|
||||
} else if (modal.name === 'delete-account') {
|
||||
element = <DeleteAccountModal.Component />
|
||||
} else if (modal.name === 'repost') {
|
||||
|
||||
Reference in New Issue
Block a user