tooot/src/screens/Compose/EditAttachment/Image.tsx

179 lines
5.5 KiB
TypeScript
Raw Normal View History

2021-01-01 17:52:14 +01:00
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
2021-02-11 01:33:31 +01:00
import React, { useContext } from 'react'
2021-01-19 01:13:45 +01:00
import { useTranslation } from 'react-i18next'
2021-03-19 21:44:52 +01:00
import { Dimensions, Image, StyleSheet, Text, View } from 'react-native'
2020-12-30 00:56:25 +01:00
import { PanGestureHandler } from 'react-native-gesture-handler'
import Animated, {
Extrapolate,
interpolate,
runOnJS,
useAnimatedGestureHandler,
useAnimatedStyle,
useSharedValue
} from 'react-native-reanimated'
2020-12-30 00:56:25 +01:00
import Svg, { Circle, G, Path } from 'react-native-svg'
2021-01-01 17:52:14 +01:00
import ComposeContext from '../utils/createContext'
2020-12-30 00:56:25 +01:00
export interface Props {
index: number
}
2021-03-09 14:43:31 +01:00
const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
2021-01-19 01:13:45 +01:00
const { t } = useTranslation('sharedCompose')
2020-12-30 00:56:25 +01:00
const { theme } = useTheme()
2021-03-09 14:43:31 +01:00
const { composeState, composeDispatch } = useContext(ComposeContext)
const theAttachmentRemote = composeState.attachments.uploads[index].remote!
2021-01-22 01:34:20 +01:00
const theAttachmentLocal = composeState.attachments.uploads[index].local
2020-12-30 00:56:25 +01:00
2021-01-04 14:55:34 +01:00
const imageWidthBase =
2021-01-22 01:34:20 +01:00
theAttachmentRemote?.meta?.original?.aspect < 1
2021-01-04 14:55:34 +01:00
? Dimensions.get('screen').width *
2021-01-22 01:34:20 +01:00
theAttachmentRemote?.meta?.original?.aspect
2021-01-04 14:55:34 +01:00
: Dimensions.get('screen').width
const padding = (Dimensions.get('screen').width - imageWidthBase) / 2
2020-12-30 00:56:25 +01:00
const imageDimensionis = {
2021-01-04 14:55:34 +01:00
width: imageWidthBase,
2020-12-30 00:56:25 +01:00
height:
2021-01-04 14:55:34 +01:00
imageWidthBase /
2021-03-09 01:17:07 +01:00
((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.original
2021-01-22 01:34:20 +01:00
?.aspect || 1)
2020-12-30 00:56:25 +01:00
}
const panX = useSharedValue(
2021-03-09 01:17:07 +01:00
(((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.focus?.x || 0) *
imageDimensionis.width) /
2
)
const panY = useSharedValue(
2021-03-09 01:17:07 +01:00
(((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.focus?.y || 0) *
imageDimensionis.height) /
2
)
const updateFocus = ({ x, y }: { x: number; y: number }) => {
2021-03-09 14:43:31 +01:00
composeDispatch({
type: 'attachment/edit',
payload: {
...theAttachmentRemote,
meta: {
...theAttachmentRemote.meta,
focus: {
x: x > 1 ? 1 : x,
y: y > 1 ? 1 : y
}
}
}
})
}
2021-03-09 14:43:31 +01:00
type PanContext = {
startX: number
startY: number
}
const onGestureEvent = useAnimatedGestureHandler({
onStart: (_, context: PanContext) => {
context.startX = panX.value
context.startY = panY.value
},
onActive: ({ translationX, translationY }, context: PanContext) => {
panX.value = context.startX + translationX
panY.value = context.startY + translationY
},
onEnd: ({ translationX, translationY }, context: PanContext) => {
runOnJS(updateFocus)({
x: (context.startX + translationX) / (imageDimensionis.width / 2),
y: (context.startY + translationY) / (imageDimensionis.height / 2)
})
}
2020-12-30 00:56:25 +01:00
})
const styleTransform = useAnimatedStyle(() => {
return {
transform: [
{
translateX: interpolate(
panX.value,
2021-01-04 14:55:34 +01:00
[
-imageDimensionis.width / 2 + padding,
imageDimensionis.width / 2 + padding
],
[
-imageDimensionis.width / 2 + padding,
imageDimensionis.width / 2 + padding
],
Extrapolate.CLAMP
)
},
{
translateY: interpolate(
panY.value,
[-imageDimensionis.height / 2, imageDimensionis.height / 2],
[-imageDimensionis.height / 2, imageDimensionis.height / 2],
Extrapolate.CLAMP
)
}
]
2020-12-30 00:56:25 +01:00
}
})
return (
<>
2021-02-11 01:33:31 +01:00
<View style={styles.base}>
2021-03-19 21:44:52 +01:00
<Image
2020-12-30 00:56:25 +01:00
style={{
width: imageDimensionis.width,
height: imageDimensionis.height
}}
source={{
2021-01-22 01:34:20 +01:00
uri: theAttachmentLocal?.uri || theAttachmentRemote?.preview_url
2020-12-30 00:56:25 +01:00
}}
/>
<PanGestureHandler onGestureEvent={onGestureEvent}>
2020-12-30 00:56:25 +01:00
<Animated.View
style={[
styleTransform,
2020-12-30 00:56:25 +01:00
{
position: 'absolute',
2021-01-14 00:43:35 +01:00
top: -500 + imageDimensionis.height / 2,
left: -500 + imageDimensionis.width / 2
2020-12-30 00:56:25 +01:00
}
]}
>
2021-01-14 00:43:35 +01:00
<Svg width='1000' height='1000' viewBox='0 0 1000 1000'>
<G stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'>
<G>
2020-12-30 00:56:25 +01:00
<Path
2021-01-14 00:43:35 +01:00
d='M1000,0 L1000,1000 L0,1000 L0,0 L1000,0 Z M500,475 C486.192881,475 475,486.192881 475,500 C475,513.807119 486.192881,525 500,525 C513.807119,525 525,513.807119 525,500 C525,486.192881 513.807119,475 500,475 Z'
fill={theme.backgroundOverlayInvert}
2020-12-30 00:56:25 +01:00
/>
2021-01-14 00:43:35 +01:00
<Circle
stroke={theme.primaryOverlay}
stroke-width='2'
cx='500'
cy='500'
r='24'
/>
<Circle fill={theme.primaryOverlay} cx='500' cy='500' r='2' />
2020-12-30 00:56:25 +01:00
</G>
</G>
</Svg>
</Animated.View>
</PanGestureHandler>
</View>
<Text style={[styles.imageFocusText, { color: theme.primaryDefault }]}>
2021-01-19 01:13:45 +01:00
{t('content.editAttachment.content.imageFocus')}
2020-12-30 00:56:25 +01:00
</Text>
</>
)
}
const styles = StyleSheet.create({
2021-02-11 01:33:31 +01:00
base: { overflow: 'hidden', flex: 1, alignItems: 'center' },
2020-12-30 00:56:25 +01:00
imageFocusText: {
...StyleConstants.FontStyle.M,
padding: StyleConstants.Spacing.Global.PagePadding
}
})
export default ComposeEditAttachmentImage